IIR濾波器軟件實現(Matlab+C++)


使用C++來寫一個IIR濾波器

我們首先要在MATLAB中設計一個IIR濾波器,並生成一個頭文件,這個頭文件中反映了IIR濾波器的頻率響應特性


理論支持

IIR濾波叫做遞歸濾波器,它是一種具有反饋的濾波器。當階數較大時一般采取多個二階節濾波進行串聯,這樣可以提高系統穩定性。

一個二階節系數規律如圖所示:

可以寫出第K個二階節的差分方程

N個二階節的級聯結構如下圖所示:

根據二階節圖,把前一級的輸出作為后一級的輸入,就可以通過軟件實現IIR數字濾波的功能。


 

使用Matlab生成頭文件

首先打開MATLAB中Filter Design & Analysis Tool

 

 

 

 

 

 

 

 

 

 

 

 

 

 

這里我們先設計一個低通濾波器

Fs代表采樣頻率,采樣頻率必須大於原信號最高頻率的兩倍,

否則會產生頻譜混疊。

Fpass為通帶頻率,Fstop為阻帶截止頻率

這些參數設置好就可以點擊Design Filter

 

生成的是一個二階節濾波組合,一共有31階,也就是多個二階濾波器的組合

接着在Target選項中生成C Header File

 Numerator為分子系數數組的命名,Numerator length為分子系數數組的長度,

 Denominator為分母。


對生成頭文件進行分析

以下以Fpass為10K,Fstop為12K的低通濾波器舉栵

在使用頭文件前需要根據情況將Matlab的數據類型轉換為C++支持的數據類型,這里我們使用double類型

 

在分析頭文件前先看下Matlab提供的第一節濾波參數

以第一個二階節的數據舉例:

  • Numerator: 1  2  1
  • Denominator: 1  -0.55930961405944157  0.92579835996619642
  • Gain:0.34162218647668868

Numerator為分子的系數,分別為b0,b1,b2

Denominator為分母的系數,分別為a0,a1,a2.

Gain為各節的增益,此項為了穩定各節,穩定信號大小

 

接着對照頭文件,以下為頭文件主要部分的一段截取:

#define MWSPT_NSEC 41
int NL[MWSPT_NSEC] = { 1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,
3,1,3,1,2,1 };
double NUM[MWSPT_NSEC][3] = {
  {
     0.3416221864767,                 0,                 0 
  },
  {
                   1,                 2,                 1 
  },
  {
     0.3180955154747,                 0,                 0 
  },
  {
                   1,                 2,                 1 
  },......
MWSPT_NSEC為濾波器階數,具體的節數在頭文件開頭的注釋中
NL[MWSPT_NSEC]這個數組定義了NUM[MWSPT_NSEC][3]數組每一行的有用數據個數(可以不用)

在NUM[MWSPT_NSEC][3]數組(分子參數)奇數行第一項都為增益項,偶數行為3個系數,分別為b0,b1,b2。

由此可以找出規律,定義K為目前所在的階數,p為數組的首指針,則,每一節的增益項為(p+6*K),第一個系數為(p+3+6*K),

第二個系數為(p+3+6*K+1),第三個系數為(p+3+6*K+2)。


C++編程實現

在軟件設計的過程中,每個二階節的延遲變量只取 和 , 作為中間變量在過程中直接賦給 。這是因為對於下一個輸入數據n+1的延遲變量即為上一個輸入數據的 和 ,采用這種方式進行設計,可以節省寄存器的空間。

為了提高處理速度,程序中需要使用指針進行參數傳遞,特別注意二維數組的首地址傳遞方式為&a[0][0]->double* a。

 

濾波函數

double iir(double *a, double *b,double* w, double xin, int N_IIR)

{

    int k;

double temp = xin;

 

for (k = 0; k<N_IIR; k++)

{

   

    *(w+k*3) = temp - *(a + 3+6 * k  + 1) *(*(w + k * 3+1)) - *(a + 3 + 6 * k + 2) *(*(w + k * 3+2));

         //這里temp為本二階節的輸入,也是上一個二階節的輸出

         temp = *(b + 3 + 6 * k )* (*(w + k * 3)) + *(b + 3 + 6 * k + 1) * (*(w + k * 3+1)) + *(b + 3+6 * k + 2)* (*(w + k * 3+2));

//這里temp為本二階節的輸出,也是下一個二階節的輸入

 

        

         *(w + k * 3 + 2) = *(w + k * 3 + 1);

         *(w + k * 3 + 1) = *(w + k * 3);

        

         temp = temp*(*(b + 6 * k));//放大倍數,穩定信號

}

return temp;

}


實際測試

測試Fpass為10K,Fstop為12K的低通濾波器

在程序中輸入三個頻率為2K,11K,20K的信號,理論上2k完全通過,11k部分衰減,20K完全濾除。

上圖為原信號,下圖為濾波后信號。

實際測試發現符合設計要求,而且在過渡帶信號也基本完全衰減。

測試用C++程序
void main()
{
    const int N = 100;
    int i,j;
    double xn[N];
    double w[20][3];
    double yn[N];

    for (i = 0; i < 20; i++)//初始化
    {
        for (j = 0; j < 3; j++)
            w[i][j] = 0;
    }

    for (i = 0; i < N; i++)
    {
        xn[i] = sin(2 * 3.1416 * 20 / 50 * i)+ sin(2 * 3.1416 * 2 / 50 * i)+ sin(2 * 3.1416 * 11 / 50 * i);

        yn[i]=iir(&DEN[0][0], &NUM[0][0], &w[0][0],xn[i], 20);
    
    }

    ofstream SaveFile_a("xn.txt");
    for (i = 0; i<N; i++)
        SaveFile_a << " " << xn[i] << endl;
    SaveFile_a.close();

    ofstream SaveFile_b("yn.txt");
    for (i = 0; i<N; i++)
        SaveFile_b << " " << yn[i] << endl;
    SaveFile_a.close();
}

分析用Matlab程序
xn1=fopen('xn.txt','r');
[xn,count]=fscanf(xn1,'%f');
fclose(xn1);

N = length(xn);%求取抽樣點數
xn_f = fft(xn);%對信號進行傅里葉變換
xn_f=abs(xn_f(1:N/2));
f = 50000/N*(0:N/2-1);

subplot(211);
stem(f,abs(xn_f));
xlabel('Frequency / (s)');ylabel('Amplitude');

title('原信號頻譜');
grid;

yn1=fopen('yn.txt','r');
[yn,count]=fscanf(yn1,'%f');
fclose(yn1);

yn_f = fft(yn);%對信號進行傅里葉變換
yn_f=abs(yn_f(1:N/2));
subplot(212);
stem(f,abs(yn_f));
xlabel('Frequency / (s)');ylabel('Amplitude');
title('濾波后信號頻譜');
grid;

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM