三、并行结构的FPGA实现
并行结构,并行实现滤波器的累加运算,即并行将具有对称系数的输入数据进行相加,而后采用多个乘法器并行实现系数与数据的乘法运算,最后将所有乘积结果相加输出。这种结构具有最高的运行速度,因不需要累加运算,因此系数时钟频率可以与数据输出时钟频率保持一致。
与串行结构相比,更高的速度付出的是成倍的硬件资源的代价。
设计实例
设计一个15阶的低通线性相位FIR滤波器,采用布莱克曼窗函数设计,截止频率为500Hz,采样频率为2000Hz;采用FPGA实现并行结构的滤波器,系数的量化位数为12bit,输入数据位宽为12bit,输出数据位宽为29bit,系统时钟2000Hz。
1、matlab参数与数据
FIR滤波器参数与串行结构实现的完全相同,请参照前一篇文章
链接: 基于FPGA的FIR滤波器的实现(4)— 串行结构FIR滤波器的FPGA代码实现文章来源:https://www.toymoban.com/news/detail-435364.html
2、使用Verilog编写并行结构的FIR滤波器
- RTL代码(需要先将matlab产生的noise_B和sin_B添加到工程目录下的simulation/modelsim文件夹中)
module FirParallel(
input wire clk,
input wire rst_n,
input signed [11:0]Xin,
output signed [28:0]Yout
);
reg signed[11:0]Xin_reg[15:0];
reg [3:0]i,j;
//将数据存入移位寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
for(i=0;i<15;i=i+1)
Xin_reg[i] = 12'd0;
end
else
begin //与串行结构不同,此处不用判断计数器状态
for(j=0;j<15;j=j+1)
Xin_reg[j+1] <= Xin_reg[j];
Xin_reg[0] <= Xin;
end
//将对称系数的输入数据相加,同时将对应的滤波器系数送入乘法器
//为了进一步提高运行速度,另外增加了一级寄存器
reg signed[12:0]Add_reg[7:0];
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
for(i=0;i<8;i=i+1)
Add_reg[i] = 13'd0;
end
else
begin
for(i=0;i<8;i=i+1)
Add_reg[i] = {Xin_reg[i][11],Xin_reg[i]} + {Xin_reg[15-i][11],Xin_reg[15-i]};
end
//与串行结构不同,另外需要实例化8个乘法器IP核
//实例化有符号数乘法器IP核mult
wire signed[11:0]coe[7:0]; //滤波器为12bit量化数据
wire signed[24:0]Mout[7:0]; //乘法器输出为25bit数据
assign coe[0] = 12'h000;
assign coe[1] = 12'hffd;
assign coe[2] = 12'h00f;
assign coe[3] = 12'h02e;
assign coe[4] = 12'hf8b;
assign coe[5] = 12'hef9;
assign coe[6] = 12'h24e;
assign coe[7] = 12'h7ff;
mult mult_inst0(
.clock(clk),
.dataa(coe[0]),
.datab(Add_reg[0]),
.result(Mout[0])
);
mult mult_inst1(
.clock(clk),
.dataa(coe[1]),
.datab(Add_reg[1]),
.result(Mout[1])
);
mult mult_inst2(
.clock(clk),
.dataa(coe[2]),
.datab(Add_reg[2]),
.result(Mout[2])
);
mult mult_inst3(
.clock(clk),
.dataa(coe[3]),
.datab(Add_reg[3]),
.result(Mout[3])
);
mult mult_inst4(
.clock(clk),
.dataa(coe[4]),
.datab(Add_reg[4]),
.result(Mout[4])
);
mult mult_inst5(
.clock(clk),
.dataa(coe[5]),
.datab(Add_reg[5]),
.result(Mout[5])
);
mult mult_inst6(
.clock(clk),
.dataa(coe[6]),
.datab(Add_reg[6]),
.result(Mout[6])
);
mult mult_inst7(
.clock(clk),
.dataa(coe[7]),
.datab(Add_reg[7]),
.result(Mout[7])
);
//对滤波器系数与输入数据的乘法结果进行累加,并输出滤波后的数据
//与串行结构不同,此处在一个时钟周期内直接将所有乘法器结果相加
reg signed[28:0]sum;
reg signed[28:0]yout;
reg [3:0]k;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
sum = 29'd0;
yout <= 29'd0;
end
else
begin
yout <= sum;
sum = 29'd0;
for(k=0;k<8;k=k+1)
sum = sum + Mout[k];
end
assign Yout = yout;
endmodule
- 仿真测试模块
`timescale 1ns/1ns
module FirParallel_tb;
reg clk;
reg rst_n,write_en;
reg [11:0]Xin;
wire [28:0]Yout;
wire clk_data; //数据时钟,速率为时钟的八分之一
FirParallel FirParallel_inst(
.clk(clk),
.rst_n(rst_n),
.Xin(Xin), //数据输入频率为2khz
.Yout(Yout) //滤波后的输出数据
);
parameter clk_period = 500000; //设置时钟信号周期/频率:2KHz
parameter data_num = 2000; //仿真数据长度
parameter time_sim = data_num*clk_period; //仿真时间
initial clk=1'b1;
always #(clk_period/2) clk=~clk;
initial begin
rst_n=1'b0;
write_en=1'b0;
#20000 rst_n = 1'b1;
write_en=1'b1;
#time_sim $stop;
Xin = 12'd10;
end
//从外部文件读入数据作为测试激励
integer Pattern;
reg [11:0]stimulus[1:data_num];
initial begin
//$readmemb("noise_B.txt",stimulus);
$readmemb("sin_B.txt",stimulus);
Pattern = 0;
repeat(data_num)
begin
Pattern = Pattern + 1;
Xin = stimulus[Pattern];
#clk_period;
end
end
//将仿真数据dout写入外部文件中
integer file_out;
initial begin
//file_out = $fopen("noise_out.txt");
file_out = $fopen("sout.txt");
if(!file_out)
begin
$display("could not open file!");
$finish;
end
end
wire rst_write;
wire signed [28:0]dout_s;
assign dout_s = Yout;
assign rst_write = clk & (rst_n);
always @(posedge rst_write)
$fdisplay(file_out,"%d",dout_s);
endmodule
- 仿真波形图
3、使用matlab将产生的程序进行仿真验证
- M程序:
%E4_7_NoiseAndCarrierOut.M
f1=200; %信号1频率为200Hz
f2=800; %信号2频率为800Hz
Fs=2000; %采样频率为2KHz
N=12; %量化位数
%从文本文件中读取数据
%测试输入数据分别放在Noise_in和S_in变量中
fid=fopen('C:\matlab work\fir1_1\filterCoe\noise.txt','r');
[Noise_in,N_n]=fscanf(fid,'%lg',inf);
fclose(fid);
fid=fopen('C:\matlab work\fir1_1\filterCoe\sin.txt','r');
[S_in,S_n]=fscanf(fid,'%lg',inf);
fclose(fid);
%滤波后的输出结果数据分别放在Noise_out和S_out变量中
fid=fopen('C:\matlab work\fir1_1\filterCoe\noise_out.txt','r');
[Noise_out,N_count]=fscanf(fid,'%lg',inf);
fclose(fid);
fid=fopen('C:\matlab work\fir1_1\filterCoe\sout.txt','r');
%fid=fopen('C:\matlab work\fir1_1\filterCoe\E4_7_Sout.txt','r');
[S_out,S_count]=fscanf(fid,'%lg',inf)
fclose(fid);
%归一化处理
Noise_out=Noise_out/max(abs(Noise_out));
S_out=S_out/max(abs(S_out));
Noise_in=Noise_in/max(abs(Noise_in));
S_in=S_in/max(abs(S_in));
%求信号的幅频响应
out_noise=20*log10(abs(fft(Noise_out,1024))); out_noise=out_noise-max(out_noise);
out_s=20*log10(abs(fft(S_out(150:length(S_out)),1024))); out_s=out_s-max(out_s);
in_noise=20*log10(abs(fft(Noise_in,1024))); in_noise=in_noise-max(in_noise);
in_s=20*log10(abs(fft(S_in,1024))); in_s=in_s-max(in_s);
%滤波器本身的幅频响应
hn=black_fpga;
m_hn=20*log10(abs(fft(hn,1024))); m_hn=m_hn-max(m_hn);
%设置幅频响应的横坐标单位为Hz
x_f=[0:(Fs/length(out_noise)):Fs/2];
%只显示正频率部分的幅频响应
mf_noise=out_noise(1:length(x_f));
mf_s=out_s(1:length(x_f));
mf_in_noise=in_noise(1:length(x_f));
mf_in_s=in_s(1:length(x_f));
mf_hn=m_hn(1:length(x_f));
%绘制幅频响应曲线
figure(1);
subplot(211);
plot(x_f,mf_in_noise,'--',x_f,mf_noise,'-',x_f,mf_hn,'--');
xlabel('频率(Hz)');ylabel('幅度(dB)');title('FPGA仿真白噪声信号滤波前后的频谱');
legend('输入信号频谱','输出信号频谱','滤波器响应');
grid;
subplot(212);
plot(x_f,mf_in_s,'--',x_f,mf_s,'-',x_f,mf_hn,'--');
xlabel('频率(Hz)');ylabel('幅度(dB)');title('FPGA仿真合成单频信号滤波前后的频谱');
axis([0 1000 -100 0]);
legend('输入信号频谱','输出信号频谱','滤波器响应');
grid;
%绘制时域波形
%设置显示数据范围
t=0:1/Fs:50/Fs;t=t*1000;
t_in_noise=Noise_in(1:length(t));
t_in_s=S_in(1:length(t));
t_out_noise=Noise_out(1:length(t));
t_out_s=S_out(1:length(t));
figure(2);
subplot(211);
plot(t,t_in_noise,'--',t,t_out_noise,'-');
xlabel('时间(ms)');ylabel('幅度');title('FPGA仿真白噪声信号滤波前后的时域波形');
legend('输入信号波形','输出信号波形');
grid;
subplot(212);
plot(t,t_in_s,'--',t,t_out_s,'-');
xlabel('时间(ms)');ylabel('幅度');title('FPGA仿真合成单频信号滤波前后的时域波形');
legend('输入信号波形','输出信号波形');
grid;
- 仿真波形图
可以看到,并行结构的FIR滤波器设计成功,并且性能相比于串行结构更好,设计成功。文章来源地址https://www.toymoban.com/news/detail-435364.html
到了这里,关于基于FPGA的FIR滤波器的实现(5)— 并行结构FIR滤波器的FPGA代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!