2016-08-23 162 views
1

我想在C语言中做一个移动平均过滤器,我已经改编了一个正确工作的matlab程序,我的过滤器的输入是一个.pcm压缩文件(扫描音频信号),对我来说问题是C语言中移动平均值的输出存档,输出出错,信号只随时间减少(不填充)。以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

信号的开头还是有干扰,但从中间到结束的信号是正确的。

+1

开始使用自我解释的名称(在这里最好用英文发布)。像文件级别的'm'这样的单字符宏是一个禁止行为(无论如何都是小写字母)。然后将代码墙分成几个函数以获得更好的概述。最后调试代码。我们不是一个调试服务。看[问]! – Olaf

+0

注意:'int main(){... return;'是个小问题。 – chux

回答

3

您的主信号处理循环有几个问题。

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); 
} 

更高效的版本可避免重复处理中间元素,而不是仅仅增加进入滑动窗口的新号码,并减去老号离开窗口中的每个迭代。如果处理浮点数,在处理病态数字等时,必须小心谨慎,数值稳定,但这是一个完全不同的问题,您现在不必关心自己。

+1

苏丹,使用你的答案,移动平均在信号的末尾得到正确的结果,但在信号的起始点仍然是干扰。我尝试调试代码,但我没有发现问题。我会更新一个屏幕,以便在原始帖子中看到。也许你知道发生了什么事。 – Mutante