基於FPGA的16階級聯型iir帶通濾波器實現


警告

此文章將耗費你成噸的流量,請wifi下閱讀,造成的流量浪費本人不承擔任何責任。初版源代碼獲取(請勿用作他用,僅供學習):https://gitee.com/kingstacker/iir.git

若有問題可以聯系我郵箱:kingstacker_work@163.com

版權所有,轉載請注明出處。

感謝

感謝杜勇老師的書籍:

感謝杜勇老師不厭其煩的答復我的郵件垂詢。

感謝自己,編代碼調試眼睛快瞎了。。。。。

 

前言

這個課程設計做過一年多了,知識什么的差不多都忘記了,最近去面試直接就問項目,而且問得挺細,一臉懵逼,眼淚掉下來,

簡歷上寫的項目你自己一定要說的明白

簡歷上寫的項目你自己一定要說的明白

簡歷上寫的項目你自己一定要說的明白

所以,又復習了一遍,當然更為嫻熟也添加了新的東西。

基礎知識:

什么叫濾波器?

簡單的說,就像篩米,留下你需要的米,濾掉不需要的米頭。過濾的功能。

什么叫數字濾波器?

用數字芯片做的濾波器,而不是rc搭的,輸入是離散的序列,輸出也是離散的序列;

快速了解時域頻域:

https://zhuanlan.zhihu.com/p/19763358?from=singlemessage&isappinstalled=1

什么叫時域?

信號隨時間的變化。

什么叫頻域?

 

 

 曾經有個通俗的解釋是:彈鋼琴,琴鍵1234等表示的就是頻域,產生的各種音樂就是時域,你以為的萬變其實是永恆的不變。

什么叫fir與iir濾波器?

FIR(Finite Impulse Response)濾波器:有限長單位沖激響應濾波器,又稱為非遞歸型濾波器,是數字信號處理系統中最基本的元件,它可以在保證任意幅頻特性的同時具有嚴格的線性相頻特性,同時其單位抽樣響應是有限長的,因而濾波器是穩定的系統。

無限脈沖響應。遞歸濾波器,也就是IIR數字濾波器,顧名思義,具有反饋。 

fir和iir有啥異同(important)?

 根據沖激響應的不同,將數字濾波器分為有限沖激響應(FIR)濾波器和無限沖激響應(IIR)濾波器。對於FIR濾波器,沖激響應在有限時間內衰減為零,其輸出僅取決於當前和過去的輸入信號值。對於IIR濾波器,沖激響應理論上應會無限持續,其輸出不僅取決於當前和過去的輸入信號值,也取決於過去的信號輸出值。

1. 在相同技術指標下,IIR濾波器由於存在着輸出對輸入的反饋,因而可用比FIR濾波器較少的階數來滿足指標的要求,這樣一來所用的存儲單元少,運算次數少,較為經濟。例如用頻率抽樣法設計阻帶衰減為-20db的FIR濾波器,其階數要33階才能達到,而如果用雙線性變換法設計只需4-5階的切貝雪夫濾波器,即可達到指標要求,所以FIR濾波器的階數要高5-10倍左右。

2. FIR濾波器可得到嚴格的線性相位,而IIR濾波器則做不到這一點,IIR濾波器選擇性愈好,則相位的非線性愈嚴重,困而,如果IIR濾波器要得到線性相位,又要滿足幅度濾波的技術要求,必須加全通網絡進行相位校正,這同樣會大大增加濾波器的階數,從這一點上看,FIR濾波器又優於IIR濾波器。

3. FIR濾波器主要采用非遞歸結構,因而從理論上到實際的有限精度的運算中,都是穩定的。有限精度運算誤差也較小,IIR濾波器必須采用遞歸的結構,極點必須在Z平面單位圓內,才能穩定,這種結構,運算中的四舍五入處理,有時會引起寄生振盪。

4. FIR濾波器,由於沖激響應是有限長的,因而可以用快速傅里葉變換算法,這樣運算速度可以快得多,IIR濾波器則不能這樣運算。

5. 從設計上看,IIR濾波器可以利用模擬濾波器設計的現成閉合公式、數據和表格,因而計算工作量較小,對計算工具要求不高。FIR濾波器則一般沒有現成的設計公式,窗函數法只給出窗函數的計算工式,但計算通帶、阻帶衰衰減仍無顯示表達式。一般FIR濾波器設計只有計算機程序可資利用,因而要借助於計算機。

6. IIR濾波器主要是設計規格化的、頻率特性為分段常數的標准低通、高通、帶通、帶阻、全通濾波器,而FIR濾波器則要靈活得多,例如頻率抽樣設計法,可適應各種幅度特性的要求,因而FIR濾波器則要靈活得多,例如頻率器可設計出理想正交變換器、理想微分器、線性調頻器等各種網絡,適應性較廣。而且,目前已有許多FIR濾波器的計算機程序可供使用。

什么叫定點數?

計算機中采用的一種數的表示方法。參與運算的數的小數點位置固定不變。

什么叫濾波器的零點極點?

濾波器可以看成是一個信號處理的系統,其輸入輸出之間存在一定的關系,這種關系無論在時域還是頻域都可以用數學表達式來表示.而這數學表達式又是分子分母都是多項式的表達式(稱為傳輸函數),這樣滿足使傳輸函數的分子為零的是零點,滿足使傳輸函數分母為零的就是其極點.

iir濾波器的種類:很多啊,直接一型,直接二型,級聯型,並聯型。

對於matlab的fdatool工具中二階節默認結構為:

對於這個結構用圖表示為:

差分方程表示為:

零極點表示為:零點就是差分方程的前面三項,極點就是后面兩項。用FPGA實現主要就是實現濾波器的差分方程。

 

流程:

任務要求:

16階二階級聯IIR數字濾波器設計,16bit有符號整數連續輸入,采樣率80khz,通帶頻率1k-8khz。系數為16bit有符號整數。

1.系數產生:通過matlab中的fdatool軟件生成所需系數。(當然可以用各種函數生成,太難工科生表示要陣亡了,還是默默用fdatooll吧)

把需求放入fdatool中:生成的架構就是直接二型二階節結構。

 

 零極點圖:

未量化的系數:

未量化的系數導出:生成一個c文件。

 

那么問題來了,這個c文件中的內容是啥子意思呢,一開始我也是一臉懵逼,而且網上的資料少之又少,文件如下所示,含義已注釋:

  1 /*
  2  * Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool
  3  *
  4  * Generated by MATLAB(R) 7.8 and the Signal Processing Toolbox 6.11.
  5  *
  6  * Generated on: 22-Sep-2017 20:23:35
  7  *
  8  */
  9 
 10 /*
 11  * Discrete-Time IIR Filter (real)
 12  * -------------------------------
 13  * Filter Structure    : Direct-Form II, Second-Order Sections
 14  * Number of Sections  : 8
 15  * Stable              : Yes
 16  * Linear Phase        : No
 17  */
 18 
 19 /* General type conversion for MATLAB generated C-code  */
 20 #include "tmwtypes.h"
 21 /* 
 22  * Expected path to tmwtypes.h 
 23  * D:\workfile\Matlab2009\extern\include\tmwtypes.h 
 24  */
 25 /*
 26  * Warning - Filter coefficients were truncated to fit specified data type.  
 27  *   The resulting response may not match generated theoretical response.
 28  *   Use the Filter Design & Analysis Tool to design accurate
 29  *   single-precision filter coefficients.
 30  */
 31 #define MWSPT_NSEC 17
 32 const int NL[MWSPT_NSEC] = { 1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1 };
 33 //上面1313的玩意表示下面這個數組哪個項有效,1則表示第一項有效,3表示都有效;
 34 const real32_T NUM[MWSPT_NSEC][3] = {
 35   {
 36      0.1001105756,              0,              0  //第一個二階節的增益;
 37   },
 38   {
 39                 1,   0.7806397676,              1 //第一個二階節的零點;b0,b1,b2;
 40   },
 41   {
 42      0.1001105756,              0,              0 //第二個二階節的增益;
 43   },
 44   {
 45                 1,   -1.999714136,              1 //第二個二階節的零點;b0,b1,b2;
 46   },
 47   {
 48      0.3725369573,              0,              0 //以下就是類似的了;
 49   },
 50   {
 51                 1,  -0.9795594215,              1 
 52   },
 53   {
 54      0.3725369573,              0,              0 
 55   },
 56   {
 57                 1,    -1.99809742,              1 
 58   },
 59   {
 60      0.6452683806,              0,              0 
 61   },
 62   {
 63                 1,   -1.352879047,              1 
 64   },
 65   {
 66      0.6452683806,              0,              0 
 67   },
 68   {
 69                 1,   -1.996625185,              1 
 70   },
 71   {
 72      0.7896357179,              0,              0 
 73   },
 74   {
 75                 1,   -1.448690891,              1 
 76   },
 77   {
 78      0.7896357179,              0,              0 
 79   },
 80   {
 81                 1,   -1.995926261,              1 
 82   },
 83   {
 84                 1,              0,              0    //總的增益為1,上面8個分增益相乘最終為1;
 85   }
 86 };
 87 const int DL[MWSPT_NSEC] = { 1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1 };
 88 const real32_T DEN[MWSPT_NSEC][3] = {
 89   {
 90                 1,              0,              0  //忽略項;
 91   },
 92   {
 93                 1,   -1.765431523,   0.8537048697 //第一個二階節的極點;a0,a1,a2;
 94   },
 95   {
 96                 1,              0,              0 
 97   },
 98   {
 99                 1,   -1.893844962,    0.919323802  //以下類似;
100   },
101   {
102                 1,              0,              0 
103   },
104   {
105                 1,   -1.666594863,    0.877212882 
106   },
107   {
108                 1,              0,              0 
109   },
110   {
111                 1,   -1.959967136,   0.9707458019 
112   },
113   {
114                 1,              0,              0 
115   },
116   {
117                 1,   -1.614711642,   0.9346644878 
118   },
119   {
120                 1,              0,              0 
121   },
122   {
123                 1,   -1.982463837,   0.9896451831 
124   },
125   {
126                 1,              0,              0 
127   },
128   {
129                 1,   -1.603200555,   0.9806866646 
130   },
131   {
132                 1,              0,              0 
133   },
134   {
135                 1,   -1.991223216,   0.9973948002 
136   },
137   {
138                 1,              0,              0 
139   }
140 };

 

系數量化選項:系數量化你可以自己量化也可以讓軟件量化,不過它量化出來的數據零點並不是乘完增益后再進行量化的。最好還是乘完增益后再量化,所以還是自己用excel慢慢量化吧,眼淚掉下來。

 未量化excel表:

excel中計算單元格方便到不行:零點乘完增益放大16384;極點直接放大16384;下圖gain請無視。

新的b0=b0*gain1*16384;新的a0=a0*16384;放大16384倍方便FPGA實現除法截位。

2.編碼實現:

先看一下16階iir濾波器架構:級聯8個二階節。

一個二階節:

現在就可以編碼實現它了,這是第一版代碼,尚未優化,仿真ok,不要邏輯綜合,會占用成噸的資源。

由於技術垃圾,不做十分精確輸出位控制,輸出都為16bit數據。

兩個n位的加法結果需要n+1位;兩個n位的乘法結果需要2n位。

matalb生成modelsim仿真文件向量:

生成1500hz,采樣80khz波形向量文件。生成其他hz的波形文件類似。

 1 f1=1500;   %頻率1500hz;
 2 Fs=80000;  %采樣80khz;
 3 N=16;        %16bit量化;
 4 t=0:1/Fs:0.01;  %采樣時長0.01 5 c2=2*pi*f1*t;
 6 s2=sin(c2);  %正弦波產生;
 7 s2=s2/max(abs(s2));
 8 Q_s=round(s2*(2^(N-1)-1));
 9 plot(t,s2,'r*-');   %畫圖;
10 
11 fid=fopen('D:\data\data_1500\data_1500.txt','w');    %采樣點保存為10進制;
12 fprintf(fid,'%8d\r\n',s2);
13 fprintf(fid,';'); 
14 fclose(fid);
15 
16 fid=fopen('D:\data\data_1500\data_1500_B.txt','w'); %采樣點保存為2進制;
17 for i=1:length(Q_s)
18     B_s=dec2bin(Q_s(i)+(Q_s(i)<0)*2^N,N)
19     for j=1:N
20        if B_s(j)=='1'
21            tb=1;
22        else
23            tb=0;
24        end
25        fprintf(fid,'%d',tb);  
26     end
27     fprintf(fid,'\r\n');
28 end
29 fprintf(fid,';'); 
30 fclose(fid);

 

仿真測試:

對600hz正弦波濾波結果:600hz波形被濾除。

 

 對5000hz正弦波濾波結果:5000hz波形通過。

 

 

 對9000hz波形濾波結果:開始有點點迷之振盪,基本濾除9000hz的波。

 

最開始的結果經過多久出來到out?(特么上次面試還問這個了,十臉懵逼,根本沒注意這啊。。。emmm很氣)

可以看到是復位拉高后的9個時鍾周期后yout數據產生,因為流水線啊,emmm。

 初版代碼綜合上板子:通過rom輸出5khz的數據。

 

所以優化很重要,這是未優化版本。

signaltapII抓下波:

 

優化版以及未優化版比較:只包含iir部分,不含pll以及rom。系統時鍾跟采樣時鍾一樣,80khz。

未優化版:直接采用*(乘)的方式。

 

優化版:采用內置乘法器,以及采用移位相加的方法。資源少的可憐啊,一共才30個9bit乘法器。。。。,若再增加乘法器,le使用量又會往上漲。未來優化方向:提高時鍾頻率,復用乘法器。

 

 

其他:

怎么優雅的分解系數用來移位相加:

直接寫了個c程序,來看看效果:

c源代碼:看看就好啦,很久沒寫c,完全沒有代碼style了emmm。

 1 #include <stdio.h>
 2 #include <math.h>
 3 int main(void)
 4 {
 5     int coefficient;
 6     int sum;
 7     int sum1;
 8     int mul;
 9     int mul1;
10     int j;
11     int i;
12     int k=0;
13     int m;
14     int n=0;
15     int cha;
16     printf("All rights by kingstacker!\n");
17     begin:
18     printf("Pelese input the coefficient:");
19     scanf("%d",&coefficient);
20     printf("%d=",coefficient);
21     sum = coefficient;
22     sum1 = coefficient;
23     for (m=15;m>=0;m--)   //add;
24     {
25         mul1=pow(2,m);
26         if (sum1 >= mul1)
27         {
28              sum1 = sum1 -mul1;
29              n=n+1;
30              printf("+%d(2^%d)",mul1,m );
31             
32         }
33         
34     }
35     printf("\nIf add,use %d add source !\n",n-1 );
36     //sub;
37     for (j=0;j<=15;j++)
38     {
39         mul=pow(2,j);
40         if (mul >= sum)
41         {
42             goto this;
43         }
44     }
45     this:
46     cha = mul - sum;
47     printf("%d=%d(2^%d)",sum,mul,j );
48     for (i=j;i>=0;i--)
49     {
50        mul1 = pow(2,i);
51        if (cha >= mul1)
52        {
53            cha = cha - mul1;
54            k=k+1;
55            printf("-%d(2^%d)",mul1,i );  
56        }
57     }
58     printf("\nIf sub,use %d add source !\n",k );
59     //result;
60     if((n-1) <= k)
61     {
62         printf("\nadd is better!\n");
63     }
64     else
65     {
66         printf("\nsub is better!\n");
67     }
68     k=0;
69     n=0;
70     goto begin;
71     printf("Thanks for you use!bye!\n");
72     
73 }

 

以上。

 


免責聲明!

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



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