Возникла задача реализовать на С++ алгоритм скользящего среднего, который находит широкое применение в обработке сигналов и статистике.

За основу была взята функция smooth в MATLAB.
Данную функцию можно использовать для фильтрации сигналов. В качестве входных параметров определяются массив данных и окно усреднения.
Кому интересно, прошу под кат
Итак, есть несколько реализаций данного алгоритма. Рассмотрим самый простой из них:
предположим, размер окна усреднения будет равен 5, тогда на каждом шаге усреднения берется текущее значение, к нему прибавляются 4 предыдущих и результат делится на 5. Очевидная проблема здесь в инициализации алгоритма, сначала нужно накопить определенное количество данных, не меньшее, чем окно усреднения.
В MATLAB алгоритм фильтрации с помощью скользящего среднего реализован в функции smooth
Пример использования smooth(input,window),
где input — массив входящих данных
window — окно усреднения.
Изменяя параметр window можно получить большую или меньшую степень сглаживания данных:

Исходник, реализующий данный пример представлен ниже:
Для компенсации задержки в обработке сигнала, MATLAB использует динамически изменяемый размер окна, суть метода иллюстрирует следующий пример:

Собственную реализацию данного алгоритма я сначала написал в MATLAB, а затем перенес на С++
MATLAB edition:
Результат работы данной программы абсолютно совпадает с матлабовским smooth при нечетных размерах окна и несколько отличается при четном его значении (четные окна матлаб считает чуть иначе)
Исходный m-файл можно взять тут
С++ Edition
спасибо за внимание, конструктивная критика приветствуется
p.s.:
Алгоритм можно оптимизировать по скорости работы изменив подсчет суммы:

Видно, что для подсчета суммы элементов на 4-м шаге нужно из суммы на третьем шаге вычесть 1-й элемент массива (2, отмечен красным) и прибавить 6-й элемент (8, желтая клетка).
На следующем шаге процедура повторяется.
Данный подход будет эффективным при большом размере окна усреднения

За основу была взята функция smooth в MATLAB.
Данную функцию можно использовать для фильтрации сигналов. В качестве входных параметров определяются массив данных и окно усреднения.
Кому интересно, прошу под кат
Итак, есть несколько реализаций данного алгоритма. Рассмотрим самый простой из них:
предположим, размер окна усреднения будет равен 5, тогда на каждом шаге усреднения берется текущее значение, к нему прибавляются 4 предыдущих и результат делится на 5. Очевидная проблема здесь в инициализации алгоритма, сначала нужно накопить определенное количество данных, не меньшее, чем окно усреднения.
В MATLAB алгоритм фильтрации с помощью скользящего среднего реализован в функции smooth
Пример использования smooth(input,window),
где input — массив входящих данных
window — окно усреднения.
Изменяя параметр window можно получить большую или меньшую степень сглаживания данных:

Исходник, реализующий данный пример представлен ниже:
clear all; %% Параметры t=1;% длительность сигнала Fd=512;% Частота дискретизации (Гц) A1=1;% Амплитуда синусоиды F1=10;% Частота синусоиды (Гц) SNR=0.3;% Соотношение сигнал/шум T=0:1/Fd:t;% Массив отсчетов Noise=A1*SNR*randn(1,length(T));%Сгенерированный шум Signal=A1*sind((F1*360).*T);%Сгенерированный сигнал SN=Signal+Noise; figure(1); subplot(4,1,1); plot(SN); subplot(4,1,2); plot(smooth(SN,3)); subplot(4,1,3); plot(smooth(SN,8)); subplot(4,1,4); plot(smooth(SN,20));
Для компенсации задержки в обработке сигнала, MATLAB использует динамически изменяемый размер окна, суть метода иллюстрирует следующий пример:

Собственную реализацию данного алгоритма я сначала написал в MATLAB, а затем перенес на С++
MATLAB edition:
%my_smooth %в случае, если размер окна четный, увеличиваем его на 1 для симметрии; window = 5; if(mod(window,2)==0) window=window+1; end hw=(window-1)/2; %размах окна влево и вправо от текущей позиции n=length(Signal); result=zeros(n,1); result(1)=SN(1); %первый элемент берем из исходного массива SN как есть for i=2:n %организовываем цикл по числу элементов init_sum = 0; if(i<=hw) %если индекс меньше половины окна, мы находимся в начале массива, %нужно брать окно меньшего размера k1=1; %в качестве начала окна берем первый элемент k2=2*i-1; %конец окна z=k2; %текущий размер окна elseif (i+hw>n) %если индекс+половина окна больше n - мы приближаемся к концу массива и размер окна %также нужно уменьшать k1=i-n+i; %начало окна k2=n; %конец окна - последний элемент массива z=k2-k1; %размер окна else %если первые два условия не выполняются, мы в середине массива k1=i-hw; k2=i+hw; z=window; end for j=k1:k2 %организуем цикл от начала до конца окна init_sum=init_sum+SN(j); %складываем все элементы end result(i)=init_sum/(z); %и делим на текущий размер окна end
Результат работы данной программы абсолютно совпадает с матлабовским smooth при нечетных размерах окна и несколько отличается при четном его значении (четные окна матлаб считает чуть иначе)
Исходный m-файл можно взять тут
С++ Edition
void smooth(double *input, double *output, int n, int window) { int i,j,z,k1,k2,hw; double tmp; if(fmod(window,2)==0) window++; hw=(window-1)/2; output[0]=input[0]; for (i=1;i<n;i++){ tmp=0; if(i<hw){ k1=0; k2=2*i; z=k2+1; } else if((i+hw)>(n-1)){ k1=i-n+i+1; k2=n-1; z=k2-k1+1; } else{ k1=i-hw; k2=i+hw; z=window; } for (j=k1;j<=k2;j++){ tmp=tmp+input[j]; } output[i]=tmp/z; }
спасибо за внимание, конструктивная критика приветствуется
p.s.:
Алгоритм можно оптимизировать по скорости работы изменив подсчет суммы:

Видно, что для подсчета суммы элементов на 4-м шаге нужно из суммы на третьем шаге вычесть 1-й элемент массива (2, отмечен красным) и прибавить 6-й элемент (8, желтая клетка).
На следующем шаге процедура повторяется.
Данный подход будет эффективным при большом размере окна усреднения
