2016-08-23 356 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