在 FPGA 上實(shí)現(xiàn)低通濾波器,附Verilog解析
掃描二維碼
隨時(shí)隨地手機(jī)看文章
在本文中,我們將簡要探討不同類型的濾波器,然后學(xué)習(xí)如何實(shí)現(xiàn)移動(dòng)平均濾波器并使用 CIC 架構(gòu)對其進(jìn)行優(yōu)化。
濾波在許多設(shè)計(jì)中都至關(guān)重要。它使我們能夠提取隱藏在大量噪聲之下的有用信號(hào)。我們還可以通過濾波特定頻率的輸出來確定系統(tǒng)的非線性度。
讓我們首先討論一下不同類型的濾波器之間的一些區(qū)別。
理論
濾波器類型
根據(jù)濾波器的頻段類別,濾波器可以分為五類。每種濾波器的功能在其名稱中有所體現(xiàn)。例如,低通濾波器是指允許低頻輸入通過并阻止高頻輸入的濾波器,等等。
這五種類型是:
- 低通Low-pass
- 帶通Band-pass
- 帶阻Band-stop
- 高通High-pass
- 全通All-pass
濾波器的形狀也各有不同。例如,它們的通帶上可能有波紋,或者過渡帶可能比較平坦等等。
濾波器形狀
濾波器通常可按形狀分類如下:
- 貝塞爾Bessel: 與其他相比群延遲最平坦
- 巴特沃斯濾波器Butterworth: 設(shè)計(jì)用于在通帶中實(shí)現(xiàn)最平坦的幅頻響應(yīng);也稱為“最大平坦度”
- 切比雪夫Chebyshev: 旨在使理想濾波器與實(shí)際濾波器之間的誤差最??;可分為兩類:通帶中有紋波的濾波器和阻帶中有紋波的濾波器
- 橢圓形Elliptic:在通帶和阻帶中都有波紋,但它們在通帶和阻帶之間具有最快的過渡
選擇濾波器的形狀取決于所需的規(guī)格。例如,我們可能需要輸出信號(hào)幅度在通帶內(nèi)盡可能精確地跟蹤輸入信號(hào)幅度。在這種情況下,我們應(yīng)該使用巴特沃斯濾波器,即使它可以提供更多的過渡帶。
另一方面,我們可能希望輸出信號(hào)頻率精確跟隨輸入信號(hào),并具有線性相位響應(yīng),因此應(yīng)該選擇貝塞爾濾波器。如果我們需要使用盡可能少的元件,并保持與其他濾波器相同的階數(shù)和過渡速度,橢圓濾波器或切比雪夫?yàn)V波器也可以,但通帶或阻帶中會(huì)出現(xiàn)波紋。
模擬和數(shù)字濾波器
另一方面,濾波器可以通過兩種方式構(gòu)建:數(shù)字和模擬。
在模擬電路中,無源濾波器是由電感器和電容器或電阻器組成的梯形電路。有源模擬濾波器可以是一種利用放大器或諧振器的結(jié)構(gòu)。它們的值可以通過使用已創(chuàng)建的用于設(shè)計(jì)模擬濾波器的表格或應(yīng)用程序輕松確定。
數(shù)字濾波器可以用兩種方法創(chuàng)建:IIR 和 FIR。IIR(無限脈沖響應(yīng))濾波器是一種輸出取決于輸入和先前輸出的濾波器。
圖 1. IIR 濾波器。圖片由Mark Wilde提供(https://en.wikipedia.org/wiki/User:Mwilde)
數(shù)字濾波器的另一種實(shí)現(xiàn)方式是有限脈沖響應(yīng) (FIR)。這類濾波器不使用反饋,其輸出僅與當(dāng)前和先前的輸入相關(guān)。就穩(wěn)定性而言,F(xiàn)IR 濾波器始終穩(wěn)定, 因?yàn)樗鼈兊妮敵鰞H與輸入相關(guān)。另一方面,它們需要更高的階數(shù)才能滿足與 IIR 相同的規(guī)格。
圖 2. FIR 濾波器 圖片由Jonathan Blanchard提供(https://www.jblopen.com/)
移動(dòng)平均(moving average)
移動(dòng)平均(moving average)是一種濾波器,它對先前輸入的 N 個(gè)點(diǎn)進(jìn)行平均,并根據(jù)這些點(diǎn)得出輸出。
移動(dòng)平均濾波器是一個(gè) FIR 濾波器,其 N 個(gè)系數(shù)為1/N,一些具有不同N的移動(dòng)平均濾波器的頻率響應(yīng)如圖3所示。
圖 3.移動(dòng)平均線的頻率響應(yīng)
移動(dòng)平均moving average (MA) 濾波器的脈沖響應(yīng)在 0 到 N 之外的點(diǎn)上為零。
因此,MA 濾波器的頻率響應(yīng)為:
截止頻率可估算為:
根據(jù)這些公式,截止頻率僅與 N 有關(guān)。隨著 N 的增加,截止頻率會(huì)降低,但會(huì)耗費(fèi)時(shí)間。我們需要等待第 N 個(gè)周期才能獲得正確的結(jié)果,因此 N 越大,所需的時(shí)間就越長。隨著濾波器的清晰度提高,其輸出達(dá)到穩(wěn)定狀態(tài)所需的時(shí)間也會(huì)增加。
濾波及其設(shè)計(jì)實(shí)現(xiàn)是 FPGA 設(shè)計(jì)中一個(gè)廣泛的課題。設(shè)計(jì)人員需要學(xué)習(xí)大量知識(shí)才能設(shè)計(jì)出合適的濾波器,并以最少的資源占用或最快的速度在 FPGA 上實(shí)現(xiàn)它。
在本文中,我們將嘗試實(shí)現(xiàn)一個(gè) N 點(diǎn)MA濾波器。我們假設(shè) N 是一個(gè)參數(shù),可以在使用 Xilinx Vivado 等 CAD 工具綜合之前進(jìn)行更改。
如圖 2 所示,F(xiàn)IR 濾波器可以通過一個(gè)長度為 N(即 FIR 階數(shù))的延遲鏈、將系數(shù)乘以延遲線的乘法器以及一些將乘法器結(jié)果相加的加法器來實(shí)現(xiàn)。這種架構(gòu)需要大量的乘法器和加法器,而這些功能在 FPGA 中受到限制,具體取決于您使用的 FPGA 型號(hào)(即使是功能最強(qiáng)大的 FPGA 也存在限制)。
設(shè)計(jì) FIR 濾波器需要進(jìn)行一些研究來減少這些資源,因?yàn)樵谌魏?FPGA 設(shè)計(jì)的階段,減少資源都是必要的。不過,我們不會(huì)討論這個(gè)話題,而是用另一個(gè)技巧來設(shè)計(jì)MA濾波器。在MA濾波器中,所有系數(shù)都是1/N。如果我們想要實(shí)現(xiàn)像圖 2 那樣的濾波器,我們應(yīng)該制作一個(gè)抽頭延遲線并存儲(chǔ)最后 N 個(gè)輸入,然后將它們乘以1/N,最后將結(jié)果相加。不過,我們可以將最后 N 個(gè)輸入存儲(chǔ)在 FIFO 中,然后在每個(gè)周期將它們相加,再乘以 1/N。使用這種方法,我們只需要一個(gè) N 乘法器。
代碼說明
首先,我們有 N,即輸入點(diǎn)的數(shù)量,它是一個(gè)可調(diào)整的參數(shù)。我們將這 N 個(gè)點(diǎn)相加,得到輸出。
我們還假設(shè)輸入是 28 位格式,并且我們希望輸出也采用相同的格式。在處理添加 N 個(gè)點(diǎn)時(shí),我們可能會(huì)面臨位增長的問題。添加兩個(gè) 28 位點(diǎn)會(huì)導(dǎo)致輸出為 28 位,并產(chǎn)生一個(gè)溢出位。因此,添加 N 個(gè) 28 位點(diǎn)時(shí),我們需要 (log2(N) +28) 位輸出。
假設(shè)所有 N 個(gè)點(diǎn)都相同,將它們相加就好比將 N 乘以其中一個(gè)點(diǎn)。因此,我們實(shí)現(xiàn)了一個(gè)“l(fā)og2”函數(shù),它只需計(jì)算輸入的對數(shù)即可。通過了解 N 的對數(shù),我們可以設(shè)置輸出長度。需要注意的是,log2 不是一種可綜合的方法,并且僅適用于 Xilinx Vivado(即 Xilinx Vivado 計(jì)算 log2,然后將結(jié)果用于其余的綜合)。
“l(fā)og2”函數(shù)如下代碼所示:
function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction
現(xiàn)在我們已經(jīng)設(shè)置了輸入和輸出的長度,我們需要?jiǎng)?chuàng)建一個(gè)用于存儲(chǔ) N 個(gè)先前和當(dāng)前輸入的 tap 線。以下代碼可以實(shí)現(xiàn)這個(gè)功能:
genvar i; generate for (i = 0; i < N-1 ; i = i + 1) begin: gd always @(posedge clock_in) begin if(reset==1'b1) begin data[i+1]<=0; end else begin data[i+1] <= data[i]; end end end endgenerate
最后,我們需要一個(gè)加法器來對 FIFO 中存儲(chǔ)的所有數(shù)據(jù)進(jìn)行求和。這個(gè)階段有點(diǎn)棘手。如果我們想在每個(gè)時(shí)鐘周期都有輸出,就需要制作一個(gè)組合電路,逐步將 FIFO 中的數(shù)據(jù)相加。下面的代碼將實(shí)現(xiàn)這一點(diǎn):
genvar c; generate assign summation_steps[0] = data[0] + data[1]; for (c = 0; c < N-2 ; c = c + 1) begin: gdz assign summation_steps[c+1] = summation_steps[c] + data[c+2]; end endgenerate
然而,我們的目標(biāo) FPGA 沒有這么多資源(假設(shè)),在這個(gè) FPGA 上綜合這個(gè)模塊是不可行的。因此,把問題簡化了一些。假設(shè)我們希望輸出每 N 個(gè)時(shí)鐘周期更新一次。有了這個(gè)技巧,我們不再需要存儲(chǔ)所有接收到的數(shù)據(jù)。我們可以簡單地存儲(chǔ)總和,并在每個(gè)周期將其添加到當(dāng)前輸入。以下代碼可以實(shí)現(xiàn)這個(gè)技巧:
always@(posedge clock_in) begin if(reset) begin signal_out_tmp<=0; count<=0; signal_out<=0; end else begin if(down_sample_clk==N_down_sample) begin if(count begin count<=count+1'b1; signal_out_tmp<=signal_out_tmp+signal_in; end else begin count<=0; signal_out<=signal_out_tmp[27+N2:N2]; signal_out_tmp<=0; end end end end
在此代碼中,總和保存為 signal_out_tmp,并將在每個(gè)周期添加到輸入。在 N 個(gè)點(diǎn)之后,輸出將變?yōu)?signal_out_tmp,并且此變量將設(shè)置為零,并再次開始存儲(chǔ)和。
這種方法使用的資源非常少,但其輸出每 N 個(gè)周期就會(huì)更新一次。
仿真
測試平臺(tái)包含在項(xiàng)目代碼中,文后可以下載。在測試平臺(tái)中,將輸入視為一個(gè)步驟,并保存了輸出。在測試平臺(tái)中讀寫操作非常簡單,如下面的代碼所示。我們可以在測試平臺(tái)中使用 fopen 函數(shù)打開一個(gè)文件,然后使用 fwrite 函數(shù)寫入文件。
f = $fopen("output.txt","w"); f2 = $fopen("time.txt","w"); $fwrite(f,"%d %d\n",signal_in,signal_out); $fwrite(f2,"%d\n",cur_time);
fwrite 中的格式化功能與 C 語言中簡單的 printf 函數(shù)非常相似。我們還將在測試平臺(tái)中使用 變量。使用time 變量可以獲取當(dāng)前時(shí)間,并將其寫入文本文件。在對項(xiàng)目進(jìn)行仿真后,我們可以在 MATLAB 中使用寫入的文件來確保其正確性。用 MATLAB 編寫的代碼首先讀取文件并繪制圖表。
A = importdata('D:\low_test\output.txt'); B = importdata('D:\low_test\time.txt'); M2=A(:,2); M1=A(:,1); T=B(:,1)*10e-9; M1=M1/(2^24); M2=M2/(2^24); plot(M1); hold on; plot(M2); s=size(M1); val=0; t=0:s(1,1)-1; t=t*50e-9; for i=405:s(1,1) if(abs(M1(i,1)-M2(i,1))<1*.1) val=i; break; end end stepp=stepinfo(M2,t); pp=stepp.RiseTime; fc=.35/pp cycles=val-405 time=((cycles)*50)/1000
為了測試目的,我們首先用階躍輸入仿真我們的工作臺(tái),然后將輸入改為正弦輸入。結(jié)果如圖 6 和圖 7 所示。
圖 6.階躍響應(yīng)
圖 7. Sin(x)*sin(x) 響應(yīng)
如圖 6 所示,0.2 ms后,濾波器輸出變得與輸入幅度一樣高。圖 6 中每 N 個(gè)周期都會(huì)有一次響應(yīng),因?yàn)檩敵霾⒎瞧交兓O喾?,它在?N 個(gè)周期后才發(fā)生變化。
在圖 7 中,因?yàn)檩斎胧?6*sin(x)*sin(x),我們知道該輸入的直流偏移是 3,因?yàn)槲覀兊牡屯V波器輸出是 3。
CIC濾波器
級(jí)聯(lián)積分器梳狀濾波器(The cascaded integrator-comb filter)是一種硬件高效的 FIR 數(shù)字濾波器。
CIC 濾波器由相同級(jí)數(shù)的理想積分濾波器和抽取濾波器組成。CIC 濾波器架構(gòu)如圖 8 所示。
圖 8. CIC 濾波器圖像。圖片來自Wikimedia Commons(https://commons.wikimedia.org/wiki/File:CIC_interpolator.svg)
我們可以使用 CIC 濾波器并重寫MA方程來優(yōu)化MA低通濾波器,如下所示:
該架構(gòu)由一個(gè)梳狀部分 (c[n]=x[n]-x[nN]) 和一個(gè)積分器 (y[n]=y[n-1]+c[n]) 組成,因此我們可以在這里使用 CIC 架構(gòu)。在該架構(gòu)中,我們將加法器精簡為僅三個(gè)部分,以便每個(gè)周期都能獲得輸出,這正是 CIC 濾波器的神奇之處。
在文后可供下載的代碼中,使用 CIC 濾波器拓?fù)鋬?yōu)化了MA。我們可以使用以下 Verilog 代碼在硬件中實(shí)現(xiàn)上述公式:
wire signed [27+N2:0] signal_out_tmp_2=signal_out_tmp_3+signal_in-data[N-1];
圖 9 顯示了具有 sin(x)*sin(x) 輸入的新結(jié)構(gòu)的輸出。
圖 9. CIC 輸出
結(jié)論
數(shù)字和模擬電路都可用于濾波。每種方法各有優(yōu)勢,但數(shù)字濾波具有可重新編程的特性,并且實(shí)現(xiàn)面積更小。在本文中,我們首先研究了濾波器的構(gòu)建方法,然后以最簡單的方式實(shí)現(xiàn)了一個(gè)MA濾波器。最后,我們使用 CIC 架構(gòu)對其進(jìn)行了優(yōu)化。
代碼
https://github.com/suisuisi/FPGATechnologyGroup/blob/main/files-low-pass.zip





