DDS原理及简易实现

DDS原理及简易实现

文章目录

摘要 :讲解 DDS 直接数字频率合成器基础原理,相位累加器、相位调制、ROM 查表的工作机制;提供两种 Verilog 实现:标准框图极简 DDS、状态机实现可调频调相调幅 DDS,分析两种方案优缺点,给出仿真上板注意事项。

一、DDS基本概念

DDS 是直接数字式频率合成器(Direct Digital Synthesizer)的英文缩写,是一项关键的数字化技术。与传统的频率合成器相比,DDS 具有低成本、低功耗、高分辨率和快速转换时间 等优点,广泛应用于电信与电子仪器领域,是实现设备全数字化的关键技术。作为设计人员,我们习惯称它为信号发生器 ,一般用它产生正弦、锯齿、方波等不同波形或不同频率的信号波形,在电子设计和测试中得到广泛应用。

基本结构:主要由相位累加器、相位调制器、波形数据表 ROM、D/A 转换器等四大结构组成,其中较多设计还会在数模转换器之后增加一个低通滤波器。

基本原理:根据结构图来看,相位累加器其实就是以频率字为单位进行累加,然后在相位调制器中将累加后的值与相位字相加作为 ROM 的读取地址,从而获得相应的数据,例如在 ROM 中已经存储了 256 字节的波形数据,那么最开始的时候频率字路径到 ROM 经过两个寄存器,而相位字只有一个寄存器,所以第一次到来的地址是相位字+0,读取第一个数据,第二次来的是相位字+频率字,第三次来的是相位字+2*频率字...以此类推,就可以根据需求取到相应频率和初始相位的信号,此时尚未对数据进行幅值处理。ROM 输出的是数字信号,再经 DAC 转换为模拟信号,即可用示波器观测。

二、DDS核心工作原理

DDS 本质是相位‑地址映射查表机制。

  1. 相位累加器 :每个时钟周期,将内部寄存器与频率控制字做加法,持续累加,输出相位值;频率字大小直接决定相位累加步长。
  2. 相位调制器 :把相位累加器输出的值,再叠加相位控制字,得到最终 ROM 读取地址,从而实现输出波形的初始相位偏移。
  3. ROM 波形查找表:ROM 预先存储一个周期波形的采样数据;输入地址,输出对应时刻的波形数字采样值。> 举例:ROM 内部预存 256 点正弦波形采样数据
  • 第 1 个时钟:地址 = 相位字 + 0,读出第一点波形数据
  • 第 2 个时钟:地址 = 相位字 + 频率字,读出第二点
  • 第 3 个时钟:地址 = 相位字 + 2×频率字
  • 以此循环往复,持续查表输出波形数字量。
    频率字越大,相位每次步进越大,查表地址跳转越快,输出信号频率越高;相位字用来控制波形起始偏移位置。
  1. DAC数模转换:ROM输出的是数字波形数据,经过DAC转换为模拟电平信号,外接示波器就可以观测波形。
  2. 后置低通滤波器:滤除DAC带来的量化噪声、高频镜像分量,输出干净连续模拟波形。

关键公式

f o u t = f c l k ⋅ K 2 N f_{out}=\frac{f_{clk}\cdot K}{2^N} fout=2Nfclk⋅K

  • f o u t f_{out} fout:DDS输出信号频率
  • f c l k f_{clk} fclk:DDS模块工作时钟
  • K K K:频率控制字
  • N N N:相位累加器位宽

三、两种 Verilog 实现思路

两种实现思路:

思路 1:严格参照 DDS 标准框图实现,极简版本,只完成调频、调相;适合理解经典 DDS 架构。

思路 2:面向功能需求实现,使用状态机完成调频、调相、调幅、波形选择,可以完成更多控制功能。

方式一:参照标准 DDS 结构框图实现

核心:相位累加器持续叠加频率字,叠加相位字得到 ROM 读地址,直接查表输出波形数据。

verilog 复制代码
module DDS (
    input   wire            clk         ,
    input   wire            rst_n       ,
    input   wire    [7:0]   phal        ,//相位字,设置初始相位偏移
    input   wire    [7:0]   freq        ,//频率控制字,相位步进
    output  wire    [7:0]   data_wave    //输出波形数字信号
);
    reg  [7:0]    phase_add    ;//相位累加器
    wire [7:0]    address_dds  ;//ROM 的读取地址

    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 0) begin
            phase_add <= 0;
        end
        else begin 
            phase_add <= phase_add + freq;    //相位累加
        end
    end

    assign address_dds = phase_add + phal;    //叠加相位字,得到 ROM 访问地址

rom rom_u (
    .address    (address_dds),
    .clock      (clk        ),
    .q          (data_wave  )
);

endmodule

说明:rom为ROM IP核,预先存储单周期波形采样点(正弦波/锯齿波/方波);本版本只实现调频、调相,幅值固定。

方式二:基于功能需求(状态机方式实现 DDS)

设计思路:对 ROM 读出的波形数据完成调相、调频、调幅处理,输出调制之后的波形数据给后级模块。

  • 调相:修改 ROM 读取的起始地址,实现波形相位偏移;
  • 调频:
    • 调大频率:相同时间内采样点数变少,间隔采样,波形周期缩小;
    • 调小频率:插入等待计数,相当于补点,拉长波形周期;
  • 调幅:对 ROM 输出原始波形数据做除法/乘法运算,缩放输出幅值。
verilog 复制代码
//本质其实就是对已经存好的数据进行相位,频率,幅度的调制,然后再把已调信号输出到其他模块里
//调相:设置ROM最开始读出的地址,即初始相位
//调频:调大频率,同等采样时钟下间隔采样;调小频率,增加计数等待进行补点,拉长周期
//调幅:直接对ROM读取出来的数据做缩放运算
    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 0) begin
            wave_reg <= 0;
            phal_reg <= 0;
            freq_reg <= 0;
            ampl_reg <= 0;
            data_reg <= 0;
            cnt_freq <= 0;
            address  <= 0;
        end
        else begin
            case (state_c)
                IDLE: begin//等待done_cmd指令有效信号
                    wave_reg <= 0;
                    phal_reg <= 0;
                    freq_reg <= 0;
                    ampl_reg <= 0;
                    data_reg <= 0;
                    cnt_freq <= 0;
                    address  <= 0;
                end
                REG :begin//寄存外部配置指令
                    wave_reg <= wave;
                    phal_reg <= phal;
                    freq_reg <= freq;
                    ampl_reg <= ampl;                    
                end
                WAVE:begin//进行波形选择,只做了判断,可扩展多波形
                end
                PHAL:begin//调相,设置ROM起始读地址
                    address  <= phal_reg;
                end
                FREQ:begin//调频,调大(周期缩小)、调小(周期扩宽)
                    //频率分频计数
                    if (cnt_freq == freq_reg[3:0] - 1) begin
                        cnt_freq <= 0;
                    end
                    else begin
                        cnt_freq <= cnt_freq + 1;
                    end
                    //更新ROM地址
                    if ((freq_reg[4] == 1 && cnt_freq == freq_reg[3:0] - 1 ) || freq_reg[4] == 0) begin
                        address <= address + 1;
                    end
                end
                AMPL:begin//调幅,读取ROM数据之后做幅值缩放
                    data_reg <= q/ampl_reg;
                end
                DATA:begin//产生数据有效指示信号
                end
                WAIT:begin//状态机过渡等待状态
                end
                default:begin
                    wave_reg <= 0;
                    phal_reg <= 0;
                    freq_reg <= 0;
                    ampl_reg <= 0;
                    data_reg <= 0;
                    cnt_freq <= 0;
                    address  <= 0;
                end 
            endcase
        end
    end

四、工程对比总结

实现方式 优点 缺点 适用场景
框图式 DDS 代码极简,严格贴合 DDS 理论模型 缺少调幅,功能简单 学习 DDS 原理,快速生成固定幅值波形
状态机功能式 DDS 支持调相、调频、调幅、多波形切换 状态机复杂,逻辑较多 可配置信号源,项目工程使用
相关推荐
无锡银洲自动化1 小时前
煤粉测点频繁堵管?FD 防堵风压取样器现场调试小结
笔记·产品运营
ACP广源盛139246256732 小时前
Type-C 扩展坞选型笔记:DP1.4a 转 HDMI2.0 桥接方案 GSV2201E @ACP评估
笔记·硬件架构·硬件工程·视频·hdmi·国产芯片
智购科技自动售卖机厂家2 小时前
双摄像头方案F1-score只有0.85,排查发现是上下视角的融合逻辑写反了~YH
python·单片机·嵌入式硬件·算法·eclipse
xian_wwq2 小时前
【学习笔记-一文读懂系列】读懂GBZ-195-2026《人工智能 工业智能体参考架构》
笔记·学习
llilian_162 小时前
脉冲时间间隔及计数如何精准测试?
功能测试·嵌入式硬件·51单片机·软件工程
路上有只喵2 小时前
认识元器件 · 牛角型电解电容· 规格书解读
嵌入式硬件
weixin_452600692 小时前
高精密运放——D8629
单片机·嵌入式硬件·dc-dc 转换器·水/气表阀门·共享单车锁舌电机
code2cat2 小时前
Java高级篇之Socket:从建立连接到完整收发一条消息
java·开发语言
凯瑟琳.奥古斯特2 小时前
OCR文字检测算法对比解析
开发语言·python·职场和发展