轉載自 http://blog.csdn.net/liyuanbhu/article/details/38849897html
最近在寫的一個程序須要用到IIR濾波器,並且IIR濾波器的係數須要動態調整。所以就花了點時間研究IIR 濾波器的實現。python
之前用到的IIR濾波器的參數都是事先肯定好的,有個網站,只要把濾波器的參數特性輸進去,直接就能生成須要的C代碼。數組
http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html函數
一直都偷懶直接用這個網站的結果,因此手上也沒積累什麼有用的代碼。此次就須要本身從頭作起。測試
我面臨的問題有兩個:網站
1. 根據濾波器的參數(濾波器的類型、截止頻率、濾波器的階數等),計算出濾波器對應的差分方程的係數。spa
2. 利用獲得的差分方程的係數構造一個能夠工做的濾波器。.net
其中第一個問題,對於不一樣類型的濾波器,好比Butterworth型、Bessel型等,濾波器係數的計算方法都不一樣。這部分工做我還沒作徹底,等我把常見的幾種濾波器類型的係數計算方法都實現後再來寫一篇文章。htm
這裏就先寫寫第二個問題。IIR 濾波器對應的差分方程爲:blog
相應的系統函數爲:
這裏默認a[0] = 1。實際上,總能夠經過調整a[k] 與 b[k] 的值使得a[0] = 1,因此這個條件時總能知足的。
按照奧本海默寫的《離散時間信號處理》上面的介紹,IIR 濾波器有兩種基本的實現形式,分別成爲直接I型和直接II型。我分別寫了兩個類,實現這兩種形式。
直接I型
- class IIR_I
- {
- private:
- double *m_pNum;
- double *m_pDen;
- double *m_px;
- double *m_py;
- int m_num_order;
- int m_den_order;
- public:
- IIR_I();
- void reset();
- void setPara(double num[], int num_order, double den[], int den_order);
- void resp(double data_in[], int m, double data_out[], int n);
- double filter(double data);
- void filter(double data[], int len);
- void filter(double data_in[], double data_out[], int len);
- };
其中 m_px 存放x[n-k] 的值(m_px[0]存放x[n-0]、 m_px[1] 存放x[n-1],以此類推),m_py存放y[n-k] 的值(m_py[0]存放y[n-0]、 m_py[1] 存放y[n-1],以此類推)。
三個filter函數用來作實際的濾波操做。在這以前,須要用setPara函數初始化濾波器的係數。
下面是實現代碼:
除此以外,還提供了個resp函數,這個函數能夠計算濾波器的時域響應。而且不要求data_in與data_out 的數組長度相同。默認data_in[0] 以前的數據全爲0,data_in[M-1]以後的數字所有爲data_in[M-1]。所以,用這個函數計算階躍響應輸入數據只須要提供一個數據點就好了。而且這個函數不改變濾波器的內部狀態。
- void IIR_I::resp(double data_in[], int M, double data_out[], int N)
- {
- int i, k, il;
- for(k = 0; k < N; k++)
- {
- data_out[k] = 0.0;
- for(i = 0; i <= m_num_order; i++)
- {
- if( k - i >= 0)
- {
- il = ((k - i) < M) ? (k - i) : (M - 1);
- data_out[k] = data_out[k] + m_pNum[i] * data_in[il];
- }
- }
- for(i = 1; i <= m_den_order; i++)
- {
- if( k - i >= 0)
- {
- data_out[k] = data_out[k] - m_pDen[i] * data_out[k - i];
- }
- }
- }
- }
直接II型
- class IIR_II
- {
- public:
- IIR_II();
- void reset();
- void setPara(double num[], int num_order, double den[], int den_order);
- void resp(double data_in[], int m, double data_out[], int n);
- double filter(double data);
- void filter(double data[], int len);
- void filter(double data_in[], double data_out[], int len);
- protected:
- private:
- double *m_pNum;
- double *m_pDen;
- double *m_pW;
- int m_num_order;
- int m_den_order;
- int m_N;
- };
-
- class IIR_BODE
- {
- private:
- double *m_pNum;
- double *m_pDen;
- int m_num_order;
- int m_den_order;
- complex<double> poly_val(double p[], int order, double omega);
- public:
- IIR_BODE();
- void setPara(double num[], int num_order, double den[], int den_order);
- complex<double> bode(double omega);
- void bode(double omega[], int n, complex<double> resp[]);
- };
直接II型實現中所需的存儲單元少了不少。另外,這兩種實現的外部接口是徹底相同的。
- IIR_II::IIR_II()
- {
-
- m_pNum = NULL;
- m_pDen = NULL;
- m_pW = NULL;
- m_num_order = -1;
- m_den_order = -1;
- m_N = 0;
- };
-
- void IIR_II::reset()
- {
- for(int i = 0; i < m_N; i++)
- {
- m_pW[i] = 0.0;
- }
- }
- void IIR_II::setPara(double num[], int num_order, double den[], int den_order)
- {
- delete[] m_pNum;
- delete[] m_pDen;
- delete[] m_pW;
- m_num_order = num_order;
- m_den_order = den_order;
- m_N = max(num_order, den_order) + 1;
- m_pNum = new double[m_N];
- m_pDen = new double[m_N];
- m_pW = new double[m_N];
- for(int i = 0; i < m_N; i++)
- {
- m_pNum[i] = 0.0;
- m_pDen[i] = 0.0;
- m_pW[i] = 0.0;
- }
- for(int i = 0; i <= num_order; i++)
- {
- m_pNum[i] = num[i];
- }
- for(int i = 0; i <= den_order; i++)
- {
- m_pDen[i] = den[i];
- }
- }
- void IIR_II::resp(double data_in[], int M, double data_out[], int N)
- {
- int i, k, il;
- for(k = 0; k < N; k++)
- {
- data_out[k] = 0.0;
- for(i = 0; i <= m_num_order; i++)
- {
- if( k - i >= 0)
- {
- il = ((k - i) < M) ? (k - i) : (M - 1);
- data_out[k] = data_out[k] + m_pNum[i] * data_in[il];
- }
- }
- for(i = 1; i <= m_den_order; i++)
- {
- if( k - i >= 0)
- {
- data_out[k] = data_out[k] - m_pDen[i] * data_out[k - i];
- }
- }
- }
- }
- double IIR_II::filter(double data)
- {
- m_pW[0] = data;
- for(int i = 1; i <= m_den_order; i++)
- {
- m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i];
- }
- data = 0.0;
- for(int i = 0; i <= m_num_order; i++)
- {
- data = data + m_pNum[i] * m_pW[i];
- }
- for(int i = m_N - 1; i >= 1; i--)
- {
- m_pW[i] = m_pW[i-1];
- }
- return data;
- }
- void IIR_II::filter(double data[], int len)
- {
- int i, k;
- for(k = 0; k < len; k++)
- {
- m_pW[0] = data[k];
- for(i = 1; i <= m_den_order; i++)
- {
- m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i];
- }
- data[k] = 0.0;
- for(i = 0; i <= m_num_order; i++)
- {
- data[k] = data[k] + m_pNum[i] * m_pW[i];
- }
-
- for(i = m_N - 1; i >= 1; i--)
- {
- m_pW[i] = m_pW[i-1];
- }
- }
- }
- void IIR_II::filter(double data_in[], double data_out[], int len)
- {
- int i, k;
- for(k = 0; k < len; k++)
- {
- m_pW[0] = data_in[k];
- for(i = 1; i <= m_den_order; i++)
- {
- m_pW[0] = m_pW[0] - m_pDen[i] * m_pW[i];
- }
- data_out[k] = 0.0;
- for(i = 0; i <= m_num_order; i++)
- {
- data_out[k] = data_out[k] + m_pNum[i] * m_pW[i];
- }
-
- for(i = m_N - 1; i >= 1; i--)
- {
- m_pW[i] = m_pW[i-1];
- }
- }
- }
測試
下面是幾個測試例子,首先計算一個4階切比雪夫低通濾波器的階躍響應。
- void resp_test(void)
- {
- double b[5] = {0.001836, 0.007344, 0.011016, 0.007344, 0.001836};
- double a[5] = {1.0, -3.0544, 3.8291, -2.2925, 0.55075};
- double x[2] = {1.0, 1.0};
- double y[100];
-
- IIR_II filter;
- filter.setPara(b, 4, a, 4);
- filter.resp(x, 2, y, 100);
-
- for(int i= 0; i< 100; i++)
- {
- cout << y[i] << endl;
- }
- }
獲得的結果以下:
一樣是這個濾波器,計算輸入信號爲 delta 函數時的結果。
- void filter_test(void)
- {
- double b[5] = {0.001836, 0.007344, 0.011016, 0.007344, 0.001836};
- double a[5] = {1.0, -3.0544, 3.8291, -2.2925, 0.55075};
- double x[100], y[100];
- int len = 100;
- IIR_I filter;
-
- filter.setPara(b, 4, a, 4);
-
- for (int i = 0; i < len; i++)
- {
- x[i] = 0.0;
- y[i] = 0.0;
- }
- x[0] = 1.0;
- filter.filter(x, y, 100);
- filter.reset();
- filter.filter(x, 100);
-
- for (int i = 0; i < len; i++)
- {
- cout << x[i] <<", " << y[i]<< endl;
- }
- }
獲得的結果以下: