基于FPGA设计数字滤波器流程
因为工作需要,要在FPGA上实现FIR滤波器,研究了一段时间,记录一下思路。主要流程如下:1,根据使用场景,确定自己想要什么类型的滤波器;2,利用matlab中的FDAtool工具,选择滤波器的参数,查看频率特性。3,利用matlab仿真,模拟信号,查看滤波效果。4,进行滤波器系数量化(供FPGA使用),导出滤波器系数。5,在FPGA中进行设计,利用modelsim进行仿真。一,数字滤波器选择,参
因为工作需要,要在FPGA上实现FIR滤波器,研究了一段时间,记录一下思路。
主要流程如下:
1,根据使用场景,确定自己想要什么类型的滤波器;
2,利用matlab中的FDAtool工具,选择滤波器的参数,查看频率特性。
3,利用matlab仿真,模拟信号,查看滤波效果。
4,进行滤波器系数量化(供FPGA使用),导出滤波器系数。
5,在FPGA中进行设计,利用modelsim进行仿真。
一,数字滤波器选择,参考FIR滤波器和IIR滤波器的区别 - alifpga - 博客园
FIR滤波器
定义:
FIR滤波器是有限长单位冲激响应滤波器,又称为非递归型滤波器,是数字信号处理系统中最基本的元件,它可以在保证任意幅频特性的同时具有严格的线性相频特性,同时其单位抽样响应是有限长的,因而滤波器是稳定的系统。
特点:
- FIR滤波器的最主要的特点是没有反馈回路,稳定性强,故不存在不稳定的问题;
- FIR具有严格的线性相位,幅度特性随意设置的同时,保证精确的线性相位;
- FIR设计方式是线性的,硬件容易实现;
- FIR相对IIR滤波器而言,相同性能指标时,阶次较高,对CPU的性能要去较高。
-
图1 FIR滤波原理图
IIR滤波器
定义:
IIR滤波器是无限脉冲响应滤波器,又称递归型滤波器,即结构上带有反馈环路。
特点:
- IIR数字滤波器的系统函数可以写成封闭函数的形式,具有反馈回路;
- IIR数字滤波器的相位非线性,相位特性不好控制,随截止频率变化而变化,对相位要求较高时,需加相位校准网络;
- IIR滤波器有历史的输出参与反馈,同FIR相比在相同阶数时取得更好的滤波效果;
- IIR数字滤波器采用递归型结构,由于运算中的舍入处理,使误差不断累积,有时会产生微弱的寄生振荡。
- 图2 IIR基础原理图
区别
-
-
稳定性:由于FIR滤波器没有反馈回路,稳定性要强于IIR;
-
相位特性:FIR 为线性相位延迟,IIR 为非线性相位延迟。
-
如下图所示为10Hz的方波信号,采样率为1KHz。
图3 方波信号
FIR滤波器后,滤波后效果图下图所示
图4 FIR滤波效果图
IIR滤波器后,滤波后效果图下图所示
图5 IIR滤波效果图
通过对比不难发现,IIR滤波器存在非线性相位延迟,校正时需要双向滤波进行校正,复杂不易控制;FIR滤波器为线性延迟,可通过左右平移的方式直接校正,误差小。
信号处理速度:FIR的滤波输出取决于当前输入数据和历史输入数据,IIR的滤波输出取决于当前输入数据、历史输入数据和历史输出数据。以基于FPGA硬件的数字滤波器为例,FIR在处理信号时不需等待前一个信号的滤波输出,只需要考虑输入数据便可实时滤波;IIR需要等待上一个信号的滤波输出,存在一定的时间延迟,所以处理速度上没有FIR快。
图6 FIR和IIR滤波对比图
从上面的简单比较可以看到IIR与FIR滤波器各有所长,所以在实际应用时应该从多方面考虑来加以选择。从使用要求上来看,在对相位要求不敏感的场合,如语言通信等,选用IIR较为合适,这样可以充分发挥其经济高效的特点;对于图像信号处理,数据传输等以波形携带信息的系统,则对线性相位要求较高,采用FIR滤波器较好。当然,在实际应用中可能还要考虑更多方面的因素。
二,利用matlab中的FDAtool工具设计数字滤波器。参考FPGA实现FIR滤波器_不休的博客-CSDN博客_fpga 滤波器
1,在matlab命令行输入FDATool,出现FDAtool设计界面。
2,设计一个9阶低通滤波器如下。
3,滤波器系数导出file—>export,然后用以下命令将系数放大、取整。
>> Num
Num =
-0.032520274817651 -0.038393343465240 0.078426769306951 0.287437638322338 0.398431099816101 0.287437638322338 0.078426769306951 -0.038393343465240 -0.032520274817651
取整:
>> sprintf('%.4f ', Num)
Num=round(Num*400)%将系数放大并取整
ans =
-0.0325 -0.0384 0.0784 0.2874 0.3984 0.2874 0.0784 -0.0384 -0.0325
Num =
-13 -15 31 115 159 115 31 -15 -13
>> Num=Num+20%将系数符号变成正的,便于FPGA使用
Num =
7 5 51 135 179 135 51 5 7
4,利用matlab进行仿真测试。
clear all;
Fs = 10000; %采样频率决定了两个正弦波点之间的间隔
N = 4096; %采样点数
N1 = 0 : 1/Fs :N/Fs-1/Fs;
x1 = sin(1000*2*pi*N1);
x2 = sin(3000*2*pi*N1);
x3 = sin(4000*2*pi*N1);
in = x1 + x2 + x3;
Fs = 10000; %采样频率决定了两个正弦波点之间的间隔
N = 4096; %采样点数
N1 = 0 : 1/Fs : N/Fs-1/Fs;
s = x1 + x2 + x3;%三种正弦波
fidc = fopen('F:\FPGA\lianxi\FIR\mem.txt','wt'); %将结果写入mem.txt文件,便于modesim使用
for x = 1 : N
fprintf(fidc,'%x\n',round((s(x)+2.12)*58));
end
fclose(fidc);
a=textread('F:\FPGA\lianxi\FIR\mem.txt','%s');
alpha=hex2dec(a);
coeff =[7,5,51,135,179,135,51,5,7];
out =conv(alpha,coeff);%卷积滤波
subplot(3,1,1);
x4 = round((x1+2.12)*58);
plot(x4);
axis([0 200 0 256]);
subplot(3,1,2);
plot(alpha);
xlabel('滤波前');
axis([0 200 0 256]);
subplot(3,1,3);
plot(out);
xlabel('滤波后');
axis([0 200 0 160000]);
三,FPGA设计数字滤波器。参考FPGA实现FIR滤波器_不休的博客-CSDN博客_fpga 滤波器
实现FIR滤波器的过程其实就是实现卷积的过程,卷积的公式如下,从如下公式
中可以看出,x(n)是我们的待滤波信号,h(n)是滤波器系数,卷积的过程其实就是一个乘、累加的过程,所以用FPGA实现8阶FIR滤波器的主要分成三级流水线,第一级、将输入信号延时,这样才能将信号和滤波器系数相乘。第二级、将输入信号和系数相乘。第三级、将乘积进行累加得到结果。
FPGA代码:
module FIR(
input CLK, //系统时钟50M
input RSTn, //外部复位,Pin31引脚
input [7:0] FIR_IN,
output reg [17:0] FIR_OUT
);
reg[7:0] delay_pipeline1;
reg[7:0] delay_pipeline2;
reg[7:0] delay_pipeline3;
reg[7:0] delay_pipeline4;
reg[7:0] delay_pipeline5;
reg[7:0] delay_pipeline6;
reg[7:0] delay_pipeline7;
reg[7:0] delay_pipeline8;
reg[7:0] delay_pipeline9;
always@(posedge CLK or negedge RSTn) begin
if(!RSTn)
begin
delay_pipeline1 <= 8'b0;
delay_pipeline2 <= 8'b0;
delay_pipeline3 <= 8'b0;
delay_pipeline4 <= 8'b0;
delay_pipeline5 <= 8'b0;
delay_pipeline6 <= 8'b0;
delay_pipeline7 <= 8'b0;
delay_pipeline8 <= 8'b0;
delay_pipeline9 <= 8'b0;
end
else
begin
delay_pipeline1 <= FIR_IN;
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;
end
end
wire[7:0] coeff1 = 8'd7; //滤波器系数
wire[7:0] coeff2 = 8'd5;
wire[7:0] coeff3 = 8'd51;
wire[7:0] coeff4 = 8'd135;
wire[7:0] coeff5 = 8'd179;
wire[7:0] coeff6 = 8'd135;
wire[7:0] coeff7 = 8'd51;
wire[7:0] coeff8 = 8'd5;
wire[7:0] coeff9 = 8'd7;
reg signed [16:0] multi_data1;//乘积结果
reg signed [16:0] multi_data2;
reg signed [16:0] multi_data3;
reg signed [16:0] multi_data4;
reg signed [16:0] multi_data5;
reg signed [16:0] multi_data6;
reg signed [16:0] multi_data7;
reg signed [16:0] multi_data8;
reg signed [16:0] multi_data9;
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data1 <= 17'b0;
else
multi_data1 <= delay_pipeline1*coeff1;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data2 <= 17'b0;
else
multi_data2 <= delay_pipeline2*coeff2;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data3 <= 17'b0;
else
multi_data3 <= delay_pipeline3*coeff3;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data4 <= 17'b0;
else
multi_data4 <= delay_pipeline4*coeff4;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data5 <= 17'b0;
else
multi_data5 <= delay_pipeline5*coeff5;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data6 <= 17'b0;
else
multi_data6 <= delay_pipeline6*coeff6;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data7 <= 17'b0;
else
multi_data7 <= delay_pipeline7*coeff7;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data8 <= 17'b0;
else
multi_data8 <= delay_pipeline8*coeff8;
end
always@(posedge CLK or negedge RSTn) begin//x(1) * h(1)
if(!RSTn)
multi_data9 <= 17'b0;
else
multi_data9 <= delay_pipeline9*coeff9;
end
//===================================================================
//加法器
//====================================================================
always@(posedge CLK or negedge RSTn) begin
if(!RSTn)
FIR_OUT <= 18'b0;
else
FIR_OUT <= multi_data1 + multi_data2 + multi_data3 + multi_data4 +multi_data5 + multi_data6 + multi_data7 + multi_data8 + multi_data9;
end
endmodule
四,modelsim仿真。参考FPGA实现FIR滤波器_不休的博客-CSDN博客_fpga 滤波器
仿真文件:
module FIR_tb();
reg CLK;
reg [7:0] FIR_IN;
reg RSTn;
reg [7:0] mem[1:4096];
wire [17:0] FIR_OUT;
reg [12:0] i;
flow_led u0_flow_led (
.CLK(CLK),
.FIR_IN(FIR_IN),
.FIR_OUT(FIR_OUT),
.RSTn(RSTn)
);
initial
begin
$readmemh("F:/FPGA/lianxi/FIR/mem.txt",mem);//????????mem
RSTn= 0;
CLK= 0;
#50;
RSTn= 1;
#50000;
$stop;
end
initial
forever
#10 CLK = ~CLK;
always@(posedge CLK or negedge RSTn)
if(!RSTn)
FIR_IN <= 8'b0 ;
else
FIR_IN <= mem[i];
always@(posedge CLK or negedge RSTn)
if(!RSTn)
i <= 12'd0;
else
i <= i + 1'd1;
endmodule
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)