FPGA中级项目4——DDS实现
DDS简介
DDS(直接数字频率合成器,Direct Digital Frequency Synthesis)是一种基于数字信号处理技术的频率合成方法,广泛应用于通信、雷达、仪器仪表等领域。在 FPGA中实现 DDS 具有灵活性高、集成度强、响应速度快等优势。其实也就是能产生各种波形!
DDS 基本原理
相位累加器:通过数字累加器生成相位增量,决定输出信号的频率。
相位增量怎么决定输出信号频率呢?请继续看下文
相位增量就是频率控制字FCW,由用户输入
波形 ROM / 查找表:根据相位增量依次等间隔来查找存储不同相位对应的波形数据(如正弦波、方波等)。
数模转换器(DAC):将数字波形转换为模拟信号。
频率控制字(FCW):输入的频率指令,决定相位累加的步长。输出频率与频率控制字成正比,通过改变频率控制字的大小,可以方便地调整输出信号的频率。
相位控制字(PCW):通常用于对相位累加器的输出结果进行偏移。这样,通过改变相位控制字,可以改变输出信号的初始相位。
相位
在了解DDS时,必须要补充的一个知识即:相位(不是宰相之位)。在信号处理和电子系统中,相位(Phase)是描述周期性信号波形位置的关键参数,通常以角度(弧度或度)表示。
相位的基本定义
物理意义:相位表示信号波形在时间轴上的偏移位置。例如,对于正弦波 Asin(ωt+ϕ) ,ϕ 是初始相位(单位:弧度或度)。
当 ϕ=0 时,波形从原点开始;
当 ϕ=Π/2 时,波形处于峰值位置。
相位差:
两个同频率信号的相位之差决定了它们的相对位置关系。
例如:相位差为 0:同相;
相位差为Π:反相。
相位在 DDS 中的作用
在 DDS 系统中,相位是生成频率的核心变量,其作用如下:
相位累加器:通过不断累加相位增量(频率控制字 FCW)生成连续的相位序列。例如
相位值(k + 1)= 相位值(k)+ FCW(模2^N)
相位累加器的溢出速度直接决定输出信号的频率:公式为
相位与频率的关系
-
相位变化率: 频率是相位随时间的变化率,即。ω= dϕ/dt
在 DDS 中,相位增量 FCW 决定了每个时钟周期的相位变化量,因此直接控制输出频率。
相位的单位与精度
-
单位: 通常用弧度(rad)表示,例如:
- 一个完整周期对应 2Π 弧度;
- 半周期对应 Π 弧度。
-
相位精度: 相位累加器的位数 N 决定了相位的量化精度。例如:
- N = 32 时,相位分辨率为 2Π / 2^32 。
- 不同的相位值对应波形的不同点
需要特别指出的是:溢出频率等于输出信号的频率,即 每输出一个完整周期信号,相位累加器溢出一次。
相位累加器是一个 N 位寄存器,当累加结果达到 2^N 时,溢出回 0。相位累加器每溢出一次,意味着数字相位完成了一个完整的周期(从 0 到 2^N-1再回到 0),对应物理相位完成 2Π 弧度的变化。
问题分析
1. 我们需要搭建的便是DDS电路逻辑,需要有选择波形输入端mode_sel 和 输出给DAC 的数字数据输出端data 。其中频率控制字fword 的位宽为32位,因为我们要实现fword 与累加寄存器的数值相加,保证位宽相同(累加器位宽固定为32位)。对于相位控制字pword ,理论上我们也需要32位位宽用于计数波形数据,但是所需容量太大。所以我们取12位即可(即整个波形我们只取其中4096个点) ,同时也决定了data的位宽。
2. 在进行编写定义波形数据表时,由于相位控制字的位宽为12位,也就是只需要4096个数据;但是频率控制字的位宽为32位。因此我们要进行截取高位来取点即选择位宽为【31:20】。频率控制字和相位控制字共同来决定一个数据,因此ROM表也只需要4096个数据存储即可!
3. 然后需要进行不同波形数据的存储,即对不同ROM IP核的创建,根据需要分别存储不同波形。其中正弦波的设置如下所示(其余两个波形设置相同,只是产生数据文件不一致,便不与累赘):
直至完成3个ROM IP核的创建,然后对其进行例化。
4. 最后根据用户输入选择对应不同波形输出, 使用case语句即可完成。
代码展示
//定义输入输出端口
module DDS(clk,reset_n,mode_sel,//控制输出的波形fword,//频率控制字pword,//相位控制字data//输出给DAC的数据);input clk;input reset_n;input [1:0]mode_sel;input [31:0]fword;input [11:0]pword;output reg [13:0]data;//将fword打一拍reg [31:0]fword_r;
always@(posedge clk)fword_r <= fword;//将pword打一拍reg [11:0]pword_r;
always@(posedge clk)pword_r <= pword; //定义相位累加寄存器reg [31:0]freq_acc;
always@(posedge clk or negedge reset_n)
if(!reset_n)freq_acc <= 0;
elsefreq_acc <= freq_acc + fword_r;// 定义波形数据表wire [11:0]rom_addr;
assign rom_addr = freq_acc[31:20] + pword_r;//例化创建好的ROM IP核wire [13:0]sine, square, triangular;sine DDS_sine (.clka(clk), // input wire clka.addra(rom_addr), // input wire [11 : 0] addra.douta(sine) // output wire [13 : 0] douta);square DDS_square (.clka(clk), // input wire clka.addra(rom_addr), // input wire [11 : 0] addra.douta(square) // output wire [13 : 0] douta);triangular DDS_triangular (.clka(clk), // input wire clka.addra(rom_addr), // input wire [11 : 0] addra.douta(triangular) // output wire [13 : 0] douta);//case选择输出
always@(*)case(mode_sel)0: data = sine;1: data = square;2: data = triangular;3: data = 5555;endcaseendmodule
综合出来的底层系统逻辑图schematic如下: