【FPGA-DSP】第三期:DDS直接频率合成及FIR滤波

目录

1. DDS ip核

1.1 DDS ip核调用

ip核配置

 ip核的例化

1.2 TestBench 

2. 时序混频

2.1 Multiplier ip核调用

2.2 ip核的例化

 2.3 TestBench

3. FIR滤波器ip核实现

3.1 matlab fdatool工具箱的使用

3.2 浮点数与定点数的转化

3.3 FIR coe文件导出

3.4 FIR滤波器ip核例化

3.5 Testbench 

原始代码


参考

基于FPGA的FIR滤波器,手把手带你实现_哔哩哔哩_bilibiliicon-default.png?t=N2N8https://www.bilibili.com/video/BV1Vu411y7e6/?spm_id_from=333.788.recommend_more_video.0&vd_source=71acea6682c8121539b919e1e8ca93efFPGA数字信号处理(4)FIR滤波器设计【Matlab】【FPGA】【数字信号处理】【FIR数字滤波器】【FPGA流水线】【数字通信】【FPGA探索者】_哔哩哔哩_bilibiliicon-default.png?t=N2N8https://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

猜你喜欢

转载自blog.csdn.net/weixin_44810982/article/details/129811471
今日推荐