FIR(Finite Impulse Response)滤波器:有限长单位冲激响应滤波器,又称为非递归型滤波器,是数字信号处理系统中最基本的元件,它可以在保证任意幅频特性的同时具有严格的线性相频特性,同时其单位抽样响应是有限长的,因而滤波器是稳定的系统。因此,FIR滤波器在通信、图像处理、模式识别等领域都有着广泛的应用。(更多介绍网上自行查找数不胜数,在此主要介绍使用部分)
FIR介绍:
FIR滤波器分类:
低通滤波器:低通滤波器是容许低于截止频率的信号通过,但高于截止频率的信号不能通过的滤波。
高通滤波器:高通滤波器,又称低截止滤波器,低阻滤波器,允许高于某一截频的频率通过,而大大衰减较低频率的一种滤波器 ,它去掉了信号中不必要的低频成分或者说去掉了低频干扰。
带通滤波器:是指能通过某一频率范围内的频率分量,但将其他范围的频率分量衰减到极低水平的滤波器,与带阻滤波器的概念相对。
带阻滤波器:是指能通过大多数频率分量,但将某些范围的频率分量衰减到极低水平的滤波器,与带通滤波器的概念相。
程序介绍:分别使用两个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为相加后的结果!
IP核介绍:
接着点击左上角第二个选项,即 Edit Coefficient Set 选项,进入如下所示界面,对滤波器参数进行设置。
IP核介绍:
Column Configuration : 指定的DSP中列的长度
Inter-Column Pipe Length : 多个DSP之间中插入的管道阶数
设计一个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阶)。
特点:矩形窗使用最多,习惯上不加窗就是使信号通过了矩形窗。这种窗的优点是主瓣比较集中,缺点是旁瓣较高,并有负旁瓣,导致变换中带进了高频干扰和泄漏,甚至出现负谱现象。频率识别精度最高,幅值识别精度最低,所以矩形窗不是一个理想的窗。
应用:如果仅要求精确读出主瓣频率,而不考虑幅值精度,则可选用矩形窗,例如测量物体的自振频率等,也可以用在阶次分析中。
特点:主瓣加宽并降低,旁瓣则显著减小,从减小泄漏观点出发,汉宁窗优于矩形窗。但汉宁窗主瓣加宽,相当于分析带宽加宽,频率分辨力下降。它与矩形窗相比,泄漏、波动都减小了,并且选择性也提高。
应用:汉宁窗是很有用的窗函数。如果测试信号有多个频率分量,频谱表现的十分复杂,且测试的目的更多关注频率点而非能量的大小,需要选择汉宁窗。如果被测信号是随机或者未知的,选择汉宁窗。
特点:与汉宁窗都是余弦窗,又称改进的升余弦窗,只是加权系数不同,使旁瓣达到更小。但其旁瓣衰减速度比汉宁窗衰减速度慢。
应用:与汉明窗类似,也是很有用的窗函数。
特点:是一种指数窗。主瓣较宽,故而频率分辨力低;无负的旁瓣,第一旁瓣衰减达一55dB。常被用来截短一些非周期信号,如指数衰减信号等。
应用:对于随时间按指数衰减的函数,可采用指数窗来提高信噪比。
特点:二阶升余弦窗,主瓣宽,旁瓣比较低,但等效噪声带宽比汉宁窗要大一点,波动却小一点。频率识别精度最低,但幅值识别精度最高,有更好的选择性。
应用:常用来检测两个频率相近幅度不同的信号。
特点:平顶窗在频域时的表现就象它的名称一样有非常小的通带波动。
应用:由于在幅度上有较小的误差,所以这个窗可以用在校准上。
将下方数据代入到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 为滤波后的效果。
使用quartus与vivado的IP核配置进行滤波器设置的其道理一样,网上文案一大堆在此不做多介绍。