matlab - C语言的移动平均线

标签 matlab c moving-average

我正在尝试用 C 语言做一个移动平均滤波器,我已经改编了一个可以正常工作的 matlab 程序,我的滤波器的输入是 .pcm 存档(扫描音频信号),对我来说问题是C语言的移动平均线输出存档,输出出错,信号仅随时间减小(不滤波)。

下面是我的 C 代码:

#include <stdio.h>
#include <stdlib.h>



#define m 16  // MEDIA LENGTH

int main()
{
    short *x;                              // X VECTOR = 0
    double coef[m];                           // COEF VECTOR = 0
    int i;                                  // FOR COUNT VARIABLE
    int n;                                  // FOR COUNT VARIABLE
    int itera;                              // LENGTH OF THE INPUT FILE
    double aux;                                // AUX VARIABLE TO MAKE THE SUM
    double *y;                              // AUX VECTOR TO RECEIVE X VECTOR
    double *saida;                          // OUTPUT VECTOR
    FILE *arq;                                 // POINTER TO THE FILE

    for (i = 0; i < m; i++) {
        coef[i] = 1.0/m;
    }
    arq = fopen("sweep_100_3400.pcm", "rb");
    if (arq == NULL)
    {
        printf("ERROR WHILE OPENING THE FILE\n");
        return;
    }
    // compute size of file
    fseek(arq,0,SEEK_END);
    itera = ftell(arq)/sizeof(short);
    rewind(arq);

    // alloc mem for x, read the vector from input file
    x = malloc(itera*sizeof(short));
    fread(x,sizeof(short),itera,arq);
    fclose(arq);
    // alloc mem for y

    y = malloc(itera*sizeof(double));
    saida = malloc(itera*sizeof(double));

    for (i=0; i < itera; i++) {
        y[0] = x[i];
        aux=0;
        for (n=0; n<m; n++){
            aux += coef[n] * y[n];
        }
        saida[i]=aux;
        for (n=m; n <2; n--){
            x[n] = x[n-1];
        }
    }
    arq=fopen("saida_medial_movel_c.pcm","wb");
    fwrite(saida, sizeof(double),itera,arq);
    fclose(arq);
    free(saida);
    free(y);
    free(x);
}

下图是matlab程序对长度为16的移动平均的输出:

enter image description here

该图像是C语言的输出,长度为16的移动平均:

enter image description here

有人知道可能是什么吗?

下面是我改编的 matlab 代码:

%MOVING AVERAGE EXAMPLE SCRIPT
clear all;
close all;
clc;
% DEFINES MEDIA LENGTH
m = 16;
%VECTOS EQUAL ZERO
x = zeros (m,1); 
coef = zeros (m,1);
%INITIALIZE VECTOR 
for j = 1 : m,
        coef (j,1) = 1/m;
end
%READ INPUT FILE
fid = fopen ('sweep_100_3400.pcm','rb');
s = fread (fid, 'int16');
fclose(fid);
subplot(2,1,1);
plot(s);
grid on;
title('ENTRADA DO FILTRO');
%PROCESS
itera = length(s);
sav_y = zeros (itera, 1);
%EXECUTE PROCESS
for j = 1 : itera,
    x(1,1) = s (j,1);
    %PRODUCTS SUM
    y=0;
    for n = 1 : m,
        y = y + coef(n,1) * x(n,1);
    end
    sav_y(j,1) = y;
    %SHIFT THE VECTOR
    for n = m: -1 : 2,
        x (n,1) = x(n-1,1);
    end 
end 
%PLOT OUTPUT
subplot (2,1,2);
plot (sav_y);
grid on;
title('SAÍDA DO FLITRO');
%SAVE THE OUTPUT IN ANOTHER FILE
fid = fopen('saida_mm_manual.pcm','wb');
fwrite(fid,sav_y,'int16');
fclose(fid);

更新 1(使用上面的答案):

enter image description here

信号的开头仍然有干扰,但从中间到结尾信号是正确的。

最佳答案

您的主信号处理循环存在一些问题。

for (i=0; i < itera; i++) {
    y[0] = x[i];
    aux=0;
    for (n=0; n<m; n++){
        aux += coef[n] * y[n];
    }
    saida[i]=aux;
    for (n=m; n <2; n--){
        x[n] = x[n-1];
    }
}

coef 数组的每个元素都是相同的,因此您不妨将其设为 1.0/m 的单个常量值。对于 y 数组,除了第一个元素之外,您没有设置任何元素。因此,您的循环将一个常量乘以未初始化值 16 倍添加到 aux 中。这就是产生垃圾输出的原因。我不确定你的 (n=m; n <2; n--) 循环应该做什么,但自从 m > 2 以来它永远不会运行。

(低效的)简单移动平均线看起来更像是这样的:

for (i = 0; i < itera - m; i++) {
    aux = 0;
    for (n = 0; n < m; n++){
        aux += x[i+n];
    }
    saida[i] = aux * (1.0 / m);
}

更高效的版本可以避免重复处理中间元素,而只需在每次迭代中添加进入滑动窗口的新数字并减去离开窗口的旧数字。如果处理 float ,在处理病态数字等时必须注意数值稳定性,但这是一个完全不同的问题,您现在不必担心。

关于matlab - C语言的移动平均线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39109043/

相关文章:

algorithm - 均值偏移图像分割

c - 在 C 中使用 SDL 在屏幕上绘制像素

c - fread 不插入值

algorithm - 时间段不一致的平滑值

c++ - 我尝试用 C++ 编写自己的简单移动平均线

matlab - 在 Matlab 中绘制方形曲面

matlab - 编辑器选项卡在 GUI 中消失

matlab - 使用包含单元格长度的向量将嵌套结构转换为单元格数组

c - 如何在不继续循环的情况下显示输出?

database - PostgreSQL 时态数据库中的移动平均值