在时域中,FIR滤波器的输入/输出就是一个输入信号与单位脉冲相应的卷积。离散方程为y(n)=x(n)*h(n)=∑x(k)h(n-k)=∑h(k)x(n-k),其中y(n)为滤波输出,x(n)为采样数据,h(n)为滤波抽头系数.设计FIR滤波器就是要找到N个系数。N-1阶滤波器通常需要N个系数描述,通常需要N个乘法器和N-1个2输入加法器实现。根据FIR表达式,滤波器实质上就是进行乘累加运算,乘累加的次数由滤波器阶数决定。其串行结构如图
系数表的产生我们利用matlab的FDATool来完成。
首先打开matlab的FDATool工具,选择一个38阶的带通滤波,利用窗函数法,窗口类型为kaiser,BETA设置为3.4,通带频率为10Hz~20Hz。采样频率100Hz。
设置好之后点击Design Filter并保存为.fda文件。之后在simulation环境下,添加该设计,另外使用y=sin(5t)+sin(15t)+sin(30t)作为输入信号,开始运行并查看滤波器的滤波效果,如下图
可见这个带通滤波器的滤波效果还是比较好的,同样我们可以利用FDATool工具设计一个LowPass Filter,采用等波纹设计法,采样频率100Hz,截止频率为20Hz,同样用上述的信号作为输入,得到如下的滤波效果
自此我们在matlab中验证了滤波器的效果,接下来我们需要在FPGA中实现。在我们设置好FDATool的参数后,我们可以点击Analysis-->Filter Coefficients来观察FIR滤波器的系数,
这里的系数全是有符号型的小数,我们在FPGA中需要用整数作为滤波器的系数,所以我们要进行系数的归一化,点击左下角设置量化参数(Set Quantization Parameters),Filter arithmetic选择Fixed-point(定点)。然后就可以导出Xilink的.coe文件了。Targets-->XILINK Coefficients(.COE) File.保存后matlab自动打开该.coe文件
CoefData这就是我们FPGA要用的系数表。接下来去编写Verilog代码
module FIR_kaiser_LPF(Clk,Rst_n,data_in,data_out);
parameter word_data_in = 8;
parameter word_data_out = 2*word_data_in+1;
parameter order = 8;
parameter c0 = 8'h0d;
parameter c1 = 8'h23;
parameter c2 = 8'h41;
parameter c3 = 8'h5b;
parameter c4 = 8'h65;
parameter c5 = 8'h5b;
parameter c6 = 8'h41;
parameter c7 = 8'h23;
parameter c8 = 8'h0d;
input Clk;
input Rst_n;
input [word_data_in-1:0]data_in;
output wire [word_data_out-1:0]data_out;
reg [word_data_in-1:0]samples[order-1:0];
reg [word_data_in-1:0]data_in_tmp1;
reg [word_data_in-1:0]data_in_tmp2;
integer i;
always@(posedge Clk)
if(!Rst_n)begin
data_in_tmp1<=8'd0;
data_in_tmp2<=8'd0;
end
else begin
data_in_tmp1<=data_in;
data_in_tmp2<=data_in_tmp1;
end
always@(posedge Clk)//同步复位,完成移位功能
if(!Rst_n)begin
for(i=0;i<order;i=i+1)
samples[i]<=0;
end
else begin
samples[0]<=data_in_tmp2;
for(i=1;i<order;i=i+1)
samples[i]<=samples[i-1];
end
//串行实现累加
assign data_out = c0*data_in_tmp2 + c1*samples[0] + c2*samples[1] + c3*samples[2] +
c4*samples[3] + c5*samples[4] + c6*samples[5] + c7*samples[6] + c8*samples[7];
endmodule