2.14 FIR濾波器設計-明德揚至簡設計法原理與應用
? ? 本連載學習效果:不僅看能懂代碼,還能知道每一行代碼怎么寫,怎么設計。
本文的文檔編號:000600000025
需要看對應的視頻,請點擊視頻編號:002700000452
1、本文檔講述FPGA產生兩路正弦波數據,一路直接由DA輸出,一路經過FIR處理之后輸出,然后傳到示波器進行觀察,從而了解FIR濾波器的效果
2、801開發(fā)板使用
第十四章? FIR濾波器設計
1?項目背景
1.1?FIR和IIR濾波器
? ? FIR(Finite Impulse Response)Filter:有限沖激響應濾波器,又稱為非遞歸線性濾波器。
? ? FIR濾波器,顧名思義,其脈沖響應由有限個采樣值構成。長度(抽頭數)為N、階數為N?1的FIR系統(tǒng)的轉移函數、差分方程和單位沖激響應分別如下列三式所示。

?
圖?510
? ? IIR(Infinite Impulse Response)Filter:無限沖激響應濾波器,又稱為遞歸線性濾波器。
? ? FIR相對與IIR來說,具有如下的優(yōu)點:
可以具備線性相位特性
線性相位的概念:?如果濾波器的N個實值系數為對稱或者反對稱結構,該濾波器具有線性相位。?W(n)=±W(N?1?n)W(n)=±W(N?1?n)
線性相位的特性:通過線性相位濾波器的信號的所有頻率部分具有相同的延遲量。?
易于設計
但FIR也有自身的缺點:同樣指標的濾波器,FIR需要更多的參數,即實現時消耗更多的計算單元,產生更大的延遲。
1.2?FIR濾波器的原理
信號通過一個FIR濾波器其實就是信號與FIR濾波器的系數進行卷積(即乘累加)的過程。我們以一個簡單信號模型為例,了解一下FIR波形器的原理。
現在有三組信號,分別是:
信號1:低頻信號,即在時域上變化慢的信號,其輸入先后為1 1 1 1 2 2 2 2。
信號2:直流信號,其輸入先后為1 1 1 1 1 1 1?。
信號3:高頻信號,即在時域上變化快的信號,其輸入先后為1 2 1 2 1 2 1 2?。
簡單的濾波器模型
低通濾波器:1 1
?信號1與低通濾波器進行卷積運算,其結果再除以2,得到如下數據:1 1 1 1.5 2 2 2。可以看到,低頻信號經過低通濾波器后,各個點仍然保持了其形狀,而且在1變成2時,還變平緩了。
信號2與低通濾波器進行卷積運算,其結果再除以2,得到如下數據:1 1 1 1 1 1 1??梢钥吹?,直流信號與輸入的信號完成相同。
信號3與低通濾波器進行卷積運算,其結果再除以2,得到如下數據:1.5 1.5 1.5 1.5 1.5 1.5 1.5。可以看到,高頻信號經過低通濾波器后,已經完成消去了形狀,變成了直流信號。
?再考慮另一種濾波器模型,高通濾波器:1 -1
信號1與高通濾波器進行卷積運算,其結果再除以2,得到如下數據:0 0 0 -0.5 0 0 0??梢钥吹剑皖l信號經過高通濾波器后,信號變化基本上消失。
信號2與低通濾波器進行卷積運算,其結果再除以2,得到如下數據:0 0 0 0 0 0 0??梢钥吹剑绷餍盘柸匀皇菦]有變化。
信號3與低通濾波器進行卷積運算,其結果再除以2,得到如下數據:-0.5 0.5 -0.5 0.5 -0.5 0.5 -0.5 0.5??梢钥吹?,高頻信號已經仍然保持了變化的形狀。
由這兩個例子可以看出,FIR濾波器其實就是信號與FIR濾波器的系數進行卷積(即乘累加)的過程。通過調整濾波器系數、抽頭個數,就可實現低通、高通、帶通等濾波器。
1.3?FIR濾波器的設計
1.3.1?matlab產生濾波器系數
? ? 打開matlab在其命令窗口輸入fdatool?按下回車

?
? ? 調出FIR濾波器的設計界面

圖?511
? 在波形設計界面中,我們重要關注以下選項。
?Response Type:選擇可以選擇濾波器的類型,可選擇:lowpass低通濾波器、Highpass高通濾波器、bandpass帶通濾波器、bandstop帶阻濾波器。
?Fs(采樣頻率):
?Fstop?:信號截止頻率
?Fpass:
Filter Order:用來設置濾波器的抽頭個數??梢栽趕pecify order中輸入個數,也可以選擇Minimum order,讓系統(tǒng)計算滿足要求的前提下的最小抽頭個數。點擊Design Filter,就可以計算出抽頭系數。產生系數后點擊file?菜單里的Export?將系數保存到工作區(qū)

?
圖?512
? ? 點擊export

?
圖?513
? ? 點擊之后打開工作區(qū)里的Num

圖?514
? ? 而后將下圖第一列的數據復制粘貼到txt文件中

?
圖?515
? ? 注意復制后需在兩個系數間插入逗號(英文輸入狀態(tài)下的的逗號)

圖?516
? ? 這樣就得到濾波器的系數了。
1.3.2?FPGA生成FIR IP核
? ? 打開工程后,在IP catalog這一界面中選擇DSP下一目錄中選擇Filter?在選擇選擇?FIR II

?
圖?517
? ? 首先在Fitter這一界面做如下操作

?
圖?518
Filter Type
? ? Interpolation Factor:
? ? Decimation Factor:
? ? Max Number of channels:
? ? Clock rate:填寫本IP核的工作時鐘頻率。
? ? clock slack:
? ? Input sample rate?(msps):采樣率
? ? 點擊coefficients,進入coefficients界面。
? ? 這一界面點擊import from file?,彈出一下界面,找出我們之前用matlab生成的系數文件,點擊import,導入成功后可以看到下圖的?frequency response界面的波形發(fā)生變化。

圖?519
? ? 在coefficient界面,還可以設置系數的格式、數據位寬等。

圖?520
? ? 其它選項不改按默認的來點擊finish即可。
? ? 以上就是生成?FIR濾波器的主要步驟。
2?設計目標
? ? 本次案例將使用到采樣率大于100M的雙通道的示波器。將示波器的兩個通道,分別與FPGA的DA通道1和DA通道2相連,觀察兩路DA的輸出。其連接示意如下圖所示。

圖?521
本案例是FPGA內部產生正弦信號,這個正弦信號一路輸出給DA通道1,另一路經過FIR濾波器后,輸出給DA通道2。

圖?522
正弦信號的頻率受開發(fā)板上的3個撥碼開關控制,用3位信號key表示,一共可以產生8種頻率。
? ? 正弦信號的頻率?約等于:?100KHz * (key+1)。
? ? 例如,當key等于0時,產生約100KHz的正弦信號;
? ? 當key等于1時,產生約200KHz的正弦波;
? ? 當key等于7時,產生約800KHz的正弦波。
FIR濾波器是低通濾波器,其截止頻率是500KHz,這樣原則上超過500KHz的信號就會被濾除。濾波器的輸出給通道2。
下面是示波器的顯示效果,其中黃色是通道1輸出的信號(上面的波形),下面藍色是通道2的輸出信號(下面的波形)。
下圖是100KHz的信號圖。

100KHz的信號圖
? ? 下圖是200KHz的信號圖。?

200KHz的信號圖
下圖是300KHz的信號圖。

300KHz的信號圖
下圖是400KHz的信號圖,可以看到已經衰減了。?

400KHz的信號圖
下圖是500KHz的信號圖,可以看到已經衰減的很小了。?

500KHz的信號圖
下圖是600KHz的信號圖,可以看到通道2已經沒有波形。?

600KHz的信號圖
下圖是700KHz的信號圖,可以看到通道2已經沒有波形。

700KHz的信號圖
下圖是800KHz的信號圖,可以看到通道2已經沒有波形。

800KHz的信號圖
3?設計實現
3.1?頂層接口
?新建目錄:D:mdy_bookir_prj。在該目錄中,新建一個名為fir_prj.v的文件,并用GVIM打開,開始編寫代碼。
?我們要實現的功能,概括起來就是FPGA產生控制AD9709,讓其中的通道A未濾波的正弦信號,讓通道B輸出濾波后的正弦信號。為了控制AD9709的工作模式,就要控制AD9709的MODE、SLEEP管腳;為了控制通道A,就需要控制AD9729的CLK1、WRT1、DB7~0P1管腳;為了控制通道B,就需要控制AD9729的CLK2、WRT2、DB7~0P2管腳。根據設計目標的要求,? ? ? 整個工程需要以下信號:
? ? 1.?使用clk連接到晶振,表示50M時鐘的輸入。
? ? 2.?使用rst_n連接到按鍵,表示復位信號。
? ? 3.?使用3位信號key,表示三位撥碼開關。
? ? 4.?使用dac_mode信號連接到AD9709的MODE管腳,用來控制其工作模式。
? ? 5.?使用dac_sleep信號連接到AD9709的SLEEP管腳,用來控制其睡眠模式。
? ? 6.?使用dac_clka信號連接到AD9709的CLK1管腳,用來控制通道A的時鐘。
? ? 7.?使用dac_wra信號連接到AD9709的WRT1管腳,用來控制通道A的寫使能。
? ? 8.?使用8位信號dac_da連接到AD9709的DB7~0P1管腳,用來控制通道A的寫數據。
? ? 9.?使用dac_clkb號連接到AD9709的CLK2腳,用來控制通道B時鐘。
? ? 10.?使用dac_wrb號連接到AD9709的WRT2腳,用來控制通道B使能。
? ? 11.?使用8位信號dac_db接到AD9709的DB7~0P2腳,用來控制通道B寫數據。
?綜上所述,我們這個工程需要11個信號,時鐘clk,復位rst_n,撥碼開關的輸入key,dac_mode、dac_sleep、dac_clka、dac_wra、dac_da、dac_clkb、dac_wrb和dac_db信號,其中dac_da和dac_db是8位信號,其他都是1位信號。下面表格表示了硬件電路圖的連接關系。

? ? 將module的名稱定義為fir_prj,代碼如下:

其中clk、rst_n是1位的輸入信號,dac_da和dac_db是8位的輸出信號,key是3位輸入信號,dac_mode,dac_clka,dac_wra,dac_sleep,dac_clkb,dac_wrb是一位輸出信號。

3.2?正弦信號設計
?假設產生的正弦信號命名為sin_data信號。sin_data是從表XX中選擇出來的值,該表一共有128個點。該表的產生方法,請看案例“信號發(fā)生器和DA轉換”一章的內容。

?很自然地定義一個7位的選擇信號addr。我們只要控制好addr,就能方便得到sin_data。因此可以寫出下面代碼。?

接下來是設計信號addr。
? ? addr是用來控制選擇數據的地址,通過控制addr的增加值,就能產生多種頻率的正弦波。
? ? 以頻率為100KHz的正弦信號為例。該正弦信號的周期是10000ns。本工程的工作時鐘? ? ? ?是?20ns,也就是10000/20 = 500個時鐘輸出一個正弦信號,也就是500個時鐘將上表的128個值輸出一遍。因此每個時鐘addr增加的值:128/500 = 0.256。
? ? 按同樣的分析方法,可以得到其他信號頻率的addr增加值,總結如下。
? ? 100KHz的正弦信號,每個時鐘addr增加:128/250 ?????= 0.256
? ? 200KHz的正弦信號,每個時鐘addr增加:128/250 ?????= 0.512
? ? 300KHz的正弦信號,每個時鐘addr增加:128/166.6667 = 0.7679
? ? 400KHz的正弦信號,每個時鐘addr增加:128/125 ?????= 1.024
? ? 500KHz的正弦信號,每個時鐘addr增加:128/100 ?????= 1.28 ?
? ? 600KHz的正弦信號,每個時鐘addr增加:128/83.3333 ?= 1.5358
? ? 700KHz的正弦信號,每個時鐘addr增加:128/71.4286 ?= 1.792
? ? 800KHz的正弦信號,每個時鐘addr增加:128/62.5 ?????= 2.048
由于addr是表示0~127的整數,而addr每次增加的值包含小數,而FPGA是沒有小數的。為此,我們將上面的小數乘以1024,然后取整,就變成了每次要增加的整數,結果保存到addr_tmp中。即:
? ? 100KHz的正弦信號,每個時鐘addr_tmp增加:0.256 ??*1024 = 262.144?≈?262
? ? 200KHz的正弦信號,每個時鐘addr_tmp增加:0.512 ??*1024 = 524.288?≈?524
? ? 300KHz的正弦信號,每個時鐘addr_tmp增加:0.7679 ?*1024 =786.3296?≈?786
? ? 400KHz的正弦信號,每個時鐘addr_tmp增加:1.024 ??*1024 =1028.576?≈?1029
? ? 500KHz的正弦信號,每個時鐘addr_tmp增加:1.28 ???*1024 =1310.72 ?≈?1311
? ? 600KHz的正弦信號,每個時鐘addr_tmp增加:1.5358 ?*1024 =1572.6592?≈1573
? ? 700KHz的正弦信號,每個時鐘addr_tmp增加:1.792 ??*1024 =1835.008?≈?1835
? ? 800KHz的正弦信號,每個時鐘addr_tmp增加:?2.048 ?*1024 =2097.152?≈?2097
? ? 而上面8種頻率信號,是由撥碼信號key控制的。因此,可以寫出addr_tmp的代碼。

上面的代碼中,addr_tmp是小數乘以1024后得到的,那么最終addr_tmp要除以1024,再賦給addr。除以1024,其實就是向右移10位。addr_tmp向各移10位后,保留7位結果賦給addr就夠了。所以addr_tmp位寬為17位。

3.3?FIR濾波器設計
3.3.1?matlab生成FIR系數
? ? ?打開matlab,在其命令窗口輸入fdatool?按下回車調出波形設計界面。?
? ? ?在波形設計界面中
? ? ?Response Type:案例要求濾波高于500KHz的信號,所以選擇lowpass低通濾波器
? ? ?Fstop: 截止頻率設為600KHz
? ? ?Fs:采樣頻率: 12.5MHz(12500Khz)

圖?526
? ? 其它選項默認點擊Design Filter
? ? 產生系數后點擊file?菜單里的Export?將系數保存的工作區(qū)

?
圖?527
? ? 點擊export

?
圖?528
? ? 點擊之后打開工作區(qū)里的Num

?
圖?529
? ? ?而后將下圖第一列的數據復制粘貼到txt文件中

?
圖?530
? ? 注意復制后需在兩個系數間插入逗號(英文輸入狀態(tài)下的的逗號)

圖?531
?
3.3.2?新建FPGA工程

?
圖?532
? ? 1.打開quartus,點擊File?在File菜單中選擇New Project Wizard....?。

?
圖?533
? ? 2.彈出Introduction界面選擇Next。

?
圖?534?
? ? 3.設置工程目錄,工程名,頂層模塊名
? ? 工程目錄設置為:D:mdy_bookir_prj
? ? 工程名:fir_prj
? ? 頂層模塊名:fir_prj
? ? 填寫完畢后,點擊next之后進入下一界面。

?
圖?535
? ? 工程類型界面,Project Type選擇Empty project,選擇空白工程。點Next進入下一個界面。

?
圖?536
? ? 4.在文件添加界面,不選擇任何文件。點擊Next,進入下一個界面。

?
圖?537
? ? 5.器件選擇界面。在Device family這一項之中選擇?Cyclone IV E;在下部的Available device?選擇EP4CE6F23C8。完成后直接點擊Finish。
3.3.3?FPGA生成FIR IP核

?
圖?538
? ? 建立工程后,在quartus中IP catalog這一界面中選擇DSP下一目錄中選擇Filter?再選擇?FIR II。

?
圖?539
? ? 點擊后進入此界面給新生成的fir濾波器ip核選擇如下路徑:D:mdy_bookir_prjmy_fir.v,IPvariation file name這一項選擇verilog。點擊OK后,進入FIR濾波器設置界面。

?
圖?540
? ? 在Fitter specification界面按如下設置:
? ? Filter Type:要選擇Single Rate,表示只采用一種采樣率。
? ? Clock Rate:因為我們工程使用的是50MHz時鐘,所以此處要填寫50MHz。
? ? Input Sample Rate (PSPS):這個是填采樣率。和matlab相匹配,因此要填12.5MHz。
? ? 其他參數默認。
? ? 然后點擊coefficients選項卡。

圖?541
? ? 單擊import from file?,在輸出的界面中,找出我們用MATLAB生成的系數文件:my_fir_coe.txt,點擊import導入。導入成功后可以看到下圖的?frequency response界面的波形發(fā)生變化。
? ? 在Coefficient Bit Width中,填寫16。表示每個系數用16比特量化。

?
圖?543
? ? 如上圖,在Input/Output Options選項卡中,做如下設置。
? ? Input Type:選擇Signed Binary,表示輸入的數據是有符號數(補碼形式)。
? ? Input Width:輸入8。表示輸入的數據是8位位寬。
? ? Output Type:選擇Signed Binary,表示輸出的數據是有符號數(補碼形式)。
? ? MSB Rounding:選擇Truncation。表示輸出結果的高位要截斷。
? ? MSB Bits to Remove:填寫3。表示MSB要截取3個符號位。
? ? LSB Rounding:選擇Truncation。表示輸出結果的低位要截斷。
? ? LSB Bits to Remove:填寫19。表示LSB要截斷低19位。這樣最終輸出的結果就是8位。
? ? 其他選項默認,點擊Finish,軟件就會去生成FIR IP核。

?
圖?544
? ? 出現上面的提示,就是生成成功了。

?
圖?545
? ? IP核生成后彈出此對話框點擊yes?將此IP核添加進工程。
3.3.4?例化FIR IP核
用GVIM打開D:mdy_bookir_prjmy_fir.v文件,該文件就是生成的FIR IP核文件。

圖?546
? ? my_fir模塊的各個信號的描述見下表。

?特別注意的是,濾波器的輸入數據和輸出數據都是有符號數(補碼的形式,-128~127)。而我們知道,正弦信sin_data是無符號數(0~255)。所以要將sin_data變成有符號數,再送給FIR進行濾波。假設轉換后的信號為fir_din,該信號位寬為8位。?
?無符號數轉成有符號數的方法很簡單:fir_din = sin_data - 128。讀者有興趣可以驗證一下。
生成FIR IP核后,我們要對其進行例化,才行使用上這個IP核,例化名起名u_my_fir,fir的輸出數據信號命名為fir_dout。

3.4?DA接口信號設計
?接下來是設計信號dac_da。dac_da是直接輸出正弦信號,但由于DA的輸出電壓與dac_da是成反比例線性關系,所以dac_da都是按(255-sin_data)得到。那么可以寫出dac_da的代碼。

? ? 接下來是設計信號dac_sleep,AD是一直工作的,所以要讓dac_sleep一直為0。
? ? dac_clka為了滿足tS的時間要求,可以讓dac_clka = ~clk。
? ? dac_wra可以與dac_clka相同。

? ? 接下來是設計信號dac_db。dac_db是直接輸出濾波后的信號fir_dout。但要注意的是fir_dout是有符號數(范圍是-128~127),所以要轉有無符號數(0~255)。假設轉換后的信號為fir_dout2,則fir_dout2 = fir_dout + 128。另外,由于DA的通道2的輸出電壓與dac_db是成反比例線性關系,所以dac_db都是按(255-fir_dout2)得到。那么可以寫出dac_db的代碼。

? ? dac_clkb為了滿足tS的時間要求,可以讓dac_clkb = ~clk。
? ? dac_wrb可以與dac_clkb相同。

3.5?信號定義
?至此,模塊主體已經完成。接下來是將module補充完整。
addr是用assign設計的,因此類型為wire。其值最大為127,一共有7根線,位寬為7,故而代碼如下

addr_tmp是用always設計的,因此類型為reg。如前面所述,該信號的位寬是17,故而代碼如下

? ? sin_data是用always設計的,因此類型為reg。其最大值為255,要有8根線表示,位寬為8,故而代碼如下

? ? fir_din是用assign設計的,因此類型為wire。其位寬為8,故而代碼如下

? ? fir_dout是用例化模塊的輸出,非always設計的,因此類型為wire。其位寬為8,故而代碼如下

? ? fir_dout2是用assign設計的,非always設計的,因此類型為wire。其位寬為8,故而代碼如下

?dac_da是用always設計的,因此類型為reg。其位寬為8;dac_sleep是用assign設計的,因此類型為wire,位寬為1;dac_wra是用assign設計的,因此類型為wire,位寬為1;dac_clka是用assign設計的,因此類型為wire,位寬為1;dac_mode是用assign設計的,因此類型為wire,位寬為1。故而代碼如下

?dac_db是用always設計的,因此類型為reg。其位寬為8;dac_wrb是用assign設計的,因此類型為wire,位寬為1;dac_clkb是用assign設計的,因此類型為wire,位寬為1。故而代碼如下

在代碼的最后一行寫下endmodule

? ? 至此,整個代碼的設計工作已經完成。下一步是新建工程和上板查看現象。
4?綜合與上板
4.1?添加文件到工程

圖?547
? ? 1.前面已經介紹了新建工程?,F在打開quartus,在Project菜單中選擇Add/Remove File to Project,彈出文件窗口。

圖?548
? ? 點擊右上角的
,在彈出來的窗口中,雙擊選擇D:mdy_bookir_prj目錄下的fir_prj.v文件。然后記得要點Add,才算正式加到工程。

圖?549
? ? 點OK關閉本窗口。
4.2?綜合

圖?550
? ? 在菜單欄中,選中Processing,然后選擇Start Compilation,開始對整個工程進行編譯和綜合。

圖?551
? ? 出現上面的界面,就說明編譯綜合成功。
4.3?配置管腳

圖?552
? ? 在菜單欄中,選中Assignments,然后選擇Pin Planner,就會彈出配置管腳的窗口。

圖?553
? ? 在配置窗口中的location一列,可以填寫每個管腳所對應的FPGA管腳號。

按上面配置好每個信號的管腳,其最終效果如下圖。

圖?554
? ? 關閉Pin Planner,軟件自動會保存管腳配置信息。
4.4?再次綜合

圖?555
? ? 在菜單欄中,選中Processing,然后選擇Start Compilation,開始對整個工程進行編譯和綜合。

圖?556
? ?出現上面的界面,就說明編譯綜合成功。
4.5?連接開發(fā)板

圖?557
? ? 連接示意如上圖所示。將電源接上開發(fā)板;USB BLASTER一端連接到JTAG插口,另一端連到PC的USB接口;將開發(fā)板上的P7接口和P11與示波器的兩個通道相連。最后再將電源打開。
4.6?上板

圖?558
? ? 在quartus的Task窗口中,右鍵Program Device?選擇Open?進入燒錄界面。

圖?559
? ? 在上面的界面中,默認會選中文件output/fir_prj.sof,如果沒有生成請看XXXX。
? ? 在上面的界面中,Hardware Setup的旁邊會顯示:USB-Blaster。如果不是,請看XXXX。

圖?560
? ? 點擊statr,在progress這一條顯示100%即表示成功,此時可以看FPGA輸出效果了。