流水线 FIR 滤波器的verilog实现
程序员文章站
2024-03-24 22:39:28
...
滤波器信号处理中比较常用的滤波器,这是一个基于流水线的FIR滤波器
//fir filter
//data witdh: 16
//filter coeff :-0.0003706 -0.0011344 -0.0018156 -0.0020642 -0.0012814 0.0010011 0.0045544 0.0080695 0.0093324 0.0061059 -0.0025289 -0.014965 -0.026692 -0.031215 -0.022162 0.0040632 0.046173 0.097395 0.14687 0.18274 0.19584 0.18274 0.14687 0.097395 0.046173 0.0040632 -0.022162 -0.031215 -0.026692 -0.014965 -0.0025289 0.0061059 0.0093324 0.0080695 0.0045544 0.0010011 -0.0012814 -0.0020642 -0.0018156 -0.0011344 -0.0003706
//model by crazyalpha (@github)
//email: aaa@qq.com
module fir_filter(clk, data_in, fil_out);
parameter dat_width = 16;
parameter fil_len = 40;
input clk;
input [dat_width-1 : 0] data_in;
output [dat_width-1 : 0] fil_out;
wire [dat_width-1 :0] coef[(fil_len+1)>>1 :0];
//filter coefficient
assign coef[0] = -12;
assign coef[1] = -37;
assign coef[2] = -59;
assign coef[3] = -68;
assign coef[4] = -42;
assign coef[5] = 33;
assign coef[6] = 149;
assign coef[7] = 264;
assign coef[8] = 306;
assign coef[9] = 200;
assign coef[10] = -83;
assign coef[11] = -490;
assign coef[12] = -875;
assign coef[13] = -1023;
assign coef[14] = -726;
assign coef[15] = 133;
assign coef[16] = 1513;
assign coef[17] = 3191;
assign coef[18] = 4813;
assign coef[19] = 5988;
assign coef[20] = 6417;
//input latch
reg [dat_width-1 :0] data_tmp;
always @(posedge clk)
begin
data_tmp <= data_in;
end
//multiply
wire [dat_width*2-1 :0] m_result[(fil_len+1)>>1 :0];
genvar j;
generate for(j=0; j<=(fil_len+1)>>1; j=j+1)
begin:filter1
signed_mult signed_mult_inst(.dataa(data_tmp), .datab(coef[j]),.result(m_result[j]));
end
endgenerate
//get sum
integer i;
reg [dat_width*2-1:0] fil_reg[fil_len:0];
always @(posedge clk)
begin
fil_reg[0] <= m_result[0];
for(i=1; i<(fil_len+1)>>1; i=i+1)
fil_reg[i] <= fil_reg[i-1] + m_result[i];
for(i=(fil_len+1)>>1; i<=fil_len; i=i+1)
fil_reg[i] <= fil_reg[i-1] + m_result[fil_len-i];
end
//output
wire [dat_width*2-1:0] filout_tmp = fil_reg[fil_len];
assign fil_out =filout_tmp[dat_width*2-2:dat_width-1 ];
endmodule
//this signed_mult can(should) be replaced by megacore function
module signed_mult(dataa,datab,result);
parameter datin_width = 16;
input [datin_width-1 :0]dataa, datab;
output[datin_width*2-1 :0] result;
assign result ={ {datin_width{dataa[datin_width-1]}}, dataa } * { {datin_width{datab[datin_width-1]}},datab };
endmodule
以上滤波器是在modelsim中实现的,以下是testbench
`timescale 1ns/1ns;
module fir_testbench;
parameter dat_width = 16;
reg clk;
reg [dat_width-1 :0] dat;
wire[dat_width-1 :0] fil_o;
integer handle1;
reg fs;
initial
begin//sequence block
handle1 =$fopen("fsave.txt");
#1080 fs = 1; //fir filter outputs first data
#100000 fs=0;
$fclose(handle1);
$stop;
end
initial
fork //synchrous block
dat = 0;
clk =0;
forever #10 clk=~clk;
join
integer seed;
always @(posedge clk )
begin
dat <= $random(seed); //generate a random ,
if(fs == 1)
$fwrite(handle1,"%d %d \n",dat,fil_o);
end
fir_filter fir_filter_inst(clk, dat, fil_o);
endmodule
在testbench中采用随机数作为滤波器的输入,进行仿真处理,并将滤波器的输入和输出都保存在文件中,以便于进行 MATLAB处理。在Matlab中将保存的数据读出,再进行计算,并与仿真的结果进行比较对,以验证其正确性
clear;
file_name='fsave.txt';
fid = fopen(file_name,'r');
c = fscanf(fid,'%d');
fclose(fid);
for i=1: length(c)
if(c(i)>32767)
b(i) = c(i)-65536;
else b(i) = c(i);
end
end
d1=b(1:2:end);
d2=b(2:2:end);
stg=40;
wn=fir1(stg,10/51.2);
wpara=int32(32768*wn);
for i= 1: (length(d1)-stg)
e(i)=sum(wpara.*int32(d1(i:i+stg)));
end
f=int16(e/32768);
m1=d2(stg+3:end);
m2=f(1:end-2);
n=int32(m1)-int32(m2);
subplot(3,1,1);
plot(m2);
subplot(3,1,2);
plot(m1);
subplot(3,1,3);
plot(n);
比较的结果如下图,第一图是MATLAB滤波的结果,第二图是Modelsim仿真滤波输出的结果,第三图两者结果相减。从第三图可以看出两者的计算结果最大有误差为1,这是matlab浮点运算与Modelsim定点运算方式不完全一致带来的差别。
上一篇: 【转】