目录
参考
基于FPGA的FIR滤波器,手把手带你实现_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Vu411y7e6/?spm_id_from=333.788.recommend_more_video.0&vd_source=71acea6682c8121539b919e1e8ca93efFPGA数字信号处理(4)FIR滤波器设计【Matlab】【FPGA】【数字信号处理】【FIR数字滤波器】【FPGA流水线】【数字通信】【FPGA探索者】_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1u54y1Y7Gb/?spm_id_from=333.999.0.0&vd_source=71acea6682c8121539b919e1e8ca93ef
1. DDS ip核
我们的开发板使用的是Zynq7100,因此在新建工程时候需选择xc7z010clg400-1的封装
1.1 DDS ip核调用
我们需要调用两次DDS的ip核,生成两个不同频率的sin函数,并将它们叠加在一起输出。
-
ip核配置
配置好的dds ip核如下图
输入系统时钟是50MHz,输出Sin函数为3MHz,第二个ip核同理,输出4MHz正弦函数
-
ip核的例化
将ip核给出的veo文件中的模块例程拷贝进你的顶层文件中
例化好的顶层文件如下:
接下来就需要添加testbench文件来进行仿真
1.2 TestBench
时序仿真测试文件如下
10ms仿真结果如下:
注意: 两个输出需要将进制(Radix)设置为有符号10进制,接着将波形形式(Weave Style)设置为模拟
2. 时序混频
接下来我们需要将两个正弦波形在时域上混频,因此需要调用乘法器ip核
2.1 Multiplier ip核调用
除了修改A/B的位宽(8位)其他选项保持默认即可
2.2 ip核的例化
在顶层文件中添加
//-----------------------------------混频---------------------------------
mult_gen_0 u_mult (
.CLK(clk), // input wire CLK
.A(sin_3M), // input wire [7 : 0] A
.B(sin_10M), // input wire [7 : 0] B
.P(sin_P) // output wire [15 : 0] P
);
2.3 TestBench
由混频器原理可知,若两个信号其频率分别为f1,f2,则经过混频器,输出信号等于输入信号的乘积,时域的乘积对应于频域的卷积,过程可推算如下
因此
由上式可知,一个信号在时域中与余弦、正弦或复信号相乘,等效于频域的频谱搬移。我们仿真得到的混频信号就会存在两个不同频率,分别是f1+f2=7MHz,|f1-f2|=1MHz。
3. FIR滤波器ip核实现
我们通过使用FIR滤波器将低频1MHz和高频7MHz分开,设置一个LPF和HPF分别过滤出低频,高频成分。
通过matlab的fdatool工具箱设计FIR滤波器,以99阶FIR低通滤波器为例,学习使用matlab的fdatool工具箱设计滤波器,并将滤波器系数导出到.coe文件,联合Vivado进行FPGA的FIR滤波器设计。本文滤波器参数为:低通FIR滤波器,窗函数设计,采用布莱克曼窗,33阶,抽样频率50MHz,通带频率1.5MHZ,适用窗函数时截止频率不需要设定,根据选定的窗函数和阶数决定截止频率。
注意:采样时钟最好和系统时钟保持一致!
3.1 matlab fdatool工具箱的使用
命令行输入fdatool,回车,打开fdatool滤波器设计工具箱
打开后的初始界面如下:
- 选定滤波器类型(低通、高通、带通、带阻)
- 选择要设计IR(无限冲激响应) 滤波器还是FIR (有限冲击响应) 滤波器,并且选择使用哪种方法设计对应的滤波器;
- 设计滤波器的阶数,一般阶数越多滤波效果越好,但是系数对应的也越多,在FPGA硬件实现的时候会占用更多的资源,设计时要综合考虑
- 设计滤波器的抽样频率Fs,通带频率Fpass和截止频率Fstop
根据该仿真需求,FIR滤波器设计如下:
由于我们的采样频率设置为50MHz,因此图中的幅值响应范围是0~25MHz(奈奎斯特)。
注意:在FPGA第五章的学习过程中,我们知道FPGA表示浮点数是很困难的,因此matlab在于FPGA通信的过程中需要注意浮点数与定点数的转化
3.2 浮点数与定点数的转化
在FPGA中计算浮点数是很麻烦的事情,并且浮点数的操作在射频输出时会影响功放性能,此处设置为定点数(一般都是设为定点数处理)。这里进行量化时就会引入量化误差,位数越少误差越大,但是位数越多在FPGA硬件中所需的资源也越多,设计中也是需要综合考虑,此处选择16位定点数量化。
点击apply,在右上方可以看到量化之后和未量化的差别,可以看到实线部分是16位量化后的幅频特性曲线,虚线部分是未量化的幅频特性曲线,量化之后在4MHz以后的阻带衰减不如原来的衰减大,但是实际上量化后也能衰减到-100dB,从幅度上来讲是原来的1/(10^5),这个衰减程度也已经足够了,所以使用16位量化对于滤波器的滤波效果几乎没有什么影响。
3.3 FIR coe文件导出
按照下图:
即可导出含有33阶滤波器系数的coe文件
3.4 FIR滤波器ip核例化
- ip核生成
- ip核例化
3.5 Testbench
FIR的ip核较大,所以仿真编译会跑很久~
可以发现,通过FIR-LPF滤波器,高频成分被滤除,仅留下了低频1MHz信号。
原始代码
- 顶层文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/03/28 10:49:39
// Design Name:
// Module Name: DDS
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module DDS(
input wire clk,
output wire [7:0] sin_3M, //第一个正弦波,由u1生成3MHz
output wire [7:0] sin_4M, //第二个正弦波,由u2生成
output wire m_axis_data_tvalid1,
output wire m_axis_data_tvalid2,
output wire [15:0] sin_P,
output wire [39:0] sin_LPF
);
//-----------------------------3MHZ/10MHz正弦波生成-------------------------------
dds u1(
.aclk(clk), // input wire aclk
.m_axis_data_tvalid(m_axis_data_tvalid1), // output wire m_axis_data_tvalid
.m_axis_data_tdata(sin_3M) // output wire [7 : 0] m_axis_data_tdata
);
dds2 u2(
.aclk(clk), // input wire aclk
.m_axis_data_tvalid(m_axis_data_tvalid2), // output wire m_axis_data_tvalid
.m_axis_data_tdata(sin_4M) // output wire [7 : 0] m_axis_data_tdata
);
//-----------------------------------混频---------------------------------
mult_gen_0 u_mult (
.CLK(clk), // input wire CLK
.A(sin_3M), // input wire [7 : 0] A
.B(sin_4M), // input wire [7 : 0] B
.P(sin_P) // output wire [15 : 0] P
);
//--------------------------------------FIR-LPF--------------------------------
fir_compiler_0 your_instance_name (
.aclk(clk), // input wire aclk
.s_axis_data_tvalid(m_axis_data_tvalid1), // input wire s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready
.s_axis_data_tdata(sin_P), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid(m_axis_data_tvalid2), // output wire m_axis_data_tvalid
.m_axis_data_tdata(sin_LPF) // output wire [39 : 0] m_axis_data_tdata
);
endmodule
- TB文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/03/28 11:15:25
// Design Name:
// Module Name: DDS_sim
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module DDS_sim();
reg sys_clk=0; //系统时钟激励
wire [7:0]sin_3M;
wire [7:0]sin_4M;//利用wire将模块的输出拉取出来
wire [15:0]sin_P;
wire [39:0]sin_LPF;
always#10 sys_clk <= ~sys_clk; //生成50MHZ的系统时钟
//模块例化
DDS u_dds(
.clk (sys_clk),
.sin_3M (sin_3M), //第一个正弦波,由u1生成3MHz
.sin_4M (sin_4M), //第二个正弦波,由u2生成
.m_axis_data_tvalid1 (m_axis_data_tvalid1),
.m_axis_data_tvalid2 (m_axis_data_tvalid2),
.sin_P(sin_P),
.sin_LPF(sin_LPF)
);
endmodule