https://blog.csdn.net/syrchina/article/details/11731325 1.單位沖擊響應(yīng)與頻響
就如同之前所說的一樣,使用下圖所示的單位沖擊響應(yīng),所設(shè)計(jì)的濾波器,是無法實(shí)現(xiàn)的。
現(xiàn)在,讓我們看看其這個(gè)濾波器的頻響。所謂頻響,就是計(jì)算其單位沖擊響應(yīng)的離散時(shí)間傅里葉變換,
我們可以看出,這個(gè)濾波器的頻響的計(jì)算結(jié)果是實(shí)數(shù),并沒有虛數(shù)部分。也就是,其相位譜一直是0,也就意味著,這個(gè)濾波器輸入與輸出之間沒有延遲,這種相位特性稱為0延遲相位特性。
但是,這個(gè)濾波器無法是無法實(shí)現(xiàn)的。我們實(shí)際計(jì)算一下該濾波器的輸入輸出,就可以明白。
這個(gè)濾波器在計(jì)算的過程中,需要過去的值和未來的值。未來的值是不可預(yù)測的,所以,這個(gè)濾波器無法實(shí)現(xiàn)。為了使得這個(gè)濾波器可以實(shí)現(xiàn),我們只好移動其單位沖擊響應(yīng),使得其不再需要未來的值。比如,就像下面這樣移動。
這樣的話,這個(gè)濾波器就可以實(shí)現(xiàn)了,我們只需要記錄其40個(gè)過去的輸入值和現(xiàn)在的輸入值。但是,由于移動了其單位沖擊響應(yīng),會不會對頻響產(chǎn)生什么影響呢,我們來看看。
為了更好的說明問題,L去代替之前例子中的20。
移動之后頻響,我們根據(jù)上面式子可以得出兩個(gè)結(jié)論:1,移動不會對幅度譜產(chǎn)生影響。2,,移動會對相位產(chǎn)生一個(gè)延遲,這個(gè)延遲主要取決于移動的長度,移動的長度越長,延遲越大。但是,這個(gè)移動是線性的。
因此,我們把這個(gè)移動的相位特性稱為,線性相位特性。到這里,我們移動后的,因果的,可實(shí)現(xiàn)的濾波器的單位沖擊響應(yīng),如下所示。
2.窗函數(shù)實(shí)現(xiàn)的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.頻響的問題
按照上面程序,參數(shù)如下設(shè)定。
運(yùn)行程序,我們就實(shí)現(xiàn)了一個(gè)FIR濾波器。我們使用Matlab做出其頻響。
好了,這里可以看出,從其幅度特性看來,我們確實(shí)實(shí)現(xiàn)了一個(gè)低通濾波器。但是,相位特性就比較奇怪(為了方便看出問題,我已經(jīng)進(jìn)行了解卷繞,至于什么是解卷繞,為什么要解卷繞,之后會說)。
那么,問題來了!按照道理來說,這個(gè)FIR濾波器應(yīng)該是擁有線性相位特性的,但是為什么這里的線性相位特性確不是一條直線!在接近于阻帶起始頻率的地方,有什么會震蕩?這個(gè)問題,之后再解決吧。
[數(shù)字信號處理]相位特性解卷繞 <-----------戳我
4.實(shí)際的濾波效果
為了驗(yàn)證效果,我們輸入實(shí)際的信號看看。這里,我們選擇采樣周期為10ms,那么,其通帶頻率和阻帶起始頻率為
為了驗(yàn)證其性質(zhì),我選擇了1KHz和3KHz的頻率混合,最終輸出。輸入的波形如下。
其輸出波形是如下。
紅色的“+”是Matlab計(jì)算的結(jié)果,黑的o是我用C語言實(shí)現(xiàn)的濾波器的計(jì)算結(jié)果,藍(lán)的*號是1KHz的信號,也就是希望的輸出。可以看出,這個(gè)濾波器有一定的延遲,但是濾波效果還是不錯(cuò)。 from:
http://blog.csdn.net/thnh169/
|