基于FPGA的FIR调试

FIR介绍:

FIR(Finite Impulse Response)滤波器:有限长单位冲激响应滤波器,又称为非递归型滤波器,是数字信号处理系统中最基本的元件,它可以在保证任意幅频特性的同时具有严格的线性相频特性,同时其单位抽样响应是有限长的,因而滤波器是稳定的系统。因此,FIR滤波器在通信、图像处理、模式识别等领域都有着广泛的应用。(更多介绍网上自行查找数不胜数,在此主要介绍使用部分)


FIR结构与公式介绍:

FIR介绍:

        FIR又叫有限长单位冲激响应滤波器,在通信、图像处理、模式识别等领域都有着广泛的应用,由于 FIR 滤波器处理的是数字信号,所以模拟信号在进入 FIR 滤波器前,需要先经过 AD 器件进行模数转换将模拟信号转化为数字信号,而为了让信号处理不发生失真,信号的采样速度必须满足奈奎斯特采样定理,一般取信号最高频率的 4 到 5 倍作为采样频率。
        由于 FIR 滤波器处理的是数字信号,所以模拟信号在进入 FIR 滤波器前,需要先经过 AD 器件进行模 数转换,将模拟信号转化为数字信号。而为了让信号处理不发生失真,信号的采样速度必须满足奈奎斯特 采样定理,一般取信号最高频率的 4 5 倍作为采样频率。
FIR结构:

基于FPGA的FIR调试_第1张图片

FIR公式:
FIR 滤波器信号处理如下公式所示,其中 xin n )是输入的信号, C/a n )为 FIR 滤波系数, yout n )为滤 波后的信号。N FIR 滤波器的抽头数,滤波器阶数为 N-1.

基于FPGA的FIR调试_第2张图片

 FIR滤波器分类:

低通滤波器:低通滤波器是容许低于截止频率的信号通过,但高于截止频率的信号不能通过的滤波。

高通滤波器:高通滤波器,又称低截止滤波器,低阻滤波器,允许高于某一截频的频率通过,而大大衰减较低频率的一种滤波器 ,它去掉了信号中不必要的低频成分或者说去掉了低频干扰。

带通滤波器:是指能通过某一频率范围内的频率分量,但将其他范围的频率分量衰减到极低水平的滤波器,与带阻滤波器的概念相对。

带阻滤波器:是指能通过大多数频率分量,但将某些范围的频率分量衰减到极低水平的滤波器,与带通滤波器的概念相。

基于FPGA的FIR调试_第3张图片

一、使用verilog建立带有杂波的波形.(测试使用)

基于FPGA的FIR调试_第4张图片

 程序介绍:分别使用两个rom输出不同频率,进行相加。

 频率计算:使用时钟/采样点=真实频率。 

module top (
	input	wire	clk,
	input	wire	rst_n
);

//------------------------------------------------------------------------------
//----------- Registers Declarations -------------------------------------------
//------------------------------------------------------------------------------
reg  [9:0] 	addr_1;
reg  [9:0] 	addr_2;
reg  [14:0] data_sum;

//------------------------------------------------------------------------------
//----------- Wired signal declaration -----------------------------------------------
//------------------------------------------------------------------------------
wire [13:0] data_1;
wire [13:0] data_2;


always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
		begin 
			addr_1	<=	10'd0;
			addr_2	<=	10'd0;
		end 
	else 
		begin 
			addr_1	<=	addr_1+10'd1;    //一个正选波采样点为 1024,输出正选波频50/1024=48.82Khz
			addr_2	<=	addr_2+10'd4;    //一个正选波采样点为 256,输出正选波频率  50/256=488Khz
		end 
end 

always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
		data_sum	<=	15'd0;
	else 
		data_sum	<=	data_1	+	data_2;
end 

rom_1 u_rom_1(
	.address			(addr_1			),
	.clock			    (clk			),
	.q					(data_1			)
	);

rom_1 u_rom_2(
	.address			(addr_2			),
	.clock			    (clk			),
	.q					(data_2			)
	);

endmodule 

仿真结果:data_sum为相加后的结果!

基于FPGA的FIR调试_第5张图片

二、使用Quartus建立FIRip核使用

IP核介绍

Step1 :  用于对 IP 核进行配置.
Step2 用于配置仿真,如生成仿真模型.
Step3 用于生成 FIR IP.
这里点击 Step1 Parameterize).

基于FPGA的FIR调试_第6张图片

Number of Input Channels :输入数据通道数量,我们只有一路音频输入数据,这里保持默认值 1.
Input Number System :输入数据系统,此处保持默认值 Signed Binary (有符号二进制).
Input Bit Width :输入数据位宽,此处的设置和音频数据位宽保持一致,即 16 位.
Coefficients Bit Width :系数位宽,与输入数据位宽保持一致,设置为 16 其余选项保持默认即可.

基于FPGA的FIR调试_第7张图片

 接着点击左上角第二个选项,即 Edit Coefficient Set 选项,进入如下所示界面,对滤波器参数进行设置。

基于FPGA的FIR调试_第8张图片

Filetr Type: (滤波器类型):由于有效的音频信号一般频率较低,而噪声一般音频较高,所以此处选择 低通滤波器(Low Pass );
Window Type: (窗函数类型):该选项栏中共有 4 个选项,选择一种窗函数后,点击 apply 按键,就会 在 Frequency Response (频率响应)界面显示对应窗函数的滤波器频率响应曲线,根据四种频率响应曲线选 择最符合需求的窗函数。这里因为 Hamming (哈明窗)的频率响应曲线到达截止频率时,衰减了 60dB 左 右,且频率响应曲线下降得更快,所以在 Window Type 选项栏中选择 Hamming 窗函数;
Coefficients: (抽头系数):该参数值越大,滤波的效果越好,但是耗用的资源越多,这里设置数值为 32;
Sample Rate: (采样率):此值和音频数据的采样率保持一致,即 48kHz ,对应科学计数法为 4.8E4
Cutoff Freq: (截止频率):本实验中为低通滤波,截止频率设置为 5kHz ,对应科学计数法为 5.0E3

三、使用vivado建立FIRip核使用

IP核介绍

基于FPGA的FIR调试_第9张图片

基于FPGA的FIR调试_第10张图片

Select Source : 系数来源
Coefficient Vector : 矢量系数
Coefficient File : 系数文件
Number of Coefficient Sets : 系数集的数量选择
Use Reloadable Coefficients : 重新加载系数
Filter Type : 滤波器类型
Rate Change Type : 数据变化类型
Interpolation Rate Value : 插值速度
Decimation Rate Value : 抽取速度
Zero Pack Factor : 零收拾因素
基于FPGA的FIR调试_第11张图片
Channel Sequence : 频道序列
Number of Channels : 频道数
Select Sequence : 模式选择
Sequence ID List : 模式列表
Number of Paths : 路径数
Sample Period : 采样周期
Input Sampling Frequency : 采样频率
Clock Frequency : 时钟频率
基于FPGA的FIR调试_第12张图片

Coefficient Type : 系数符号
Quantization : 量化
Coefficient Width : 宽度系数
Best Precision Fraction Length : 最佳精度
Coefficient Fractional Bits : 系数的小数位
Coefficient Structure : 系数结构
Input Data Type : 数据符号
Input Data Width : 数据宽度
Input Data Fractional Bits : 输入的数据小数位
Output Rounding Mode : 输出舍入模式选择
Output Width : 输出位宽
基于FPGA的FIR调试_第13张图片

Filter Architecture : 过滤器结构单元
Goal : 选择指定区域优化速度
Select Optimization : 优化选择
List : 优化列表
Data Buffer Type : 数据缓存类型选择
Coefficient Buffer Type : 系数缓存类型选择
Input Buffer Type : 输入缓存类型选择
Output Buffer Type : 输出缓存类型选择
Preference For Other Storage : 其他缓存首选项
Multi-Column Support : 指定在多个DSP切片列上实现滤波器的模式
基于FPGA的FIR调试_第14张图片

Column Configuration : 指定的DSP中列的长度

Inter-Column Pipe Length : 多个DSP之间中插入的管道阶数

四、使用matlab配置FIR滤波器参数系数

设计一个16阶的低通滤波器

基于FPGA的FIR调试_第15张图片

基于FPGA的FIR调试_第16张图片

参数选择:选用低通滤波器,使用波纹设计法,阶数自定义了16个(当然阶数越多滤波效果越好),FS的采样频率是50M,通过频率0.5M,截至频率为1M。
Response Type:选择FIR滤波器的类型:低通、高通、带通和带阻等。

Design Method:FIR滤波器设计方法有多种,最常用的是窗函数设计法(Window)、等波纹设计法(Equiripple)和最小二乘法 (Least-Squares)等。其中窗函数设计法在学校课堂中是重点讲解的,提到FIR滤波器肯定会想到hamming、kaiser窗,但是实际应用中却很少使用,因为如果采用窗函数设计法,达到所期望的频率响应,与其它方法相比往往阶数会更多;而且窗函数设计法一般只参照通频带wp、抑制频带ws 和理想增益来设计滤波器,但是实际应用中通频带和抑制带的波纹也是需要考虑的,那在这种情况下,采用等波纹设计法就非常适用了。
Frequency Specification:设置频率响应的参数,包括采样频率Fs、通带频率Fpass和阻带频率Fstop。

Filter Order:设置滤波器的阶数,这个选项直接影响滤波器的性能,阶数越高,性能越好,但是相应在FPGA实现耗用的资源需要增多。在这个设置中提供2个选项:Specify order和Minimum order,Specify order是工程师自己确定滤波器的阶数,Minimum order是让工具自动确定达到期望的频率相应所需要的最小阶数,因此具体选择哪个选项得视实际情况而定了,(这里我选用16阶)。

矩形窗 Rectangle

特点:矩形窗使用最多,习惯上不加窗就是使信号通过了矩形窗。这种窗的优点是主瓣比较集中,缺点是旁瓣较高,并有负旁瓣,导致变换中带进了高频干扰和泄漏,甚至出现负谱现象。频率识别精度最高,幅值识别精度最低,所以矩形窗不是一个理想的窗。

应用:如果仅要求精确读出主瓣频率,而不考虑幅值精度,则可选用矩形窗,例如测量物体的自振频率等,也可以用在阶次分析中。

汉宁窗 Hanning

特点:主瓣加宽并降低,旁瓣则显著减小,从减小泄漏观点出发,汉宁窗优于矩形窗。但汉宁窗主瓣加宽,相当于分析带宽加宽,频率分辨力下降。它与矩形窗相比,泄漏、波动都减小了,并且选择性也提高。

应用:汉宁窗是很有用的窗函数。如果测试信号有多个频率分量,频谱表现的十分复杂,且测试的目的更多关注频率点而非能量的大小,需要选择汉宁窗。如果被测信号是随机或者未知的,选择汉宁窗。

海明窗 Hamming

特点:与汉宁窗都是余弦窗,又称改进的升余弦窗,只是加权系数不同,使旁瓣达到更小。但其旁瓣衰减速度比汉宁窗衰减速度慢。

应用:与汉明窗类似,也是很有用的窗函数。

高斯窗 Gaussian

特点:是一种指数窗。主瓣较宽,故而频率分辨力低;无负的旁瓣,第一旁瓣衰减达一55dB。常被用来截短一些非周期信号,如指数衰减信号等。

应用:对于随时间按指数衰减的函数,可采用指数窗来提高信噪比。

布莱克曼窗 Blackman

特点:二阶升余弦窗,主瓣宽,旁瓣比较低,但等效噪声带宽比汉宁窗要大一点,波动却小一点。频率识别精度最低,但幅值识别精度最高,有更好的选择性。

应用:常用来检测两个频率相近幅度不同的信号。

平顶窗 Flap Top

特点:平顶窗在频域时的表现就象它的名称一样有非常小的通带波动。

应用:由于在幅度上有较小的误差,所以这个窗可以用在校准上。

将配置完成后的数据导出
        File ---> Export ---> Export ;
基于FPGA的FIR调试_第17张图片

 输入 : > Num=round(Num*400) 取个整基于FPGA的FIR调试_第18张图片

 将下方数据代入到verilog进行乘类加滤波。(无符号)

程序部分
module top (
	input	wire	clk,
	input	wire	rst_n
);

//------------------------------------------------------------------------------
//----------- Registers Declarations -------------------------------------------
//------------------------------------------------------------------------------
reg  [9:0] 	addr_1;
reg  [9:0] 	addr_2;
reg  [14:0] data_sum;
reg  [14:0]  delay_pipeline1  ;
reg  [14:0]  delay_pipeline2  ;
reg  [14:0]  delay_pipeline3  ;
reg  [14:0]  delay_pipeline4  ;
reg  [14:0]  delay_pipeline5  ;
reg  [14:0]  delay_pipeline6  ;
reg  [14:0]  delay_pipeline7  ;
reg  [14:0]  delay_pipeline8  ;
reg  [14:0]  delay_pipeline9  ;
reg  [14:0]  delay_pipeline10 ;
reg  [14:0]  delay_pipeline11 ;
reg  [14:0]  delay_pipeline12 ;
reg  [14:0]  delay_pipeline13 ;
reg  [14:0]  delay_pipeline14 ;
reg  [14:0]  delay_pipeline15 ;
reg  [14:0]  delay_pipeline16 ;
reg  [14:0]  delay_pipeline17 ;

reg signed [22:0] multi_data1 ;//乘积结果
reg signed [22:0] multi_data2 ;
reg signed [22:0] multi_data3 ;
reg signed [22:0] multi_data4 ;
reg signed [22:0] multi_data5 ;
reg signed [22:0] multi_data6 ;
reg signed [22:0] multi_data7 ;
reg signed [22:0] multi_data8 ;
reg signed [22:0] multi_data9 ;
reg signed [22:0] multi_data10 ;
reg signed [22:0] multi_data11 ;
reg signed [22:0] multi_data12 ;
reg signed [22:0] multi_data13 ;
reg signed [22:0] multi_data14 ;
reg signed [22:0] multi_data15 ;
reg signed [22:0] multi_data16 ;
reg signed [22:0] multi_data17 ;
reg signed [22:0] FIR_OUT;

//------------------------------------------------------------------------------
//----------- Wired signal declaration -----------------------------------------------
//------------------------------------------------------------------------------
wire [13:0] data_1;
wire [13:0] data_2;
wire[7:0] coeff1  = 8'd86;  //滤波器系数
wire[7:0] coeff2  = 8'd5;
wire[7:0] coeff3  = 8'd6;
wire[7:0] coeff4  = 8'd6;
wire[7:0] coeff5  = 8'd6;
wire[7:0] coeff6  = 8'd6;
wire[7:0] coeff7  = 8'd6;
wire[7:0] coeff8  = 8'd6;
wire[7:0] coeff9  = 8'd6;
wire[7:0] coeff10 = 8'd6;
wire[7:0] coeff11 = 8'd6;
wire[7:0] coeff12 = 8'd6;
wire[7:0] coeff13 = 8'd6;
wire[7:0] coeff14 = 8'd6;
wire[7:0] coeff15 = 8'd6;
wire[7:0] coeff16 = 8'd5;
wire[7:0] coeff17 = 8'd86;



always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
		begin 
			addr_1	<=	10'd0;
			addr_2	<=	10'd0;
		end 
	else 
		begin 
			addr_1	<=	addr_1+10'd41;    //2m
			addr_2	<=	addr_2+10'd20;    //1m
		end 
end 

always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
		data_sum	<=	15'd0;
	else 
		data_sum	<=	data_1	+	data_2;
end 

always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
	 begin 
		delay_pipeline1  	<=	15'd0;
		delay_pipeline2  	<=	15'd0;
		delay_pipeline3  	<=	15'd0;
		delay_pipeline4  	<=	15'd0;
		delay_pipeline5  	<=	15'd0;
		delay_pipeline6  	<=	15'd0;
		delay_pipeline7  	<=	15'd0;
		delay_pipeline8  	<=	15'd0;
		delay_pipeline9  	<=	15'd0;
		delay_pipeline10 	<=	15'd0;
		delay_pipeline11 	<=	15'd0;
		delay_pipeline12 	<=	15'd0;
		delay_pipeline13 	<=	15'd0;
		delay_pipeline14 	<=	15'd0;
		delay_pipeline15 	<=	15'd0;
		delay_pipeline16 	<=	15'd0;
		delay_pipeline17 	<=	15'd0;
	 end 
	else 
	 begin 
		delay_pipeline1  	<=	data_sum;
		delay_pipeline2  	<=	delay_pipeline1;
		delay_pipeline3  	<=	delay_pipeline2;
		delay_pipeline4  	<=	delay_pipeline3;  	
		delay_pipeline5  	<=	delay_pipeline4;  	
		delay_pipeline6  	<=	delay_pipeline5;  	
		delay_pipeline7  	<=	delay_pipeline6;  	
		delay_pipeline8  	<=	delay_pipeline7;  	
		delay_pipeline9  	<=	delay_pipeline8;  	
		delay_pipeline10 	<=	delay_pipeline9;  	
		delay_pipeline11 	<=	delay_pipeline10; 	
		delay_pipeline12 	<=	delay_pipeline11; 	
		delay_pipeline13 	<=	delay_pipeline12; 	
		delay_pipeline14 	<=	delay_pipeline13; 	
		delay_pipeline15 	<=	delay_pipeline14; 	
		delay_pipeline16 	<=	delay_pipeline15; 	
		delay_pipeline17 	<=	delay_pipeline16; 	
	 end                    
end 

always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
	 begin 
		multi_data1  	<=	23'd0;//乘积结果
		multi_data2  	<=	23'd0;
		multi_data3  	<=	23'd0;
		multi_data4  	<=	23'd0;
		multi_data5  	<=	23'd0;
		multi_data6  	<=	23'd0;
		multi_data7  	<=	23'd0;
		multi_data8  	<=	23'd0;
		multi_data9  	<=	23'd0;
		multi_data10 	<=	23'd0;
		multi_data11 	<=	23'd0;
		multi_data12 	<=	23'd0;
		multi_data13 	<=	23'd0;
		multi_data14 	<=	23'd0;
		multi_data15 	<=	23'd0;
		multi_data16 	<=	23'd0;
		multi_data17 	<=	23'd0;
	 end 
	else 
	 begin 
		multi_data1  	<=	delay_pipeline1	*	coeff1;//乘积结果
		multi_data2  	<=	delay_pipeline2	*	coeff2;
		multi_data3  	<=	delay_pipeline3	*	coeff3;
		multi_data4  	<=	delay_pipeline4	*	coeff4;
		multi_data5  	<=	delay_pipeline5	*	coeff5;
		multi_data6  	<=	delay_pipeline6	*	coeff6;
		multi_data7  	<=	delay_pipeline7	*	coeff7;
		multi_data8  	<=	delay_pipeline8	*	coeff8;
		multi_data9  	<=	delay_pipeline9	*	coeff9;
		multi_data10 	<=	delay_pipeline10	*	coeff10;
		multi_data11 	<=	delay_pipeline11	*	coeff11;
		multi_data12 	<=	delay_pipeline12	*	coeff12;
		multi_data13 	<=	delay_pipeline13	*	coeff13;
		multi_data14 	<=	delay_pipeline14	*	coeff14;
		multi_data15 	<=	delay_pipeline15	*	coeff15;
		multi_data16 	<=	delay_pipeline16	*	coeff16;
		multi_data17 	<=	delay_pipeline17	*	coeff17;
	 end 
end 

always @ (posedge clk or negedge rst_n) begin 
	if (!rst_n)
		FIR_OUT	<=	23'd0;
	else 
		FIR_OUT	<=	multi_data1+multi_data2+multi_data3+multi_data4+multi_data5+multi_data6+multi_data7
		+multi_data8+multi_data9+multi_data10+multi_data11+multi_data12+multi_data13+multi_data14+multi_data15
		+multi_data16+multi_data17;
end 

  
rom_1 u_rom_1(
	.address			(addr_1			),
	.clock			    (clk			),
	.q					(data_1			)
	);

rom_1 u_rom_2(
	.address			(addr_2			),
	.clock			    (clk			),
	.q					(data_2			)
	);

endmodule 

仿真结果: FIR_OUT 为滤波后的效果。

基于FPGA的FIR调试_第19张图片


总结

使用quartus与vivado的IP核配置进行滤波器设置的其道理一样,网上文案一大堆在此不做多介绍。

你可能感兴趣的:(FPGA,verilog)