[数字信号处理]IIR滤波器的直接设计(C代码)(转)

时间:2024-02-21 16:00:53

PS:转自http://blog.csdn.net/zhoufan900428/article/details/9076283

1.IIR滤波器的直接设计原理

        不利用模拟滤波器,直接进行数字滤波器的设计的方法,称为直接设计。回忆之前所说的IIR滤波器的直接设计,我们首先设计了巴特沃斯模拟滤波器,然后进行双线性变换,得到数字滤波器。我所使用的是巴特沃斯低通滤波器作为原型滤波器,其振幅特性如下所示。

        
 
        首先,我们先把数字滤波器的指标,根据下式转为模拟滤波器的指标。
        然后根据模拟滤波器的设计指标,计算次数N,然后计算极点,最后选择出稳定的极点,计算模拟滤波器的传递函数。然后,我们通过拉普拉斯反变换,再使用差分替代微分,得到了S平面-Z平面的对应关系,将其转为数字滤波器。
        现在,我们将这个过程,稍微调整一下。

      1.1 巴特沃斯低通数字滤波器的设计

         首先,转换指标的公式,直接带入巴特沃斯低通模拟滤波器的振幅特性表达式,然后化简,我们可以得到一个新的振幅特性
同样的,这个振幅特性具有巴特沃斯低通模拟滤波器的一些特性。函数为单调递减的,通带与阻带都没有纹波。这个新的滤波器,称为巴特沃斯低通数字滤波器。
        与之前一样的,我们的首先先确定所需要的滤波器的次数N,根据次数计算出极点,选择稳定的极点来计算出传递函数,然后就可以得到滤波器的系数了。
        首先是次数的计算,次数的计算,还是要根据阻带衰减指标,根据下式计算。
将巴特沃斯低通数字滤波器的振幅特性带入,我们就可以计算出所需要的滤波器的次数N。
         下一步,我们是需要计算极点。这里与之前的间接设计不同,我们需要做一些变形。首先,将其振幅特性做平方,变为
然后,把部分稍微做下变形,
然后,将替换为Z,带入,则得到了如下式子
 
 
通过这个式子,就可以很方便的计算极点与零点。很容易的能看出,这个滤波器的零点是-1,并且为N重极点(这里是振幅特性的平方所以不是2N)。此时,分母多项式为
由于一步解开很麻烦,我们先将这个式子,关于解开,我们可以得到如下解,
再解z,然后再我们就可以得到极点了,如下所示。
 
 
这里所求得的极点为2N个,为了所设计的滤波器是稳定的,我们需要选择出稳定的极点。在Z平面内,其摸小于1的极点,就是稳定的极点。或者来说,只要滤波器的所有极点均在Z平面的单位圆里,那么,这个滤波器就是稳定的。(题外话,由于FIR滤波器的极点全是0,故FIR滤波器无需考虑稳定性。因为FIR滤波器必定稳定。)
        最后,将极点带入传递函数的公式,就可以得到滤波器的系数了。
     
这里的K可以根据下式去求,
         到此,我们就设计出了一个IIR数字滤波器。

       1.1 巴特沃斯低通数字滤波器设计的实现(C语言)

         首先,还是次数的计算。代码如下
[cpp] view plaincopy
 
  1. N = Ceil(0.5*( log10 ( pow (10, IIR_Filter.Stopband_attenuation/10) - 1) /   
  2.            log10 (IIR_Filter.Stopband/IIR_Filter.Cotoff)));  

         然后,是为了计算极点,我们先计算。这里,将指数函数换为了三角函数。
[cpp] view plaincopy
 
  1. poles_1.Real_part = (0.5)*Cotoff*cos((k+dk)*(pi/N));  
  2. poles_1.Imag_Part= (0.5)*Cotoff*sin((k+dk)*(pi/N));   
         计算出之后,我们计算极点,然后选择稳定的极点。
[cpp] view plaincopy
 
  1. for(k = 0;k <= ((2*N)-1) ; k++)  
  2. {  
  3.     poles_1.Real_part = (0.5)*Cotoff*cos((k+dk)*(pi/N));  
  4.     poles_1.Imag_Part= (0.5)*Cotoff*sin((k+dk)*(pi/N));   
  5.    
  6.     poles_2.Real_part = 1 - poles_1.Real_part ;  
  7.     poles_2.Imag_Part=   -poles_1.Imag_Part;     
  8.   
  9.     poles_1.Real_part = poles_1.Real_part + 1;  
  10.     poles_1.Real_part = poles_1.Real_part;  
  11.    
  12.     Complex_Division(poles_1,poles_2,  
  13.                     &poles[count].Real_part,  
  14.                     &poles[count].Imag_Part);  
  15.           
  16.     if(Complex_Abs(poles[count])<1)  
  17.     {  
  18.         poles[count].Real_part = -poles[count].Real_part;  
  19.         poles[count].Imag_Part= -poles[count].Imag_Part;       
  20.     count++;  
  21.         if (count == N) break;  
  22.     }  
  23.      
  24. }   
        这里的计算,用到了复数的乘法与绝对值。
[cpp] view plaincopy
 
  1. int Complex_Division(COMPLEX a,COMPLEX b,  
  2.                   double *Res_Real,double *Res_Imag)  
  3. {  
  4.      *(Res_Real) =  ((a.Real_part)*(b.Real_part) + (a.Imag_Part)*(b.Imag_Part))/  
  5.                    ((b.Real_part)*(b.Real_part) + (b.Imag_Part)*(b.Imag_Part));  
  6.   
  7.      *(Res_Imag)=   ((a.Real_part)*(b.Imag_Part) - (a.Imag_Part)*(b.Real_part))/  
  8.                    ((b.Real_part)*(b.Real_part) + (b.Imag_Part)*(b.Imag_Part));  
  9.      return (int)1;   
  10. }  
  11. double Complex_Abs(COMPLEX a)  
  12. {  
  13.       return (double)(sqrt((a.Real_part)*(a.Real_part) + (a.Imag_Part)*(a.Imag_Part)));  
  14. }  
        还有就是K的计算。
[cpp] view plaincopy
 
  1. double K_z = 0.0;  
  2. for(count = 0;count <= N;count++)   {K_z += *(az+count);}  
  3. K_z = (K_z/pow ((double)2,N));  
       最后,使用之前在IIR的间接设计的乘开算法,我们就可以得到一个模拟滤波器的系数了。

2.IIR滤波器的直接设计代码(C语言)

[cpp] view plaincopy
 
  1. #include <stdio.h>  
  2. #include <math.h>  
  3. #include <malloc.h>  
  4. #include <string.h>  
  5.   
  6.   
  7. #define     pi     ((double)3.1415926)  
  8.   
  9. typedef struct   
  10. {  
  11.     double Real_part;  
  12.     double Imag_Part;  
  13. } COMPLEX;  
  14.   
  15. struct DESIGN_SPECIFICATION  
  16. {  
  17.     double Cotoff;     
  18.     double Stopband;  
  19.     double Stopband_attenuation;  
  20. };  
  21.   
  22.   
  23.   
  24. int Ceil(double input)  
  25. {  
  26.      if(input != (double)((int)input)) return ((int)input) +1;  
  27.      else return ((int)input);   
  28. }  
  29.   
  30.   
  31. int Complex_Multiple(COMPLEX a,COMPLEX b,  
  32.                                      double *Res_Real,double *Res_Imag)  
  33.       
  34. {  
  35.        *(Res_Real) =  (a.Real_part)*(b.Real_part) - (a.Imag_Part)*(b.Imag_Part);  
  36.        *(Res_Imag)=  (a.Imag_Part)*(b.Real_part) + (a.Real_part)*(b.Imag_Part);      
  37.      return (int)1;   
  38. }  
  39.   
  40.  int Complex_Division(COMPLEX a,COMPLEX b,  
  41.                                       double *Res_Real,double *Res_Imag)  
  42. {  
  43.         *(Res_Real) =  ((a.Real_part)*(b.Real_part) + (a.Imag_Part)*(b.Imag_Part))/  
  44.                        ((b.Real_part)*(b.Real_part) + (b.Imag_Part)*(b.Imag_Part));  
  45.           
  46.      *(Res_Imag)=  ((a.Real_part)*(b.Imag_Part) - (a.Imag_Part)*(b.Real_part))/  
  47.                        ((b.Real_part)*(b.Real_part) + (b.Imag_Part)*(b.Imag_Part));  
  48.   
  49.      return (int)1;   
  50. }  
  51.   
  52. double Complex_Abs(COMPLEX a)  
  53. {  
  54.       return (double)(sqrt((a.Real_part)*(a.Real_part) + (a.Imag_Part)*(a.Imag_Part)));  
  55. }  
  56.   
  57. double IIRFilter  (double *a, int Lenth_a,  
  58.                            double *b, int Lenth_b,  
  59.                            double Input_Data,  
  60.                            double *Memory_Buffer)   
  61. {  
  62.     int Count;  
  63.     double Output_Data = 0;   
  64.     int Memory_Lenth = 0;  
  65.       
  66.     if(Lenth_a >= Lenth_b) Memory_Lenth = Lenth_a;  
  67.     else Memory_Lenth = Lenth_b;  
  68.       
  69.     Output_Data += (*a) * Input_Data;  //a(0)*x(n)               
  70.       
  71.     for(Count = 1; Count < Lenth_a ;Count++)  
  72.     {  
  73.         Output_Data -= (*(a + Count)) *  
  74.                        (*(Memory_Buffer + (Memory_Lenth - 1) - Count));                                         
  75.     }   
  76.       
  77.     //------------------------save data--------------------------//   
  78.     *(Memory_Buffer + Memory_Lenth - 1) = Output_Data;  
  79.     Output_Data = 0;  
  80.     //----------------------------------------------------------//   
  81.       
  82.     for(Count = 0; Count < Lenth_b ;Count++)  
  83.     {         
  84.         Output_Data += (*(b + Count)) *  
  85.                        (*(Memory_Buffer + (Memory_Lenth - 1) - Count));        
  86.     }  
  87.       
  88.     //------------------------move data--------------------------//   
  89.     for(Count = 0 ; Count < Memory_Lenth -1 ; Count++)  
  90.     {  
  91.         *(Memory_Buffer + Count) = *(Memory_Buffer + Count + 1);  
  92.     }  
  93.     *(Memory_Buffer + Memory_Lenth - 1) = 0;  
  94.     //-----------------------------------------------------------//  
  95.   
  96.     return (double)Output_Data;   
  97. }  
  98.   
  99.   
  100. int Direct( double Cotoff,  
  101.                double Stopband,  
  102.                double Stopband_attenuation,  
  103.                int N,  
  104.                double *az,double *bz)  
  105. {  
  106.       printf("Wc =  %lf  [rad/sec] \n" ,Cotoff);  
  107.       printf("Ws =  %lf  [rad/sec] \n" ,Stopband);  
  108.       printf("As  =  %lf  [dB] \n" ,Stopband_attenuation);  
  109.       printf("--------------------------------------------------------\n" );  
  110.       printf("N:  %d  \n" ,N);  
  111.       printf("--------------------------------------------------------\n" );  
  112.   
  113.       COMPLEX poles[N],poles_1,poles_2;  
  114.       double dk = 0;  
  115.       int k = 0;  
  116.     int count = 0,count_1 = 0;;  
  117.       
  118.       if((N%2) == 0) dk = 0.5;  
  119.       else dk = 0;  
  120.   
  121.       for(k = 0;k <= ((2*N)-1) ; k++)  
  122.       {  
  123.              poles_1.Real_part = (0.5)*Cotoff*cos((k+dk)*(pi/N));  
  124.          poles_1.Imag_Part= (0.5)*Cotoff*sin((k+dk)*(pi/N));      
  125.    
  126.              poles_2.Real_part = 1 - poles_1.Real_part ;  
  127.          poles_2.Imag_Part=   -poles_1.Imag_Part;     
  128.   
  129.          poles_1.Real_part = poles_1.Real_part + 1;  
  130.              poles_1.Real_part = poles_1.Real_part;  
  131.    
  132.              Complex_Division(poles_1,poles_2,  
  133.                                     &poles[count].Real_part,  
  134.                                     &poles[count].Imag_Part);  
  135.           
  136.          if(Complex_Abs(poles[count])<1)  
  137.          {  
  138.                poles[count].Real_part = -poles[count].Real_part;  
  139.            poles[count].Imag_Part= -poles[count].Imag_Part;    
  140.                count++;  
  141.            if (count == N) break;  
  142.          }  
  143.      
  144.       }   
  145.   
  146.       printf("pk =   \n" );     
  147.       for(count = 0;count < N ;count++)  
  148.       {  
  149.            printf("(%lf) + (%lf i) \n" ,-poles[count].Real_part  
  150.                                     ,-poles[count].Imag_Part);  
  151.       }  
  152.       printf("--------------------------------------------------------\n" );  
  153.   
  154.       COMPLEX Res[N+1],Res_Save[N+1];  
  155.   
  156.       Res[0].Real_part = poles[0].Real_part;   
  157.       Res[0].Imag_Part= poles[0].Imag_Part;  
  158.   
  159.       Res[1].Real_part = 1;   
  160.       Res[1].Imag_Part= 0;  
  161.   
  162.   
  163.       for(count_1 = 0;count_1 < N-1;count_1++)  
  164.       {  
  165.          for(count = 0;count <= count_1 + 2;count++)  
  166.          {  
  167.               if(0 == count)  
  168.            {  
  169.                     Complex_Multiple(Res[count], poles[count_1+1],  
  170.                                    &(Res_Save[count].Real_part),  
  171.                                    &(Res_Save[count].Imag_Part));  
  172.               }  
  173.   
  174.               else if((count_1 + 2) == count)  
  175.               {  
  176.                      Res_Save[count].Real_part  += Res[count - 1].Real_part;  
  177.                 Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;    
  178.               }         
  179.             else   
  180.             {  
  181.                      Complex_Multiple(Res[count], poles[count_1+1],  
  182.                                    &(Res_Save[count].Real_part),  
  183.                                    &(Res_Save[count].Imag_Part));  
  184.                   
  185.                 Res_Save[count].Real_part  += Res[count - 1].Real_part;  
  186.                 Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;  
  187.             }  
  188.          }  
  189.   
  190.          for(count = 0;count <= N;count++)  
  191.          {  
  192.                Res[count].Real_part = Res_Save[count].Real_part;   
  193.                    Res[count].Imag_Part= Res_Save[count].Imag_Part;  
  194.             *(az + N - count) = Res[count].Real_part;  
  195.          }  
  196.       }  
  197.   
  198.         double K_z = 0.0;  
  199.     for(count = 0;count <= N;count++)   {K_z += *(az+count);}  
  200.     K_z = (K_z/pow ((double)2,N));  
  201.     printf("K =  %lf \n" , K_z);  
  202.   
  203.     for(count = 0;count <= N;count++)  
  204.     {  
  205.              Res[count].Real_part = 0;  
  206.          Res[count].Imag_Part= 0;  
  207.          Res_Save[count].Real_part = 0;  
  208.          Res_Save[count].Imag_Part= 0;  
  209.     }  
  210.   
  211.       COMPLEX zero;  
  212.   
  213.       zero.Real_part  =  1;  
  214.       zero.Imag_Part =  0;  
  215.   
  216.       Res[0].Real_part = 1;   
  217.       Res[0].Imag_Part= 0;  
  218.       Res[1].Real_part = 1;   
  219.       Res[1].Imag_Part= 0;  
  220.   
  221.       for(count_1 = 0;count_1 < N-1;count_1++)  
  222.       {  
  223.          for(count = 0;count <= count_1 + 2;count++)  
  224.          {  
  225.               if(0 == count)  
  226.            {  
  227.                     Complex_Multiple(Res[count], zero,  
  228.                                    &(Res_Save[count].Real_part),  
  229.                                    &(Res_Save[count].Imag_Part));  
  230.               }  
  231.   
  232.               else if((count_1 + 2) == count)  
  233.               {  
  234.                      Res_Save[count].Real_part  += Res[count - 1].Real_part;  
  235.                 Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;    
  236.               }         
  237.             else   
  238.             {  
  239.                      Complex_Multiple(Res[count],zero,  
  240.                                    &(Res_Save[count].Real_part),  
  241.                                    &(Res_Save[count].Imag_Part));  
  242.                   
  243.                 Res_Save[count].Real_part  += Res[count - 1].Real_part;  
  244.                 Res_Save[count].Imag_Part += Res[count - 1].Imag_Part;  
  245.             }  
  246.          }  
  247.   
  248.          for(count = 0;count <= N;count++)  
  249.          {  
  250.                Res[count].Real_part = Res_Save[count].Real_part;   
  251.                  Res[count].Imag_Part= Res_Save[count].Imag_Part;  
  252.             *(bz + N - count) = Res[count].Real_part;  
  253.          }  
  254.       }  
  255.   
  256.     for(count = 0;count <= N;count++)  
  257.     {  
  258.            *(bz + N - count) = *(bz + N - count) * K_z;  
  259.     }  
  260.         //------------------------display---------------------------------//  
  261.       printf("bz =  [" );     
  262.       for(count= 0;count <= N ;count++)  
  263.       {  
  264.            printf("%lf ", *(bz+count));  
  265.       }  
  266.       printf(" ] \n" );  
  267.       printf("az =  [" );     
  268.       for(count= 0;count <= N ;count++)  
  269.       {  
  270.            printf("%lf ", *(az+count));  
  271.       }  
  272.       printf(" ] \n" );  
  273.       printf("--------------------------------------------------------\n" );  
  274.        
  275.       return (int)1;  
  276. }  
  277.   
  278.   
  279.   
  280.   
  281.   
  282.   
  283. int main(void)  
  284. {  
  285.      int count;  
  286.   
  287.      struct DESIGN_SPECIFICATION IIR_Filter;  
  288.   
  289.      IIR_Filter.Cotoff      = (double)(pi/4);         //[red]  
  290.      IIR_Filter.Stopband = (double)((pi*3)/4);   //[red]  
  291.      IIR_Filter.Stopband_attenuation = 30;        //[dB]  
  292.   
  293.      int N;  
  294.   
  295.      IIR_Filter.Cotoff = 2 * tan((IIR_Filter.Cotoff)/2);            //[red/sec]  
  296.      IIR_Filter.Stopband = 2 * tan((IIR_Filter.Stopband)/2);   //[red/sec]  
  297.   
  298.      N = Ceil(0.5*( log10 ( pow (10, IIR_Filter.Stopband_attenuation/10) - 1) /   
  299.                       log10 (IIR_Filter.Stopband/IIR_Filter.Cotoff)));  
  300.   
  301.      
  302.      double az[N+1] , bz[N+1];  
  303.      Direct(IIR_Filter.Cotoff,  
  304.              IIR_Filter.Stopband,  
  305.              IIR_Filter.Stopband_attenuation,  
  306.                N,  
  307.              az,bz);  
  308.   
  309.     double *Memory_Buffer;  
  310.     Memory_Buffer = (double *) malloc(sizeof(double)*(N+1));    
  311.     memset(Memory_Buffer,  
  312.                 0,  
  313.                 sizeof(double)*(N+1));  
  314.   
  315.      FILE* Input_Data;  
  316.      FILE* Output_Data;  
  317.   
  318.      double Input = 0 ;  
  319.     double Output = 0;  
  320.        
  321.      Input_Data   = fopen("input.dat","r");   
  322.      Output_Data = fopen("output.txt","w");   
  323.   
  324.      while(1)  
  325.      {  
  326.           if(fscanf(Input_Data, "%lf", &Input) == EOF)  break;  
  327.   
  328.           Output = IIRFilter(  az, (N+1),  
  329.                                       bz, (N+1),  
  330.                                       Input,  
  331.                                       Memory_Buffer );  
  332.             
  333.           fprintf(Output_Data,"%lf,",Output);  
  334.         }  
  335.   
  336.           
  337.       
  338.      printf("Finish \n" );  
  339.        
  340.      return (int)0;  
  341. }  

3.IIR滤波器的直接设计(例)

       3.1 设计指标

          

         3.2 程序执行结果

             根据之前所说的原理,使用前面的程序,我们可以得到满足设计指标的IIR滤波器的参数。程序在gcc下编译通过,执行结果如下

           3.3设计出来的IIR滤波器的频响

 

            3.4实际滤波效果

                首先,设定采样频率为10kHz,计算出如下非正规化频率
        
我们的为验证滤波器的性能,其输入信号确定为0.5kHz与4kHz的正弦叠加信号,如下。
其理想的输出为0.5kHz正弦信号,实际输出为下。
其中,红色的----是Matlab计算的输出,粉色的o是用C语言计算的输出,蓝色的线是理想输出(也就是混合前的0.5kHz信号)。
         博客地址:http://blog.csdn.net/thnh169/ 
            到此,我们就实现了一个IIR滤波器。