濾波器在2017年IC前端的筆試中,出現頻率十分的高。不論今后是否會涉及,還是要記住一些會比較好。接下來就將從這四個方面來講解,FIR數字濾波器的工作原理(算法)與verilog實現。
·什么是FIR數字濾波器
·FIR數字濾波器與IIR數字濾波器的對比
·從sobel算法、高斯濾波算法着手,講解FIR濾波器算法
·FIR數字濾波器的幾種verilog代碼實現
一、什么是FIR數字濾波器
FIR濾波器的全稱是Finite Impulse Respond Filter。中文全稱是有限脈沖響應濾波器,它也叫做非遞歸型濾波器。
它的作用和所有的濾波器一樣,通過算法來使某刻的值處在一個更為准確的值,這句話看着很繞,但是在后面的三種算法的介紹中,應該可以理解我在這里說的這句話的含義。(它比‘通過算法來去除雜波’這句話,更清楚明白)。
實現數字濾波,就必須要有數字信號,所以這里要通過A/D轉換,來使得模擬信號變為數值,才好帶入算法中計算,然后用D/A轉換,輸出模擬信號。
二、FIR數字濾波器與IIR數字濾波器的對比
這里說了與IIR數字濾波器的對比,那什么是IIR數字濾波器呢?
IIR數字濾波器全稱是Infinite Impulse Respond Filter。中文全稱是無限脈沖響應濾波器,它也叫做遞歸型濾波器。
二者特點比較:
FIR濾波器特點:
- 沒有反饋回路,穩定性強。即FIR濾波器只需要有當前數據,和歷史輸入數據,不需要歷史濾波輸出數據的參與(這是它與IIR最大的區別了,后面許多差別也就是因為這個而來的)。因為濾波的輸出本來就是一個舍入值,若帶入下一次的計算中,就會在這個舍入值(非精准值)基礎上再一次的舍入,進行N次,會產生微小的寄生振盪。
- 算法計算完成后與原先數據有線性的相位差,更容易將計算后的信號相位還原成原相位(通過左右平移的方式直接修正)。
- 相對於IIR數字濾波器,在相同性能指標下,階次(就是后面所說的N次選點)較高,對CPU的消耗更大。
IIR濾波器特點:
- 系統函數可以寫成封閉函數的形式,具有反饋回路。這個反饋回路的加入,使得在相同CPU消耗下,IIR的精確度不如FIR,但在較小的相同階次下,也是它使得IIR的效果要比FIR更好,成也反饋敗也反饋。
- 算法計算完成后與原先數據的相位差不是線性的,這就使得在修正相位差的時候會很麻煩。
- FIR濾波器特點第一條就說了,IIR可能會產生寄生振盪。
下面的兩幅圖是我自己畫的,一個是FIR濾波后(並進行D/A轉換后)與IIR濾波后的相位差對比圖,一個是基於FPGA的功能對比圖。
圖1
從圖1中可以看出來,IIR濾波后,相位與原先是非線性的。而FIR是線性的。
圖2
從圖2中可以看到IIR明顯存在一個反饋過程。
對於不同濾波需求該怎么選擇呢?
應用選擇:
- 對於相位要求不敏感的場合用IIR,它對CPU需求較低,充分發揮經濟高效的特點。
- 對於做圖像信號處理、數據傳輸等以波形攜帶信息的場合,要使用FIR,比起CPU資源的消耗,我們更關心的是結果的准確。(在許許多多的設計中都是同樣的道理,想得到什么就得失去什么,不可能在同等工藝基礎上,又快又省功耗面積又小的。)
三、從sobel算法、高斯濾波算法着手,講解FIR濾波器算法
下面從sobel算法開始,慢慢道來。
sobel算法
Sobel算法是用在檢測像素邊沿點的一種算法。
邊沿點。一幅美麗的照片,不可能是單純的一種顏色,那在各個色彩的交階位置就是邊沿點。
通過帶入計算sobel卷積因子,計算出I GX I、I GY I,兩者相加得到的G的值與規定標准值(一個確定的邊沿點帶入卷積因子計算后得到的一個標准值) 進行比較。若大於等於標准值則認為是一個邊沿點。
sobel卷積因子
Gx: -1 0 +1 Gy: +1 +2 +1
-2 0 +2 0 0 0
-1 0 +1 -1 -2 -1
卷積因子的使用:
比如說下面是一個巨大的像素屏,選擇一點為檢測對象(紅色標記),那這一點就對應了卷積因子最中間的點,其它八個點對應像素上的八個點(藍色標記)。
口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口
將各個點的值與對應相同位置的卷積因子相乘,之后將得到的9個值相加,並求絕對值,得到的就是Gx與Gy的絕對值,兩者相加為G,再將G於標准值進行比較,得到改點是否為邊沿點。
為什么這么做就可以檢測出邊沿點了呢?
從卷積因子可以看出,兩次計算之后,其實是拿待檢測點與相鄰、相斜對角的值做放大,上下左右直接與待檢測點相連的值放大了兩倍,就像一個顯微鏡,把中間點和四周點點色彩的區別放大了,這就是檢測的原理。
高斯濾波算法
高斯濾波算法可以用來優化圖像,舉個最直白的道理,你拍了一張自拍照,但是上面的小豆豆很是討厭,而使用高斯濾波算法可以使得這些討厭的小豆豆全部變淡,或者消失。
是不是引發了愛美的你的強烈的興趣?接下來看一下卷積因子。
1 2 1
2 4 2
1 2 1
口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口口
腦補上面是一幅圖畫,每幅圖也都是由像素點組成。我們假設紅色的點是痘痘,那我們要經過高斯濾波算法,將它變為和周邊皮膚(藍色標記)顏色相同。
設九宮格內數值依次是x0,x1,x2,x3,x4,x5,x6,x7,x8。其中x4是我們要優化的點。設值為y:
Y = (x0*1+x1*2+x2*1+x3*2+x4*4+x5*2+x6*1+x7*2+x8*1)/16
這個計算出來的值就是優化值。下面看看原理:
細心的朋友會發現與sobel算法不同之處在於,最后還要除以16。為什么呢?
因為所有的因子相加是16,如果不除以16那么就會將優化值放大16被,那就是說這個痘痘反而變得與周圍皮膚更加的凸顯了,這顯然不是我們想要的。
總結:
上面兩個算法的目的是什么?引用上面兩個算法,是為了讓大家更好的了解這種卷積式的算法,以及它的原理,下面的FIR濾波器算法和上面兩者有很多相似之處。
FIR濾波器算法
終於到了正題,能堅持看到這里的朋友,下面對於FIR的分析一定不會讓你失望。
直接掏出算法公式:
Y(N) = h(0)*x(N)+h(1)*x(N-1)+``````+h(k-1)*x(N-(k-1))
Y(N)表示的是第N個取樣點縱坐標的優化值
X(N)表示的是第N個取樣點橫坐標的值(取樣值)
h()表示系數,后面會有系數的求取方法
這里的h系數就類似於前面說的卷積因子,只不過這卷積因子的數量並不確定的,並且並不是每個取樣點都會加入計算,它與系數的個數有關。所以可以這么說,FIR濾波器取的系數越多,計算的越精確(當然N要大於k),但是消耗的cpu資源也會越多。畢竟從上式可以看出這是好多加法器乘法器組成的。
濾波原理同類似於上述兩種算法,(神似而已)最后的系數相加肯定必須還是1。
很重要的一點h的取值是可以用matlab軟件計算出來的,具體方法,請自行搜索FIR濾波器算法系數的計算,因為只是一些軟件的使用,這里不在講述。
四、FIR數字濾波器的幾種verilog代碼實現
我們假設N = 8 k = 7
實現算法一:
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld) begin
y <= x0*h7+x1*h6+x2*h5+`````+x7*h0;
end
end
涉及時序用非阻塞,具體原因可以看我之前寫的verilog編寫規范里面的關於阻塞和非阻塞區別的解釋。
這個算法好嗎?
它對於人類來說是友好的,一目了然。但是對於整個FIR數字濾波器的硬件設計卻是非常不友好的。上面用了一長串的賦值語句來計算y的值。但從硬件上體現,這就是加法器和乘法器啊,這么多的加法器乘法器,那得多大的延遲啊?所以可以看一下算法二:
實現算法二: 流水線,並行乘法
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld) begin vld是指示信號,說明數據進來了
m0 <= x0*h7;
m1 <=x1*h6;
`
`
`
m7 <= x7*h0;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld_ff0) begin
n0 <= m0 + m1;
n1 <= m2 + m3;
`
`
`
n3 <= m6 + m7;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld_ff1) begin
z0 <= n0 + n1;
z1 <= n2 +n3;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld_ff2) begin
Y <= z0 + z1;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(vld_y) begin
vld_ff0 <= vld;
vld_ff1 <= vld_ff0;
vld_ff2 <= vld_ff1;
vld_y <= vld_ff2;
end
end
雖然采用了流水線的設計,使得各個乘法器、加法器並行計算,大大節省了時間,但是乘法器加法器的個數還是比較多的。能不能就用一個乘法器一個加法器?
實現方法三:
加入一個計數器
always@ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
end
else if(add_cnt) begin
if(end_cnt) begin
cnt <= 0;
end
else begin
cnt <= cnt+1;
end
end
end
assign add_cnt = flag_add;
assign end_cnt = add_cnt && cnt == 8-1;
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else if(add_cnt && cnt == 1-1) begin
A <=x0;
B<= h7;
end
`
`
`
else if(add_cnt && cnt == 8-1) begin
a <=x7;
b<= h0;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
end
else begin
mul <= a + b;
end
end
always@ (posedge clk or negedge rst_n) begin
if (rst_n == 1’b0) begin
y<= 0;
end
else if() begin
y <= y + mul;
end
end
這個方法,只用了一個加法器和一個乘法器,非常省面積,但是它與二相比,不是並行乘和加,所以速度比不上方法二。
在具體設計中會根據具體的情況來選擇三種不同的描述方式。