FPGA中级项目4——DDS实现

发布于:2025-03-19 ⋅ 阅读:(14) ⋅ 点赞:(0)

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;
else
        freq_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;
        endcase
        
endmodule

综合出来的底层系统逻辑图schematic如下:



网站公告

今日签到

点亮在社区的每一天
去签到