[數字信號處理]單位衝擊響應與頻響以及FIR實現代碼(C語言)

1.單位衝擊響應與頻響

        就如同之前所說的一樣,使用下圖所示的單位衝擊響應,所設計的濾波器,是無法實現的。


         現在,讓我們看看其這個濾波器的頻響。所謂頻響,就是計算其單位衝擊響應的離散時間傅里葉變換,


       我們可以看出,這個濾波器的頻響的計算結果是實數,並沒有虛數部分。也就是,其相位譜一直是0,也就意味着,這個濾波器輸入與輸出之間沒有延遲,這種相位特性稱爲0延遲相位特性。

        但是,這個濾波器無法是無法實現的。我們實際計算一下該濾波器的輸入輸出,就可以明白。


        這個濾波器在計算的過程中,需要過去的值和未來的值。未來的值是不可預測的,所以,這個濾波器無法實現。爲了使得這個濾波器可以實現,我們只好移動其單位衝擊響應,使得其不再需要未來的值。比如,就像下面這樣移動。


        這樣的話,這個濾波器就可以實現了,我們只需要記錄其40個過去的輸入值和現在的輸入值。但是,由於移動了其單位衝擊響應,會不會對頻響產生什麼影響呢,我們來看看。


       爲了更好的說明問題,L去代替之前例子中的20。

       移動之後頻響,我們根據上面式子可以得出兩個結論:1,移動不會對幅度譜產生影響。2,,移動會對相位產生一個延遲,這個延遲主要取決於移動的長度,移動的長度越長,延遲越大。但是,這個移動是線性的。

       因此,我們把這個移動的相位特性稱爲,線性相位特性。到這裏,我們移動後的,因果的,可實現的濾波器的單位衝擊響應,如下所示。


2.窗函數實現的FIR濾波器代碼(C語言)

#include <stdio.h>
#include <math.h>
#include <malloc.h>
#include <string.h>


#define   pi         (3.1415926)

/*-------------Win Type----------------*/
#define   Hamming    (1)



double Input_Data[] = 
{
0.000000 , 0.896802 , 1.538842 , 1.760074 ,  1.538842 ,  1.000000 ,  0.363271 , -0.142040 , -0.363271 , -0.278768,
0.000000 , 0.278768 , 0.363271 , 0.142020 , -0.363271 , -1.000000 , -1.538842 , -1.760074 , -1.538842 , -0.896802,
0.000000 , 0.896802 , 1.538842 , 1.760074 ,  1.538842 ,  1.000000 ,  0.363271 , -0.142040 , -0.363271 , -0.278768,
0.000000 , 0.278768 , 0.363271 , 0.142020 , -0.363271 , -1.000000 , -1.538842 , -1.760074 , -1.538842 , -0.896802,
0.000000 , 0.896802 , 1.538842 , 1.760074 ,  1.538842 ,  1.000000 ,  0.363271 , -0.142040 , -0.363271 , -0.278768,
0.000000 , 0.278768 , 0.363271 , 0.142020 , -0.363271 , -1.000000 , -1.538842 , -1.760074 , -1.538842 , -0.896802,
0.000000 , 0.896802 , 1.538842 , 1.760074 ,  1.538842 ,  1.000000 ,  0.363271 , -0.142040 , -0.363271 , -0.278768,
0.000000 , 0.278768 , 0.363271 , 0.142020 , -0.363271 , -1.000000 , -1.538842 , -1.760074 , -1.538842 , -0.896802,
0.000000 , 55
};




double sinc(double n)
{
    if(0==n) return (double)1;
    else return (double)(sin(pi*n)/(pi*n));
}
 
int Unit_Impulse_Response(int N,double w_c,
                          int Win_Type,
                          double *Output_Data)
{
    signed int Count = 0; 
  
    for(Count = -(N-1)/2;Count <= (N-1)/2;Count++)
    {
    	*(Output_Data+Count+((N-1)/2)) = (w_c/pi)*sinc((w_c/pi)*(double)(Count));
    	//printf("%d %lf  ",Count+((N-1)/2)+1,*(Output_Data+Count+((N-1)/2)));
        //if(Count%4 == 0) printf("\n");
    }	
	
	
    switch (Win_Type)
    {
    	
    	case Hamming:   printf("Hamming \n");
    	                for(Count = -(N-1)/2;Count <= (N-1)/2;Count++)
    			{
    			    *(Output_Data+Count+((N-1)/2)) *= (0.54 + 0.46 * cos((2*pi*Count)/(N-1)));
    			    //printf("%d %lf  ",Count+((N-1)/2)+1,*(Output_Data+Count+((N-1)/2)));
        		    //if(((Count+1)%5 == 0)&&(Count != -20)) printf("\n");
   			} 
    	                break;
    	                
    	                
    	default:        printf("default Hamming \n");
    	                for(Count = -(N-1)/2;Count <= (N-1)/2;Count++)
    			{
    			    *(Output_Data+Count+((N-1)/2)) *= (0.54 + 0.46 * cos((2*pi*Count)/(N-1)));
    			    //printf("%d %lf  ",Count+((N-1)/2)+1,*(Output_Data+Count+((N-1)/2)));
        		    //if(((Count+1)%5 == 0)&&(Count != -20)) printf("\n");
   			} 
    	
                        break;
    }
    
    return (int)1;
}


void Save_Input_Date (double Scand,
                      int    Depth,
                      double *Input_Data)
{
    int Count;
  
    for(Count = 0 ; Count < Depth-1 ; Count++)
    {
    	*(Input_Data + Count) = *(Input_Data + Count + 1);
    }
    
    *(Input_Data + Depth-1) = Scand;
}



double Real_Time_FIR_Filter(double *b,
                            int     b_Lenth,
                            double *Input_Data)
{    
    int Count;
    double Output_Data = 0;
    
    Input_Data += b_Lenth - 1;  
    
    for(Count = 0; Count < b_Lenth ;Count++)
    {    	
            Output_Data += (*(b + Count)) *
                            (*(Input_Data - Count));                         
    }         
    
    return (double)Output_Data;
}





int main(void)
{
    double w_p = pi/10;
    double w_s = pi/5;
    double w_c = (w_s + w_p)/2;
    printf("w_c =  %f \n" , w_c);
    
    int N = 0;  
    N = (int) ((6.6*pi)/(w_s - w_p) + 0.5);
    if(0 == N%2) N++;    
    printf("N =  %d \n" , N);    
  
    double *Impulse_Response;        
    Impulse_Response = (double *) malloc(sizeof(double)*N);  
    memset(Impulse_Response,
           0,
           sizeof(double)*N);
           
    Unit_Impulse_Response(N,w_c,
                          Hamming,
                          Impulse_Response);       

    double *Input_Buffer;
    double Output_Data = 0;
    Input_Buffer = (double *) malloc(sizeof(double)*N);  
    memset(Input_Buffer,
           0,
           sizeof(double)*N);
    int Count = 0;
    
    FILE *fs; 
    fs=fopen("FIR_Data.txt","w"); 
    
    while(1)
    {   
    	if(Input_Data[Count] == 55) break;
    	 
    	Save_Input_Date (Input_Data[Count],
        	         N,
                	 Input_Buffer);
       
        Output_Data = Real_Time_FIR_Filter(Impulse_Response,
                                           N,
                                           Input_Buffer);
                 		
          
        fprintf(fs,"%lf,",Output_Data);
        //if(((Count+1)%5 == 0)&&(Count != 0))  fprintf(fs,"\r\n"); 
   
        Count++;
    }
          
    /*---------------------display--------------------------------     
    for(Count = 0; Count < N;Count++)
    {
        printf("%d %lf  ",Count,*(Input_Buffer+Count));
        if(((Count+1)%5 == 0)&&(Count != 0)) printf("\n");        	 
    }      
    */  
    
    fclose(fs);
    printf("Finish \n");
    return (int)0;
}


3.頻響的問題

        按照上面程序,參數如下設定。

   

        運行程序,我們就實現了一個FIR濾波器。我們使用Matlab做出其頻響。

        

        好了,這裏可以看出,從其幅度特性看來,我們確實實現了一個低通濾波器。但是,相位特性就比較奇怪(爲了方便看出問題,我已經進行了解卷繞,至於什麼是解卷繞,爲什麼要解卷繞,之後會說)。

       那麼,問題來了!按照道理來說,這個FIR濾波器應該是擁有線性相位特性的,但是爲什麼這裏的線性相位特性確不是一條直線!在接近於阻帶起始頻率的地方,有什麼會震盪?這個問題,之後再解決吧。

      [數字信號處理]相位特性解卷繞   <-----------戳我


4.實際的濾波效果

       爲了驗證效果,我們輸入實際的信號看看。這裏,我們選擇採樣週期爲10ms(0.1ms,2014.10.3日修正),那麼,其通帶頻率和阻帶起始頻率爲


       爲了驗證其性質,我選擇了1KHz和3KHz的頻率混合,最終輸出。輸入的波形如下。


      其輸出波形是如下。

        紅色的“+”是Matlab計算的結果,黑的o是我用C語言實現的濾波器的計算結果,藍的*號是1KHz的信號,也就是希望的輸出。可以看出,這個濾波器有一定的延遲,但是濾波效果還是不錯。

       博客地址:http://blog.csdn.net/thnh169/ 

         

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章