本章将带您完成第一个真正意义上的“标准”滤波器设计。我们将面对一个经典的信号处理问题:如何从包含多个频率成分的混合信号中,精确地提取出我们需要的部分?为此,我们将设计并实现一个有限长冲激响应(FIR)带通滤波器。项目首先使用DDS生成5MHz、10MHz和20MHz的三种正弦波并将其叠加,形成一个复杂的“噪音”信号。我们的目标,是让滤波器像一个精准的频率“筛子”,仅让10MHz的成分通过,而滤除其他所有无关频率。
通过本章,您将系统地学习FIR滤波器的核心原理、如何在MATLAB中利用专业工具(如fdatool/filterDesigner)设计并导出满足指标的滤波器系数,以及如何在FPGA中高效地调用Xilinx官方IP核来实现它。最后,我们将同时从时域和频域两个维度,严谨地验证滤波器的性能,亲眼见证其“去伪存真”的强大能力。
1 项目目标
用DDS产生三个采样率为100MHz,频率分别为5MHz、10MHz和20MHz的正弦波,然后将它们叠加混合,形成一个混乱的噪音。对于这个噪音,我们需要提取出频率为10MHz的成分,过滤掉其他我们不关注的成分。于是,我们通过一个FIR带通滤波器来实现这个功能,仅保留频率为10MHz左右的成分。
2 FIR 滤波器简介
FIR滤波器,全称为有限长单位冲激响应滤波器,是数字信号处理中最基本、最常见的滤波器之一。
数字滤波器:它的输入和输出信号都是离散的数字信号。
有限长:这是它的核心特征。当您给FIR滤波器一个非常短暂且强烈的输入信号(称为“单位脉冲”)时,它产生的响应(输出)只会在有限的时间内存在,而不是无限持续。
线性、非递归:FIR滤波器的当前输出仅由当前的输入和过去的输入决定,不会将过去的输出反馈回来用于计算当前输出。这使得它在行为上非常稳定和可预测。
FIR滤波器的工作原理可以概括为 “加权滑动平均”。
想象一个长度为 N 的窗口(也称为滤波器的阶数),里面存放着 N 个预先设定好的系数(h[0], h[1], ..., h[N-1]),这些系数决定了滤波器的特性(如低通、高通等)。
计算过程如下:
输入信号 x[n] 依次进入这个窗口。
在每一个时刻 n,将窗口内的 N 个最新的输入样本(从 x[n] 到 x[n-(N-1)])分别与对应的 N 个滤波器系数相乘。
将所有乘积结果相加,就得到了当前时刻的输出 y[n]。
这个过程可以用一个关键的数学运算来描述:卷积。
差分方程(核心公式):
y[n] = h[0]*x[n] + h[1]*x[n-1] + h[2]*x[n-2] + ... + h[N-1]*x[n-(N-1)]
其中:
y[n] 是当前输出。
x[n] 是当前输入。
x[n-1], x[n-2] ... 是过去的输入。
h[0], h[1] ... h[N-1] 是滤波器系数(也称为抽头权重),它们是滤波器的“灵魂”。
3 MATLAB 设计滤波器系数
打开MATLAB在命令行窗口输入的FDATOOL(新版改用filterDesigner),打开滤波器设计工具。如图:
由于我们需要过滤的信号是有三种5M、10M及20M频率混合的,现在只保留10M,故可以设计一个带通滤波器仅保留10M的部分,以下为参考设计。
按照这个配置好后,要导出.coe文件用于配置FIR IP,步骤如下:
4 FPGA实现
这里实现FIR滤波器使用了官方IP,这里简要说明下如何配置这个IP,步骤如下:
Select source 选择COE File,然后在Coefficient File中导入MATLAB生成的.coe文件。
然后时钟和输出信号的采样率按实际情况配置,这个实验是100M故设置100.
这个界面默认就行。
默认即可。
默认即可。
配置完这个IP之后,其他的如DDS等简单的IP就不过多的赘述,我们这边放上源码:
Top.v
`timescale 1ns / 1ps
module top (
input I_sysclk_p ,
input I_sysclk_n ,
input I_rst_n ,
output O_led
);
/*******************************************************************\
变量定义
\*******************************************************************/
//clock
wire clk_100m ;
wire locked ;//后续用于高复位,待优化
//dds
wire signed [ 15: 0] dds_data_5m ;
wire dds_data_5m_valid ;
wire phase_tvalid_5m ;
wire [ 31: 0] phase_tdata_5m ;
wire signed [ 15: 0] dds_data_10m ;
wire dds_data_10m_valid ;
wire phase_tvalid_10m ;
wire [ 31: 0] phase_tdata_10m ;
wire signed [ 15: 0] dds_data_20m ;
wire dds_data_20m_valid ;
wire phase_tvalid_20m ;
wire [ 31: 0] phase_tdata_20m ;
//信号叠加
reg signed [ 16: 0] mix_data_add1 ;
reg signed [ 16: 0] mix_data_add ;
wire signed [ 15: 0] mix_data ;
wire mix_data_add_valid ;
reg mix_data_add_valid_reg ;
reg mix_data_valid ;
//fir
wire s_axis_data_tready ;
wire fir_data_out_valid ;
wire signed [ 15: 0] fir_data_out ;
/*******************************************************************\
时钟管理模块
\*******************************************************************/
clk_wiz_1 clock_and_reset
(
.clk_out1(clk_100m),
.locked(locked),
.clk_in1_p(I_sysclk_p),
.clk_in1_n(I_sysclk_n)
);
/*******************************************************************\
DDS模块
\*******************************************************************/
//采样频率为100MHz,频率为5MHz的单音信号
dds_16_16_5m dds_16_5m (
.aclk(clk_100m), // input wire aclk
.m_axis_data_tvalid(dds_data_5m_valid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(dds_data_5m), // output wire [15 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(phase_tvalid_5m), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(phase_tdata_5m) // output wire [31 : 0] m_axis_phase_tdata
);
//采样频率为100MHz,频率为10MHz的单音信号
dds_16_16_10m dds_16_10m (
.aclk(clk_100m), // input wire aclk
.m_axis_data_tvalid(dds_data_10m_valid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(dds_data_10m), // output wire [15 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(phase_tvalid_10m), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(phase_tdata_10m) // output wire [31 : 0] m_axis_phase_tdata
);
//采样频率为100MHz,频率为20MHz的单音信号
dds_16_16_20m dds_16_20m (
.aclk(clk_100m), // input wire aclk
.m_axis_data_tvalid(dds_data_20m_valid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(dds_data_20m), // output wire [15 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(phase_tvalid_20m), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(phase_tdata_20m) // output wire [31 : 0] m_axis_phase_tdata
);
/*******************************************************************\
信号叠加模块
\*******************************************************************/
//叠加信号,由三种单音信号叠加而成
always @(posedge clk_100m or negedge I_rst_n) begin
if(!I_rst_n) begin
mix_data_add1 <= 'b0;
mix_data_add <= 'b0;
end else begin
mix_data_add1 <= dds_data_5m + dds_data_10m;
mix_data_add <= mix_data_add1[16:1] + dds_data_20m;
end
end
assign mix_data = mix_data_add[16:1];
//叠加信号有效
assign mix_data_add_valid = dds_data_5m_valid & dds_data_10m_valid & dds_data_20m_valid;
always @(posedge clk_100m or negedge I_rst_n) begin
if(!I_rst_n) begin
mix_data_add_valid_reg <= 'b0;
mix_data_valid <= 'b0;
end else begin
mix_data_add_valid_reg <= mix_data_add_valid;
mix_data_valid <= mix_data_add_valid_reg;
end
end
/*******************************************************************\
FIR滤波模块
\*******************************************************************/
assign O_led = fir_data_out_valid;
//带通滤波器,保留频率为10MHz的单音信号
fir_compiler_0 fir_bpf (
.aclk(clk_100m), // input wire aclk
.s_axis_data_tvalid(mix_data_valid), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready
.s_axis_data_tdata(mix_data), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid(fir_data_out_valid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(fir_data_out) // output wire [39 : 0] m_axis_data_tdata
);
/*******************************************************************\
ILA调试模块
\*******************************************************************/
ila_0 debug(
.clk(clk_100m), // input wire clk
.probe0(mix_data), // input wire [15:0] probe0
.probe1(fir_data_out) // input wire [15:0] probe1
);
endmodule
| 仿真代码如下:
Tb_top.v
`timescale 1ns / 1ps
module tb_top();
reg I_sysclk_p;
reg I_rst_n;
wire O_led;
initial begin
I_sysclk_p = 1;
I_rst_n = 0;
#1000 I_rst_n = 1;
end
always #5 I_sysclk_p = ! I_sysclk_p ;
top top_inst (
.I_sysclk_p(I_sysclk_p),
.I_sysclk_n(~I_sysclk_p),
.I_rst_n(I_rst_n),
.O_led(O_led)
);
endmodule
|
5 实验结果分析
5.1仿真结果
如下所示,可以看到红色部分的波形(mix_data)为叠加混合的噪音,经过滤波后输出粉红色的波形,与DDS生成的频率为10MHz的正弦波(橙色波形)基本一致。也就是说,从时域上看,我们的实验成功了。
5.2 WaveVision5分析
为了严谨,我们还需要频域上验证我们的实验结果是否正确,于是我们上板,通过ila导出mix_data和fir_data_out这两个数据进行分析。
ILA抓取波形如下,可以看到与仿真结果一致。
通过TI公司的频谱分析软件WaveVision5分析如下:
mix_data时域分析,时域波形与仿真结果和ILA一致。
mix_data频域分析,频域上看有频率分别为5MHz、10MHz和20MHz的成分以及它们的谐波。
fir_data_out时域分析,时域波形与仿真结果和ILA一致。
fir_data_out频域分析,频域上看基本仅有频率为10MHz的成分以及它的谐波。
从上面的结果来看,我们的工程成功的实现了目标。
|