FIR(Finite Impulse Response)濾波器是一種有限長(zhǎng)單位沖激響應(yīng)濾波器,又稱(chēng)為非遞歸型濾波器。
FIR 濾波器具有嚴(yán)格的線性相頻特性,同時(shí)其單位響應(yīng)是有限長(zhǎng)的,因而是穩(wěn)定的系統(tǒng),在數(shù)字通信、圖像處理等領(lǐng)域都有著廣泛的應(yīng)用。
FIR 濾波器是有限長(zhǎng)單位沖擊響應(yīng)濾波器。直接型結(jié)構(gòu)如下:
FIR 濾波器本質(zhì)上就是輸入信號(hào)與單位沖擊響應(yīng)函數(shù)的卷積,表達(dá)式如下:
FIR 濾波器有如下幾個(gè)特性:
輸入頻率為 7.5 MHz 和 250 KHz 的正弦波混合信號(hào),經(jīng)過(guò) FIR 濾波器后,高頻信號(hào) 7.5MHz 被濾除,只保留 250KHz 的信號(hào)。設(shè)計(jì)參數(shù)如下:
輸入頻率: 7.5MHz 和 250KHz
采樣頻率: 50MHz
阻帶: 1MHz ~ 6MHz
階數(shù): 15(N-1=15)
由 FIR 濾波器結(jié)構(gòu)可知,階數(shù)為 15 時(shí),F(xiàn)IR 的實(shí)現(xiàn)需要 16 個(gè)乘法器,15 個(gè)加法器和 15 組延時(shí)寄存器。為了穩(wěn)定第一拍的數(shù)據(jù),可以再多用一組延時(shí)寄存器,即共用 16 組延時(shí)寄存器。由于 FIR 濾波器系數(shù)的對(duì)稱(chēng)性,乘法器可以少用一半,即共使用 8 個(gè)乘法器。
并行設(shè)計(jì),就是在一個(gè)時(shí)鐘周期內(nèi)對(duì) 16 個(gè)延時(shí)數(shù)據(jù)同時(shí)進(jìn)行乘法、加法運(yùn)算,然后在時(shí)鐘驅(qū)動(dòng)下輸出濾波值。這種方法的優(yōu)點(diǎn)是濾波延時(shí)短,但是對(duì)時(shí)序要求比較高。
設(shè)計(jì)中使用到的乘法器模塊代碼,可參考之前流水線式設(shè)計(jì)的乘法器。
為方便快速仿真,也可以直接使用乘號(hào) * 完成乘法運(yùn)算,設(shè)計(jì)中加入宏定義 ?SAFE_DESIGN
?來(lái)選擇使用哪種乘法器。
FIR 濾波器系數(shù)可由 matlab 生成,具體見(jiàn)附錄。
/***********************************************************
>> V201001 : Fs:50Mhz, fstop:1Mhz-6Mhz, order: 15
************************************************************/
`define SAFE_DESIGN
module fir_guide (
input rstn, //復(fù)位,低有效
input clk, //工作頻率,即采樣頻率
input en, //輸入數(shù)據(jù)有效信號(hào)
input [11:0] xin, //輸入混合頻率的信號(hào)數(shù)據(jù)
output valid, //輸出數(shù)據(jù)有效信號(hào)
output [28:0] yout //輸出數(shù)據(jù),低頻信號(hào),即250KHz
);
//data en delay
reg [3:0] en_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
en_r[3:0] <= 'b0 ;
end
else begin
en_r[3:0] <= {en_r[2:0], en} ;
end
end
//(1) 16 組移位寄存器
reg [11:0] xin_reg[15:0];
reg [3:0] i, j ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0; i<15; i=i+1) begin
xin_reg[i] <= 12'b0;
end
end
else if (en) begin
xin_reg[0] <= xin ;
for (j=0; j<15; j=j+1) begin
xin_reg[j+1] <= xin_reg[j] ; //周期性移位操作
end
end
end
//Only 8 multipliers needed because of the symmetry of FIR filter coefficient
//(2) 系數(shù)對(duì)稱(chēng),16個(gè)移位寄存器數(shù)據(jù)進(jìn)行首位相加
reg [12:0] add_reg[7:0];
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0; i<8; i=i+1) begin
add_reg[i] <= 13'd0 ;
end
end
else if (en_r[0]) begin
for (i=0; i<8; i=i+1) begin
add_reg[i] <= xin_reg[i] + xin_reg[15-i] ;
end
end
end
//(3) 8個(gè)乘法器
// 濾波器系數(shù),已經(jīng)過(guò)一定倍數(shù)的放大
wire [11:0] coe[7:0] ;
assign coe[0] = 12'd11 ;
assign coe[1] = 12'd31 ;
assign coe[2] = 12'd63 ;
assign coe[3] = 12'd104 ;
assign coe[4] = 12'd152 ;
assign coe[5] = 12'd198 ;
assign coe[6] = 12'd235 ;
assign coe[7] = 12'd255 ;
reg [24:0] mout[7:0];
`ifdef SAFE_DESIGN
//流水線式乘法器
wire [7:0] valid_mult ;
genvar k ;
generate
for (k=0; k<8; k=k+1) begin
mult_man #(13, 12)
u_mult_paral (
.clk (clk),
.rstn (rstn),
.data_rdy (en_r[1]),
.mult1 (add_reg[k]),
.mult2 (coe[k]),
.res_rdy (valid_mult[k]), //所有輸出使能完全一致
.res (mout[k])
);
end
endgenerate
wire valid_mult7 = valid_mult[7] ;
`else
//如果對(duì)時(shí)序要求不高,可以直接用乘號(hào)
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
for (i=0 ; i<8; i=i+1) begin
mout[i] <= 25'b0 ;
end
end
else if (en_r[1]) begin
for (i=0 ; i<8; i=i+1) begin
mout[i] <= coe[i] * add_reg[i] ;
end
end
end
wire valid_mult7 = en_r[2];
`endif
//(4) 積分累加,8組25bit數(shù)據(jù) -> 1組 29bit 數(shù)據(jù)
//數(shù)據(jù)有效延時(shí)
reg [3:0] valid_mult_r ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
valid_mult_r[3:0] <= 'b0 ;
end
else begin
valid_mult_r[3:0] <= {valid_mult_r[2:0], valid_mult7} ;
end
end
`ifdef SAFE_DESIGN
//加法運(yùn)算時(shí),分多個(gè)周期進(jìn)行流水,優(yōu)化時(shí)序
reg [28:0] sum1 ;
reg [28:0] sum2 ;
reg [28:0] yout_t ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
sum1 <= 29'd0 ;
sum2 <= 29'd0 ;
yout_t <= 29'd0 ;
end
else if(valid_mult7) begin
sum1 <= mout[0] + mout[1] + mout[2] + mout[3] ;
sum2 <= mout[4] + mout[5] + mout[6] + mout[7] ;
yout_t <= sum1 + sum2 ;
end
end
`else
//一步計(jì)算累加結(jié)果,但是實(shí)際中時(shí)序非常危險(xiǎn)
reg signed [28:0] sum ;
reg signed [28:0] yout_t ;
always @(posedge clk or negedge rstn) begin
if (!rstn) begin
sum <= 29'd0 ;
yout_t <= 29'd0 ;
end
else if (valid_mult7) begin
sum <= mout[0] + mout[1] + mout[2] + mout[3] + mout[4] + mout[5] + mout[6] + mout[7];
yout_t <= sum ;
end
end
`endif
assign yout = yout_t ;
assign valid = valid_mult_r[0];
endmodule
testbench 編寫(xiě)如下,主要功能就是不間斷連續(xù)的輸入 250KHz 與 7.5MHz 的正弦波混合信號(hào)數(shù)據(jù)。輸入的混合信號(hào)數(shù)據(jù)也可由 matlab 生成,具體見(jiàn)附錄。
`timescale 1ps/1ps
module test ;
//input
reg clk ;
reg rst_n ;
reg en ;
reg [11:0] xin ;
//output
wire valid ;
wire [28:0] yout ;
parameter SIMU_CYCLE = 64'd2000 ; //50MHz 采樣頻率
parameter SIN_DATA_NUM = 200 ; //仿真周期
//=====================================
// 50MHz clk generating
localparam TCLK_HALF = 10_000;
initial begin
clk = 1'b0 ;
forever begin
# TCLK_HALF ;
clk = ~clk ;
end
end
//============================
// reset and finish
initial begin
rst_n = 1'b0 ;
# 30 rst_n = 1'b1 ;
# (TCLK_HALF * 2 * SIMU_CYCLE) ;
$finish ;
end
//=======================================
// read signal data into register
reg [11:0] stimulus [0: SIN_DATA_NUM-1] ;
integer i ;
initial begin
$readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ;
i = 0 ;
en = 0 ;
xin = 0 ;
# 200 ;
forever begin
@(negedge clk) begin
en = 1'b1 ;
xin = stimulus[i] ;
if (i == SIN_DATA_NUM-1) begin //周期送入數(shù)據(jù)控制
i = 0 ;
end
else begin
i = i + 1 ;
end
end
end
end
fir_guide u_fir_paral (
.xin (xin),
.clk (clk),
.en (en),
.rstn (rst_n),
.valid (valid),
.yout (yout));
endmodule
由下圖仿真結(jié)果可知,經(jīng)過(guò) FIR 濾波器后的信號(hào)只有一種低頻率信號(hào)(250KHz),高頻信號(hào)(7.5MHz)被濾除了。而且輸出波形是連續(xù)的,能夠持續(xù)輸出。
但是,如紅圈所示,波形起始部分呈不規(guī)則狀態(tài),對(duì)此進(jìn)行放大。
波形起始端放大后如下圖所示,可見(jiàn)不規(guī)則波形的時(shí)間段,即兩根豎線之間的時(shí)間間隔是 16 個(gè)時(shí)鐘周期。
因?yàn)閿?shù)據(jù)是串行輸入,設(shè)計(jì)中使用了 16 組延時(shí)寄存器,所以濾波后的第一個(gè)正常點(diǎn)應(yīng)該較第一個(gè)濾波數(shù)據(jù)輸出時(shí)刻延遲 16 個(gè)時(shí)鐘周期。即數(shù)據(jù)輸出有效信號(hào) valid 應(yīng)該再延遲 16 個(gè)時(shí)鐘周期,則會(huì)使輸出波形更加完美。
打開(kāi) matlab,在命令窗口輸入命令: fdatool。
然后會(huì)打開(kāi)如下窗口,按照 FIR 濾波器參數(shù)進(jìn)行設(shè)置。
這里選擇的 FIR 實(shí)現(xiàn)方法是最小二乘法(Least-squares),不同的實(shí)現(xiàn)方式濾波效果也不同。
點(diǎn)擊 File -> Export
將濾波器參數(shù)輸出,存到變量 coef 中,如下圖所示。
此時(shí) coef 變量應(yīng)該是浮點(diǎn)型數(shù)據(jù)。對(duì)其進(jìn)行一定倍數(shù)的相乘擴(kuò)大,然后取其近似的定點(diǎn)型數(shù)據(jù)作為設(shè)計(jì)中的 FIR 濾波器參數(shù)。這里取擴(kuò)大倍數(shù)為 2048,結(jié)果如下所示。
利用 matlab 生成混合的輸入信號(hào)參考代碼如下。
信號(hào)為無(wú)符號(hào)定點(diǎn)型數(shù)據(jù),位寬寬度為 12bit,存于文件 cosx0p25m7p5m12bit.txt。
clear all;close all;clc;
%=======================================================
% generating a cos wave data with txt hex format
%=======================================================
fc = 0.25e6 ; % 中心頻率
fn = 7.5e6 ; % 雜波頻率
Fs = 50e6 ; % 采樣頻率
T = 1/fc ; % 信號(hào)周期
Num = Fs * T ; % 周期內(nèi)信號(hào)采樣點(diǎn)數(shù)
t = (0:Num-1)/Fs ; % 離散時(shí)間
cosx = cos(2*pi*fc*t) ; % 中心頻率正弦信號(hào)
cosn = cos(2*pi*fn*t) ; % 雜波信號(hào)
cosy = mapminmax(cosx + cosn) ; %幅值擴(kuò)展到(-1,1) 之間
cosy_dig = floor((2^11-1) * cosy + 2^11) ; %幅值擴(kuò)展到 0~4095
fid = fopen('cosx0p25m7p5m12bit.txt', 'wt') ; %寫(xiě)數(shù)據(jù)文件
fprintf(fid, '%x\n', cosy_dig) ;
fclose(fid) ;
%時(shí)域波形
figure(1);
subplot(121);plot(t,cosx);hold on ;
plot(t,cosn) ;
subplot(122);plot(t,cosy_dig) ;
%頻域波形
fft_cosy = fftshift(fft(cosy, Num)) ;
f_axis = (-Num/2 : Num/2 - 1) * (Fs/Num) ;
figure(5) ;
plot(f_axis, abs(fft_cosy)) ;
點(diǎn)擊這里下載源碼
更多建議: