1.模擬濾波器的設(shè)計(jì)
1.1巴特沃斯濾波器的次數(shù)
根據(jù)給定的參數(shù)設(shè)計(jì)模擬濾波器,然后進(jìn)行變數(shù)變換,求取數(shù)字濾波器的方法,稱為濾波器的間接設(shè)計(jì)。做為數(shù)字濾波器的設(shè)計(jì)基礎(chǔ)的模擬濾波器,稱之為原型濾波器。這里,我們首先介紹的是最簡單最基礎(chǔ)的原型濾波器,巴特沃斯低通濾波器。由于IIR濾波器不具有線性相位特性,因此不必考慮相位特性,直接考慮其振幅特性。
在這里,N是濾波器的次數(shù),Ωc是截止頻率。從上式的振幅特性可以看出,這個(gè)是單調(diào)遞減的函數(shù),其振幅特性是不存在紋波的。設(shè)計(jì)的時(shí)候,一般需要先計(jì)算跟所需要設(shè)計(jì)參數(shù)相符合的次數(shù)N。首先,就需要先由阻帶頻率,計(jì)算出阻帶衰減
將巴特沃斯低通濾波器的振幅特性,直接帶入上式,則有
最后,可以解得次數(shù)N為
當(dāng)然,這里的N只能為正數(shù),因此,若結(jié)果為小數(shù),則舍棄小數(shù),向上取整。
1.2巴特沃斯濾波器的傳遞函數(shù)
巴特沃斯低通濾波器的傳遞函數(shù),可由其振幅特性的分母多項(xiàng)式求得。其分母多項(xiàng)式

根據(jù)S解開,可以得到極點(diǎn)。這里,為了方便處理,我們分為兩種情況去解這個(gè)方程。當(dāng)N為偶數(shù)的時(shí)候,
這里,使用了歐拉公式
。同樣的,當(dāng)N為奇數(shù)的時(shí)候,

同樣的,這里也使用了歐拉公式。歸納以上,極點(diǎn)的解為

上式所求得的極點(diǎn),是在s平面內(nèi),在半徑為Ωc的圓上等間距的點(diǎn),其數(shù)量為2N個(gè)。為了使得其IIR濾波器穩(wěn)定,那么,只能選取極點(diǎn)在S平面左半平面的點(diǎn)。選定了穩(wěn)定的極點(diǎn)之后,其模擬濾波器的傳遞函數(shù)就可由下式求得。

1.3巴特沃斯濾波器的實(shí)現(xiàn)(C語言)
首先,是次數(shù)的計(jì)算。次數(shù)的計(jì)算,我們可以由下式求得。
其對應(yīng)的C語言程序?yàn)?
- N = Ceil(0.5*( log10 ( pow (10, Stopband_attenuation/10) - 1) /
- log10 (Stopband/Cotoff) ));
然后是極點(diǎn)的選擇,這里由于涉及到復(fù)數(shù)的操作,我們就聲明一個(gè)復(fù)數(shù)結(jié)構(gòu)體就可以了。最重要的是,極點(diǎn)的計(jì)算含有自然指數(shù)函數(shù),這點(diǎn)對于計(jì)算機(jī)來講,不是太方便,所以,我們將其替換為三角函數(shù),

這樣的話,實(shí)部與虛部就還可以分開來計(jì)算。其代碼實(shí)現(xiàn)為
- typedef struct
- {
- double Real_part;
- double Imag_Part;
- } COMPLEX;
-
-
- COMPLEX poles[N];
-
- for(k = 0;k <= ((2*N)-1) ; k++)
- {
- if(Cotoff*cos((k+dk)*(pi/N)) < 0)
- {
- poles[count].Real_part = -Cotoff*cos((k+dk)*(pi/N));
- poles[count].Imag_Part= -Cotoff*sin((k+dk)*(pi/N));
- count++;
- if (count == N) break;
- }
- }
計(jì)算出穩(wěn)定的極點(diǎn)之后,就可以進(jìn)行傳遞函數(shù)的計(jì)算了。傳遞的函數(shù)的計(jì)算,就像下式一樣

這里,為了得到模擬濾波器的系數(shù),需要將分母乘開。很顯然,這里的極點(diǎn)不一定是整數(shù),或者來說,這里的乘開需要做復(fù)數(shù)運(yùn)算。其復(fù)數(shù)的乘法代碼如下,
- int Complex_Multiple(COMPLEX a,COMPLEX b,
- double *Res_Real,double *Res_Imag)
-
- {
- *(Res_Real) = (a.Real_part)*(b.Real_part) - (a.Imag_Part)*(b.Imag_Part);
- *(Res_Imag)= (a.Imag_Part)*(b.Real_part) + (a.Real_part)*(b.Imag_Part);
- return (int)1;
- }
有了乘法代碼之后,我們現(xiàn)在簡單的情況下,看看其如何計(jì)算其濾波器系數(shù)。我們做如下假設(shè)
這個(gè)時(shí)候,其傳遞函數(shù)為
將其乘開,其大致的關(guān)系就像下圖所示一樣。

計(jì)算的關(guān)系一目了然,這樣的話,實(shí)現(xiàn)就簡單多了。高階的情況下也一樣,重復(fù)這種計(jì)算就可以了。其代碼為
- Res[0].Real_part = poles[0].Real_part;
- Res[0].Imag_Part= poles[0].Imag_Part;
- Res[1].Real_part = 1;
- Res[1].Imag_Part= 0;
-
- for(count_1 = 0;count_1 < N-1;count_1++)
- {
- for(count = 0;count <= count_1 + 2;count++)
- {
- if(0 == count)
- {
- Complex_Multiple(Res[count], poles[count_1+1],
- &(Res_Save[count].Real_part),
- &(Res_Save[count].Imag_Part));
- }
- else if((count_1 + 2) == count)
- {
- Res_Save[count].Real_part += Res[count - 1].Real_part;
- Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;
- }
- else
- {
- Complex_Multiple(Res[count], poles[count_1+1],
- &(Res_Save[count].Real_part),
- &(Res_Save[count].Imag_Part));
- 1 Res_Save[count].Real_part += Res[count - 1].Real_part;
- Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;
- }
- }
- *(b+N) = *(a+N);
到此,我們就可以得到一個(gè)模擬濾波器巴特沃斯低通濾波器了。
2.雙1次z變換
我們?yōu)榱藢⒛M濾波器轉(zhuǎn)換為數(shù)字濾波器的,可以用的方法很多。這里著重說說雙1次z變換。我們希望通過雙1次z變換,建立一個(gè)s平面到z平面的映射關(guān)系,將模擬濾波器轉(zhuǎn)換為數(shù)字濾波器。
和之前的例子一樣,我們假設(shè)有如下模擬濾波器的傳遞函數(shù)。
將其做拉普拉斯逆變換,可得到其時(shí)間域內(nèi)的連續(xù)微分方程式,
其中,x(t)表示輸入,y(t)表示輸出。然后我們需要將其離散化,假設(shè)其采樣周期是T,用差分方程去近似的替代微分方程,可以得到下面結(jié)果
然后使用z變換,再將其化簡??傻玫饺缦陆Y(jié)果
從而,我們可以得到了s平面到z平面的映射關(guān)系,即
由于所有的高階系統(tǒng)都可以視為一階系統(tǒng)的并聯(lián),所以,這個(gè)映射關(guān)系在高階系統(tǒng)中,也是成立的。
然后,將關(guān)系式
帶入上式,可得
到這里,我們可以就可以得到Ω與ω的對應(yīng)關(guān)系了。
這里的Ω與ω的對應(yīng)關(guān)系很重要。我們最終的目的設(shè)計(jì)的是數(shù)字濾波器,所以,設(shè)計(jì)時(shí)候給的參數(shù)必定是數(shù)字濾波器的指標(biāo)。而我們通過間接設(shè)計(jì)設(shè)計(jì)IIR濾波器時(shí)候,首先是要設(shè)計(jì)模擬濾波器,再通過變換,得到數(shù)字濾波器。那么,我們首先需要做的,就是將數(shù)字濾波器的指標(biāo),轉(zhuǎn)換為模擬濾波器的指標(biāo),基于這個(gè)指標(biāo)去設(shè)計(jì)模擬濾波器。另外,這里的采樣時(shí)間T的取值很隨意,為了方便計(jì)算,一般取1s就可以。
2.2雙1次z變換的實(shí)現(xiàn)(C語言)
我們設(shè)計(jì)好的巴特沃斯低通濾波器的傳遞函數(shù)如下所示。
我們將其進(jìn)行雙1次z變換,我們可以得到如下式子
可以看出,我們還是需要將式子乘開,進(jìn)行合并同類項(xiàng),這個(gè)跟之前說的算法相差不大。其代碼為。
- for(Count = 0;Count<=N;Count++)
- {
- for(Count_Z = 0;Count_Z <= N;Count_Z++)
- {
- Res[Count_Z] = 0;
- Res_Save[Count_Z] = 0;
- }
- Res_Save [0] = 1;
- for(Count_1 = 0; Count_1 < N-Count;Count_1++)
- {
- for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++)
- {
- if(Count_2 == 0) Res[Count_2] += Res_Save[Count_2];
- else if((Count_2 == (Count_1+1))&&(Count_1 != 0))
- Res[Count_2] += -Res_Save[Count_2 - 1];
- else Res[Count_2] += Res_Save[Count_2] - Res_Save[Count_2 - 1];
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- Res_Save[Count_Z] = Res[Count_Z] ;
- Res[Count_Z] = 0;
- }
- }
- for(Count_1 = (N-Count); Count_1 < N;Count_1++)
- {
- for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++)
- {
- if(Count_2 == 0) Res[Count_2] += Res_Save[Count_2];
- else if((Count_2 == (Count_1+1))&&(Count_1 != 0))
- Res[Count_2] += Res_Save[Count_2 - 1];
- else
- Res[Count_2] += Res_Save[Count_2] + Res_Save[Count_2 - 1];
- }
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- Res_Save[Count_Z] = Res[Count_Z] ;
- Res[Count_Z] = 0;
- }
- }
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- *(az+Count_Z) += pow(2,N-Count) * (*(as+Count)) *
- Res_Save[Count_Z];
- *(bz+Count_Z) += (*(bs+Count)) * Res_Save[Count_Z];
- }
- }
到此,我們就已經(jīng)實(shí)現(xiàn)了一個(gè)數(shù)字濾波器。
3.IIR濾波器的間接設(shè)計(jì)代碼(C語言)
- #include <stdio.h>
- #include <math.h>
- #include <malloc.h>
- #include <string.h>
-
-
- #define pi ((double)3.1415926)
-
-
- struct DESIGN_SPECIFICATION
- {
- double Cotoff;
- double Stopband;
- double Stopband_attenuation;
- };
-
- typedef struct
- {
- double Real_part;
- double Imag_Part;
- } COMPLEX;
-
-
-
- int Ceil(double input)
- {
- if(input != (int)input) return ((int)input) +1;
- else return ((int)input);
- }
-
-
- int Complex_Multiple(COMPLEX a,COMPLEX b
- ,double *Res_Real,double *Res_Imag)
-
- {
- *(Res_Real) = (a.Real_part)*(b.Real_part) - (a.Imag_Part)*(b.Imag_Part);
- *(Res_Imag)= (a.Imag_Part)*(b.Real_part) + (a.Real_part)*(b.Imag_Part);
- return (int)1;
- }
-
-
- int Buttord(double Cotoff,
- double Stopband,
- double Stopband_attenuation)
- {
- int N;
-
- printf("Wc = %lf [rad/sec] \n" ,Cotoff);
- printf("Ws = %lf [rad/sec] \n" ,Stopband);
- printf("As = %lf [dB] \n" ,Stopband_attenuation);
- printf("--------------------------------------------------------\n" );
-
- N = Ceil(0.5*( log10 ( pow (10, Stopband_attenuation/10) - 1) /
- log10 (Stopband/Cotoff) ));
-
-
- return (int)N;
- }
-
-
- int Butter(int N, double Cotoff,
- double *a,
- double *b)
- {
- double dk = 0;
- int k = 0;
- int count = 0,count_1 = 0;
- COMPLEX poles[N];
- COMPLEX Res[N+1],Res_Save[N+1];
-
- if((N%2) == 0) dk = 0.5;
- else dk = 0;
-
- for(k = 0;k <= ((2*N)-1) ; k++)
- {
- if(Cotoff*cos((k+dk)*(pi/N)) < 0)
- {
- poles[count].Real_part = -Cotoff*cos((k+dk)*(pi/N));
- poles[count].Imag_Part= -Cotoff*sin((k+dk)*(pi/N));
- count++;
- if (count == N) break;
- }
- }
-
- printf("Pk = \n" );
- for(count = 0;count < N ;count++)
- {
- printf("(%lf) + (%lf i) \n" ,-poles[count].Real_part
- ,-poles[count].Imag_Part);
- }
- printf("--------------------------------------------------------\n" );
-
- Res[0].Real_part = poles[0].Real_part;
- Res[0].Imag_Part= poles[0].Imag_Part;
-
- Res[1].Real_part = 1;
- Res[1].Imag_Part= 0;
-
- for(count_1 = 0;count_1 < N-1;count_1++)
- {
- for(count = 0;count <= count_1 + 2;count++)
- {
- if(0 == count)
- {
- Complex_Multiple(Res[count], poles[count_1+1],
- &(Res_Save[count].Real_part),
- &(Res_Save[count].Imag_Part));
- //printf( "Res_Save : (%lf) + (%lf i) \n" ,Res_Save[0].Real_part,Res_Save[0].Imag_Part);
- }
-
- else if((count_1 + 2) == count)
- {
- Res_Save[count].Real_part += Res[count - 1].Real_part;
- Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;
- }
- else
- {
- Complex_Multiple(Res[count], poles[count_1+1],
- &(Res_Save[count].Real_part),
- &(Res_Save[count].Imag_Part));
-
- //printf( "Res : (%lf) + (%lf i) \n" ,Res[count - 1].Real_part,Res[count - 1].Imag_Part);
- //printf( "Res_Save : (%lf) + (%lf i) \n" ,Res_Save[count].Real_part,Res_Save[count].Imag_Part);
-
- Res_Save[count].Real_part += Res[count - 1].Real_part;
- Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;
-
- //printf( "Res_Save : (%lf) + (%lf i) \n" ,Res_Save[count].Real_part,Res_Save[count].Imag_Part);
-
- }
- //printf("There \n" );
- }
-
- for(count = 0;count <= N;count++)
- {
- Res[count].Real_part = Res_Save[count].Real_part;
- Res[count].Imag_Part= Res_Save[count].Imag_Part;
-
- *(a + N - count) = Res[count].Real_part;
- }
-
- //printf("There!! \n" );
-
- }
-
- *(b+N) = *(a+N);
-
- //------------------------display---------------------------------//
- printf("bs = [" );
- for(count = 0;count <= N ;count++)
- {
- printf("%lf ", *(b+count));
- }
- printf(" ] \n" );
-
- printf("as = [" );
- for(count = 0;count <= N ;count++)
- {
- printf("%lf ", *(a+count));
- }
- printf(" ] \n" );
-
- printf("--------------------------------------------------------\n" );
-
- return (int) 1;
- }
-
-
- int Bilinear(int N,
- double *as,double *bs,
- double *az,double *bz)
- {
- int Count = 0,Count_1 = 0,Count_2 = 0,Count_Z = 0;
- double Res[N+1];
- double Res_Save[N+1];
-
- for(Count_Z = 0;Count_Z <= N;Count_Z++)
- {
- *(az+Count_Z) = 0;
- *(bz+Count_Z) = 0;
- }
-
-
- for(Count = 0;Count<=N;Count++)
- {
- for(Count_Z = 0;Count_Z <= N;Count_Z++)
- {
- Res[Count_Z] = 0;
- Res_Save[Count_Z] = 0;
- }
- Res_Save [0] = 1;
-
- for(Count_1 = 0; Count_1 < N-Count;Count_1++)
- {
- for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++)
- {
- if(Count_2 == 0)
- {
- Res[Count_2] += Res_Save[Count_2];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
-
- else if((Count_2 == (Count_1+1))&&(Count_1 != 0))
- {
- Res[Count_2] += -Res_Save[Count_2 - 1];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
-
- else
- {
- Res[Count_2] += Res_Save[Count_2] - Res_Save[Count_2 - 1];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
- }
-
- //printf( "Res : ");
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- Res_Save[Count_Z] = Res[Count_Z] ;
- Res[Count_Z] = 0;
- //printf( "[%d] %lf " ,Count_Z, Res_Save[Count_Z]);
- }
- //printf(" \n" );
-
- }
-
- for(Count_1 = (N-Count); Count_1 < N;Count_1++)
- {
- for(Count_2 = 0; Count_2 <= Count_1+1;Count_2++)
- {
- if(Count_2 == 0)
- {
- Res[Count_2] += Res_Save[Count_2];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
-
- else if((Count_2 == (Count_1+1))&&(Count_1 != 0))
- {
- Res[Count_2] += Res_Save[Count_2 - 1];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
-
- else
- {
- Res[Count_2] += Res_Save[Count_2] + Res_Save[Count_2 - 1];
- //printf( "Res[%d] %lf \n" , Count_2 ,Res[Count_2]);
- }
- }
-
- // printf( "Res : ");
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- Res_Save[Count_Z] = Res[Count_Z] ;
- Res[Count_Z] = 0;
- //printf( "[%d] %lf " ,Count_Z, Res_Save[Count_Z]);
- }
- //printf(" \n" );
- }
-
-
- //printf( "Res : ");
- for(Count_Z = 0;Count_Z<= N;Count_Z++)
- {
- *(az+Count_Z) += pow(2,N-Count) * (*(as+Count)) * Res_Save[Count_Z];
- *(bz+Count_Z) += (*(bs+Count)) * Res_Save[Count_Z];
- //printf( " %lf " ,*(bz+Count_Z));
- }
- //printf(" \n" );
-
- }
-
-
-
- for(Count_Z = N;Count_Z >= 0;Count_Z--)
- {
- *(bz+Count_Z) = (*(bz+Count_Z))/(*(az+0));
- *(az+Count_Z) = (*(az+Count_Z))/(*(az+0));
- }
-
-
- //------------------------display---------------------------------//
- printf("bz = [" );
- for(Count_Z= 0;Count_Z <= N ;Count_Z++)
- {
- printf("%lf ", *(bz+Count_Z));
- }
- printf(" ] \n" );
- printf("az = [" );
- for(Count_Z= 0;Count_Z <= N ;Count_Z++)
- {
- printf("%lf ", *(az+Count_Z));
- }
- printf(" ] \n" );
- printf("--------------------------------------------------------\n" );
-
-
-
- return (int) 1;
- }
-
-
-
-
-
- int main(void)
- {
- int count;
-
- struct DESIGN_SPECIFICATION IIR_Filter;
-
- IIR_Filter.Cotoff = (double)(pi/2); //[red]
- IIR_Filter.Stopband = (double)((pi*3)/4); //[red]
- IIR_Filter.Stopband_attenuation = 30; //[dB]
-
- int N;
-
- IIR_Filter.Cotoff = 2 * tan((IIR_Filter.Cotoff)/2); //[red/sec]
- IIR_Filter.Stopband = 2 * tan((IIR_Filter.Stopband)/2); //[red/sec]
-
- N = Buttord(IIR_Filter.Cotoff,
- IIR_Filter.Stopband,
- IIR_Filter.Stopband_attenuation);
- printf("N: %d \n" ,N);
- printf("--------------------------------------------------------\n" );
-
- double as[N+1] , bs[N+1];
- Butter(N,
- IIR_Filter.Cotoff,
- as,
- bs);
-
- double az[N+1] , bz[N+1];
-
- Bilinear(N,
- as,bs,
- az,bz);
-
- printf("Finish \n" );
- return (int)0;
- }
3.間接設(shè)計(jì)實(shí)現(xiàn)的IIR濾波器的性能
使用上述程序,gcc編譯通過,執(zhí)行結(jié)果如下。
其頻率響應(yīng)如下所示。博客地址:
http://blog.csdn.net/thnh169/
