利用FPGA实现全串行低通FIR滤波器

这篇具有很好参考价值的文章主要介绍了利用FPGA实现全串行低通FIR滤波器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

利用FPGA实现全串行低通FIR滤波器

设计一个15阶(长度为16)的具有线性相位低通FIR滤波器,采用布拉克曼窗函数设计,截止频率为500HZ,抽样频率为2000HZ;采用FPGA实现全串行FIR滤波器,系数的量化位数为12比特,输入数据位数为12比特,输出数据位数为29比特,系统时钟为16KHZ

设计思路:首先采用MATLAB根据要求设计出滤波器系数,并仿真出系数量化前后的幅频响应曲线;根据图4-17所示的结构采用Verilog HDL语言再FPGA中实现该滤波器;采用MATLAB仿真出具有白噪声特性的输入信号,以及由200HZ及800HZ单频信号合成的输入信号;将仿真的输入信号作为Verilog HDL测试输入信号,用MOdelSim仿真滤波器输出信号。采用MATLAB分析滤波器输出信号,比较输入输出信号的时域及频域图。

1.采用MATLAB设计出滤波器系数

function Q12 = My_E4_7_fir8
%设置参数
N = 15; %N阶 长度为N+1 滤波器
fc = 500;   %截止频率为500HZ
fs = 2000;  %抽样频率为2000HZ
wn = fc/(fs/2); %归一化截止频率
ftype = 'low';  %滤波器类型
window = blackman(N+1)';   %布拉克曼窗函数 与滤波器长度一样
B = 12;     %量化位数
%用firl函数设计低通滤波器
b = fir1(N,wn,ftype,window);
Q12 = round(b/max(abs(b))*(2^(B-1)-1));     %12比特量化
%求其幅度响应 
m_blcak = 20*log(abs(fft(b,1024)))/log(10); 
m12_black = 20*log(abs(fft(Q12,1024)))/log(10); 
%保证最大值相同(都为零),好进行比较
m_blcak = m_blcak - max(m_blcak);
m12_black = m12_black - max(m12_black);
%figure(2)
%x_f = [0:fs/length(m_blcak):fs-fs/length(m_blcak)];
%plot(x_f,m_blcak,'-',x_f,m12_black,'--');
%xlabel('频率(Hz)');ylabel('幅度(dB)');
%legend('未量化','12bit量化');
%grid;
%figure(3)
%x_f_2 = [0:fs/length(m_blcak):fs/2];
%plot(x_f_2,m_blcak(1:length(x_f_2)),'-',x_f_2,m12_black(1:length(x_f_2)),'--');
%xlabel('频率(HZ)');ylabel('幅度(dB)');
%legend('未量化','12bit量化');
%grid;

fpga fir滤波器,数字滤波器的MATLAB与FPGA实现,fpga开发,matlab

图1 系数量化前后幅频响应

2.采用MATLAB仿真滤波器测试数据及滤波后的输出数据

  采用MATLAB仿真滤波器测试数据、仿真测试数据经滤波器滤波后的输出数据,以便与FPGA实现后的结果进行比较,并判断FPGA实现的正确性。首先需要仿真生成12比特量化的、抽样频率为2000HZ的高斯噪声,以及两个频率分别为200HZ与800HZ信号的合成信号,并将仿真的数据转化成二进制数据写入文本文件中,供FPGA仿真程序读取;然后,仿真出量化后的数据经滤波器滤波后的输出结果。

%定义参数

fs = 2000;  %抽样频率
f1 = 200;   %信号1频率
f2 = 800;   %信号2频率
N = 12;     %量化位数为12
t = 0:1/fs:1; %数据采样时间长度
%生成信号
s1 = sin(2*pi*f1*t);    %信号1
s2 = sin(2*pi*f2*t);    %信号2
s = s1 + s2;    %合成信号
%产生随机序列信号
noise = randn(1,length(t)); %生成均值为0,方差为1,大小为[1,length(t)]的高斯噪声
%归一化处理
s = s/max(abs(s));
noise = noise/max(abs(noise));
%12比特量化
s_12 = round(s*(2^(N-1)-1));  %-2^11——2^11
noise_12 = round(noise*(2^(N-1)-1));
%调用自己设计的滤波器对信号进行滤波
Q12=My_E4_7_fir8;
Filter_noise=filter(Q12,1,noise_12);  %由于是filter滤波器,所以b=Q12,a=1
Filter_s=filter(Q12,1,s_12);
%求信号的幅频响应
m_s = 20*log(abs(fft(s,1024)))/log(10);    m_s = m_s - max(m_s); 
m_noise = 20*log(abs(fft(noise,1024)))/log(10);    m_noise = m_noise - max(m_noise);
%求滤波后信号的幅频响应
m_filter_s = 20*log(abs(fft(Filter_s,1024)))/log(10);    m_filter_s = m_filter_s - max(m_filter_s); 
m_filte_noise = 20*log(abs(fft(Filter_noise,1024)))/log(10);    m_filte_noise = m_filte_noise - max(m_filte_noise);
%求滤波器的幅频响应
m_Q12 = 20*log(abs(fft(Q12,1024)))/log(10);    m_Q12 = m_Q12 - max(m_Q12); 
%设置幅频响应的横坐标单位为Hz
x_f = 0:fs/length(m_s):fs/2; 
%只显示正频率部分的幅频响应
m_s = m_s(1:length(x_f));
m_Q12 = m_Q12(1:length(x_f));
m_noise = m_noise(1:length(x_f));
m_filter_s = m_filter_s(1:length(x_f));
m_filte_noise = m_filte_noise(1:length(x_f));

%画幅频响应曲线

figure(2)
subplot(211)
plot(x_f,m_s,'-.',x_f,m_filter_s,'-',x_f,m_Q12,'--');
xlabel('频率(HZ)');ylabel('幅度(dB)');title('Matlab仿真合成单频信号滤波前后的频谱');
legend('输入信号频谱','滤波后的频谱','滤波器频谱');
grid;
subplot(212)
plot(x_f,m_noise,'-.',x_f,m_filte_noise,'-',x_f,m_Q12,'--');
xlabel('频率(HZ)');ylabel('幅度(dB)');title('Matlab仿真白噪声信号滤波前后的频谱');
legend('输入信号频谱','滤波后的频谱','滤波器频谱');
grid;
%将生成的数据以十进制数据格式写入txt文件中

fid=fopen('D:\Work_directory\MATLAB\Digital_filter_MATLAB\Chapter_4\E4_7\E4_7_Int_noise_12.txt','w');
fprintf(fid,'%8d\r\n',noise_12);
fprintf(fid,';'); 
fclose(fid);
fid=fopen('D:\Work_directory\MATLAB\Digital_filter_MATLAB\Chapter_4\E4_7\E4_7_Int_s_12.txt','w');
fprintf(fid,'%8d\r\n',s_12);
fprintf(fid,';'); 
fclose(fid);
%将生成的数据以二进制数据格式写入txt文件中
fid=fopen('D:\Work_directory\MATLAB\Digital_filter_MATLAB\Chapter_4\E4_7\E4_7_Bin_noise_12.txt','w');
for i=1:length(noise_12)
​    B_noise=dec2bin(noise_12(i)+(noise_12(i)<0)*2^N,N);   %补码形式for j=1:N
​       if B_noise(j)=='1'
​           tb=1;else
​           tb=0;endfprintf(fid,'%d',tb);endfprintf(fid,'\r\n');
end
fprintf(fid,';'); 
fclose(fid);
fid=fopen('D:\Work_directory\MATLAB\Digital_filter_MATLAB\Chapter_4\E4_7\E4_7_Bin_s_12.txt','w');
for i=1:length(s_12)
​    B_s=dec2bin(s_12(i)+(s_12(i)<0)*2^N,N)for j=1:N
​       if B_s(j)=='1'
​          tb=1;else
​           tb=0;endfprintf(fid,'%d',tb);endfprintf(fid,'\r\n');
end
fprintf(fid,';'); 
fclose(fid);

fpga fir滤波器,数字滤波器的MATLAB与FPGA实现,fpga开发,matlab

图2 MATLAB仿真的信号滤波前后的频谱图

  不难发现,800HZ频率的信号几乎被滤掉了。

3.采用Verilog HDL语言设计全串行低通FIR滤波器

`

module My_FirlFullSerial(
//滤波器系数为12位量化 输入数据也是12位 且都是有符号数 都是以补码形式输入(计算机中数都是以补码形式存在并进行加减)
//使用到的是15阶FIR滤波器 长度为N=16 
//由FIR滤波器计算公式  最终输出的数据位宽 > (16*2^12)*2^12 = 2^(4+12+12) = 2^28 
//所以滤波后的数据保险起见可以为29位

	input clk	,		//时钟信号 时钟频率为16KHZ
	input rst	,		//复位信号
	input  signed[11:0]	Xin,	//输入数据 数据输入频率为2KHZ
	output signed[28:0] Yout	//滤波后的输出数据 
);

//实例化有符号数乘法器IP核 mult
reg signed [11:0] coe;	//滤波器系数
wire signed [12:0] add_s;	//输入数据中 对称数据的和 第n个和最后N-n个
wire signed [24:0] Mout;	//两项乘积数的和

mult Umult(      //乘法器IP核
	.clock(clk),	//时钟信号
	.dataa(coe),	
	.datab(add_s),
	.result(Mout)
);

//实例化有符号数加法器IP核,对输入数据进行1比特符号位扩展,输出结果为13比特数据
//由于结果为13比特 ,所以把输入数据都扩展为了13位
reg signed [12:0] add_a;
reg signed [12:0] add_b;
adder Uadder(	//加法器IP核 
	.dataa(add_a),
	.datab(add_b),
	.result(add_s)
);
//时钟计数器 每计数八次为一次循环
reg [2:0] count;
always @(posedge clk or negedge rst)
	if(!rst)
		count <= 3'd0;
	else count <= count + 1'd1;

//给每一个数据寄存器赋值 共16个
reg [11:0] Xin_reg[15:0];	//输入数据寄存器 
reg [3:0] i,j;	
always @(posedge clk or negedge rst)
	if(!rst) begin    //复位时每个寄存器都清零
		for(i=0;i<15;i=i+1)
			Xin_reg[i] <= 12'd0;
	end
	else if(count == 3'd7) begin	//当一次循环结束时 开始加载下一个数据 并所有数据右移
			for(j=0;j<15;j=j+1)
				Xin_reg[j+1] <= Xin_reg[j];
			Xin_reg[0] <= Xin;
		end
	else ;
	
//将对称系数的输入数据相加,同时将对应的滤波器系数送入乘法器
//需要注意的是,下面程序只用了了一个加法器及一个乘法器
//以8倍率的速率调用乘法器IP核,由于滤波器长度为16比特,系数具有一定的对称性
//故可在一个数据周期内完成所有8个滤波器系数与数据的乘法运算
//为了保证加法运算不溢出,输入、输出数据均扩展为13比特
always @(posedge clk or negedge rst)
	if(!rst) begin
		coe <= 12'd0;
		add_a <= 13'd0;
		add_b <= 13'd0;
	end
	else if(count == 3'd0) begin
		coe <= 12'd0;	//第一个滤波器及最后一个滤波器系数的值
		add_a <= {Xin_reg[0][11],Xin_reg[0]}; 	//第一个滤波器系数对应的输入值 并将12位的输入数据扩展为13位
		add_b <= {Xin_reg[15][11],Xin_reg[15]};	//若最高位为1 则补1 最高位为零 则补零 总之就是补高位的值
	    end
	else if(count == 3'd1) begin
		coe <= 12'hffd;	//c1
		add_a <= {Xin_reg[1][11],Xin_reg[1]}; 	
		add_b <= {Xin_reg[14][11],Xin_reg[14]};	
	    end
	else if(count == 3'd2) begin
		coe <= 12'h00f;	
		add_a <= {Xin_reg[2][11],Xin_reg[2]}; 	
		add_b <= {Xin_reg[13][11],Xin_reg[13]};	
	    end
	else if(count == 3'd3) begin
		coe <= 12'h02e;	
		add_a <= {Xin_reg[3][11],Xin_reg[3]}; 	
		add_b <= {Xin_reg[12][11],Xin_reg[12]};	
	    end
	else if(count == 3'd4) begin
		coe <= 12'hf8b;	
		add_a <= {Xin_reg[4][11],Xin_reg[4]}; 	
		add_b <= {Xin_reg[11][11],Xin_reg[11]};	
	    end
	else if(count == 3'd5) begin
		coe <= 12'hef9;	
		add_a <= {Xin_reg[5][11],Xin_reg[5]}; 	
		add_b <= {Xin_reg[10][11],Xin_reg[10]};	
	    end
	else if(count == 3'd6) begin
		coe <= 12'h24e;	
		add_a <= {Xin_reg[6][11],Xin_reg[6]}; 	
		add_b <= {Xin_reg[9][11],Xin_reg[9]};	
	    end
	else begin
		coe <= 12'h7ff;	
		add_a <= {Xin_reg[7][11],Xin_reg[7]}; 	
		add_b <= {Xin_reg[8][11],Xin_reg[8]};	
	    end
		
//对滤波器系数与输入数据的乘法结果进行累加,并输出滤波后的数据
//考虑到乘法器及累加器的延时,需要在计数器count=2时对累计器清零,同时输出滤波器结果
//类似的延时长度一方面可通过精确计算获取,但更好的方法是通过行为仿真查看
reg signed [28:0] sum;
reg signed [28:0] yout;
always @(posedge clk or negedge rst)
	if(!rst) begin 
		sum <= 29'd0;
		yout <= 29'd0;
	end
	else if(count == 2 ) begin  //计数到2的时候 说明一次循环结束
			yout <= sum;	//将累加值保存到yout变量中
			sum = 29'd0;	//累加值重新清零	
			sum = sum + Mout;
		end
	else sum = sum + Mout;

assign Yout = yout;	
	
endmodule

4.编写Verilog HDL测试激励文件

`timescale 1 ns/ 1 ns //设置仿真时间单位:ns
module FirFullSerial_vlg_tst();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg [11:0] Xin;
reg clk;
reg rst;
wire clk_data; //数据时钟,速率为系统时钟clk的1/8;
// wires                                               
wire [28:0]  Yout;

// assign statements (if any)                          
FirFullSerial i1 (
// port map - connection between master ports and signals/registers   
	.Xin(Xin),
	.Yout(Yout),
	.clk(clk),
	.rst(rst)
);

parameter clk_period=62500; //设置时钟信号周期(频率):16kHz
parameter clk_period_data=clk_period*8;
parameter clk_half_period=clk_period/2;
parameter clk_half_period_data=clk_half_period*8;
parameter data_num=2000;  //仿真数据长度
parameter time_sim=data_num*clk_period; //仿真时间

initial
begin
	//设置时钟信号初值
	clk=1;
	//clk_data=1;
	//设置复位信号
	rst=1;
	#200000 rst=0;
	//设置仿真时间
	#time_sim $finish;
	//设置输入信号初值
	Xin=12'd10;
end

//产生时钟信号
always                                                 
	#clk_half_period clk=~clk;

reg [2:0] cn_clk=3'd0;
always @(posedge clk) cn_clk <= cn_clk + 3'd1;
assign clk_data = cn_clk[2];

//从外部TX文件(SinIn.txt)读入数据作为测试激励
integer Pattern;
reg [11:0] stimulus[1:data_num];
initial
	begin
		//文件必须放置在"工程目录\simulation\modelsim"路径下
		//readmemb("E4_7_Bin_noise.txt",stimulus);
		$readmemb("E4_7_Bin_s.txt",stimulus);
		Pattern=0;
		repeat(data_num)
			begin 
				@(posedge clk_data);
				Pattern=Pattern+1;
				Xin=stimulus[Pattern];
			end
	end

//将仿真数据dout写入外部TXT文件中(out.txt)
integer file_out;
initial 
begin
   //文件放置在"工程目录\simulation\modelsim"路径下                                                  
	//file_out = fopen("E4_7_Noiseout.txt");
	file_out = fopen("E4_7_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;                //将dout转换成有符号数据
assign rst_write = clk_data & (!rst);//产生写入时钟信号,复位状态时不写入数据
always @(posedge rst_write )
	$fdisplay(file_out,"%d",dout_s);
endmodule

5.利用Modelsim对FPGA程序进行功能和时序仿真

6. 编写MATLAB程序,分析FPGA中输出数据是否与MATLAB仿真中相同

7.总结

  看完书本这部分内容,几乎都自己重新写了一遍,算是大概了解了这个流程。虽然由于自身技术原因,利用FPGA仿真那部分操作出了点问题,现在还不怎么明白,所以5、6节我没加上去内容。总体来说还可以文章来源地址https://www.toymoban.com/news/detail-723777.html

到了这里,关于利用FPGA实现全串行低通FIR滤波器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    并行结构,并行实现滤波器的累加运算,即并行将具有对称系数的输入数据进行相加,而后采用多个乘法器并行实现系数与数据的乘法运算,最后将所有乘积结果相加输出。这种结构具有最高的运行速度,因不需要累加运算,因此系数时钟频率可以与数据输出时钟频率保持一

    2024年02月03日
    浏览(39)
  • 【Verilog 教程】7.3 Verilog 串行 FIR 滤波器设计

    串行 FIR 滤波器设计 设计说明 设计参数不变,与并行 FIR 滤波器参数一致。即,输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号,经过 FIR 滤波器后,高频信号 7.5MHz 被滤除,只保留 250KMHz 的信号。 串行设计,就是在 16 个时钟周期内对 16 个延时数据分时依次进行乘法、加法运算

    2024年02月06日
    浏览(32)
  • FIR滤波器的FPGA实现【IP核实现版】

    本文使用FPGA来实现FIR滤波器设计,设计中使用的DDS、乘法器与FIR滤波器均采用IP core进行实现,实现效果是将3MHz和4MHz的正弦信号混频后使用FIR低通滤波器滤除7MHz信号得到1MHz的信号。 首先用两个DDS核生成3MHz以及4MHz的正弦波信号。 注意:此处的dds的命名要和代码中对应,系统

    2024年02月04日
    浏览(37)
  • FIR内插滤波器的FPGA实现(一)-matlab实现

    FIR内插滤波器是一种基本的插值方法,主要有两个步骤: 1)在输入的每一个初始采样中间插入L个零点; 2)插零后的数据经过低通滤波器。 运行结果如图(时域、频域): 我们的目标是把采样频率提升五十倍。 得到的频域图: 可以看出内插零点在频域会实现频谱扩展,因此

    2024年02月03日
    浏览(37)
  • 解析使用FPGA逻辑实现FIR滤波器的几种架构

    有限脉冲响应(finite impulse response,FIR)数字滤波器         FIR滤波器的实质就是输入序列与系统脉冲响应的卷积,即:         其中,N为滤波器的阶数,也即抽头数;x(n)为第n个输入序列;h(n)为FIR滤波器的第n级抽头系数。         FIR滤波器基本结构如下:      

    2024年02月08日
    浏览(28)
  • 数字信号处理-10-并行FIR滤波器MATLAB与FPGA实现

    本文介绍了设计滤波器的FPGA实现步骤,并结合杜勇老师的书籍中的并行FIR滤波器部分进行一步步实现硬件设计,对书中的架构做了复现以及解读,并进行了仿真验证。 FIR滤波器的结构形式时,介绍了直接型、级联型、频率取样型和快速卷积型4种。在FPGA实现时,最常用的是最

    2023年04月09日
    浏览(35)
  • FPGA 的数字信号处理:Verilog 实现简单的 FIR 滤波器

    该项目介绍了如何使用 Verilog 实现具有预生成系数的简单 FIR 滤波器。 不起眼的 FIR 滤波器是 FPGA 数字信号处理中最基本的模块之一,因此了解如何将具有给定抽头数及其相应系数值的基本模块组合在一起非常重要。因此,在这个关于 FPGA 上 DSP 基础实用入门的教程中,将从一

    2024年02月09日
    浏览(36)
  • FIR滤波器简述及FPGA仿真验证

    数字滤波器的设计,本项目做的数字滤波器准确来说是FIR滤波器。 FIR滤波器(有限冲激响应滤波器),与另一种基本类型的数字滤波器——IIR滤波器(无限冲击响应滤波器)相对应,其实就是将所输入的信号都看成是离散的,用离散的冲击信号代替实际的信号。对于FIR滤波器

    2024年02月09日
    浏览(33)
  • FPGA 的 DSP:Verilog 中的简单 FIR 滤波器

    本项目介绍如何用 Verilog 实现一个带有预生成系数的简单 FIR 滤波器。 简陋的 FIR 滤波器是 FPGA 数字信号处理中最基本的构建模块之一,因此了解如何利用给定的抽头数和相应的系数值组装一个基本模块非常重要。因此,在这个关于在 FPGA 上入门 DSP 基础知识的实用方法迷你系

    2024年03月17日
    浏览(31)
  • 图像处理之理想低通滤波器、巴特沃斯低通滤波器和高斯低通滤波器的matlab实现去噪

    一、前言 在一幅图像中, 低频部分对应图像变化缓慢的部分即图像大致外观和轮廓。高频部分对应图像变换剧烈的部分即图像细节(注意图像的噪声属于高频部分) 。 低通滤波器的功能是让低频率通过而滤掉或衰减高频,其作用是过滤掉包含在高频中的噪声。即 低通滤波的效

    2023年04月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包