当前位置:网站首页>基于FPGA的FIR滤波器的实现(5)— 并行结构FIR滤波器的FPGA代码实现

基于FPGA的FIR滤波器的实现(5)— 并行结构FIR滤波器的FPGA代码实现

2022-08-11 05:53:00 南邮学渣

三、并行结构的FPGA实现

并行结构,并行实现滤波器的累加运算,即并行将具有对称系数的输入数据进行相加,而后采用多个乘法器并行实现系数与数据的乘法运算,最后将所有乘积结果相加输出。这种结构具有最高的运行速度,因不需要累加运算,因此系数时钟频率可以与数据输出时钟频率保持一致。
与串行结构相比,更高的速度付出的是成倍的硬件资源的代价。
在这里插入图片描述

设计实例

设计一个15阶的低通线性相位FIR滤波器,采用布莱克曼窗函数设计,截止频率为500Hz,采样频率为2000Hz;采用FPGA实现并行结构的滤波器,系数的量化位数为12bit,输入数据位宽为12bit,输出数据位宽为29bit,系统时钟2000Hz。

1、matlab参数与数据

FIR滤波器参数与串行结构实现的完全相同,请参照前一篇文章
链接: 基于FPGA的FIR滤波器的实现(4)— 串行结构FIR滤波器的FPGA代码实现

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://blog.csdn.net/qq_52450571/article/details/126275030