DDS原理及简易实现
文章目录
- DDS原理及简易实现
-
- 一、DDS基本概念
- 二、DDS核心工作原理
- [三、两种 Verilog 实现思路](#三、两种 Verilog 实现思路)
-
- [方式一:参照标准 DDS 结构框图实现](#方式一:参照标准 DDS 结构框图实现)
- [方式二:基于功能需求(状态机方式实现 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 本质是相位‑地址映射查表机制。
- 相位累加器 :每个时钟周期,将内部寄存器与频率控制字做加法,持续累加,输出相位值;频率字大小直接决定相位累加步长。
- 相位调制器 :把相位累加器输出的值,再叠加相位控制字,得到最终 ROM 读取地址,从而实现输出波形的初始相位偏移。
- ROM 波形查找表:ROM 预先存储一个周期波形的采样数据;输入地址,输出对应时刻的波形数字采样值。> 举例:ROM 内部预存 256 点正弦波形采样数据
- 第 1 个时钟:地址 = 相位字 + 0,读出第一点波形数据
- 第 2 个时钟:地址 = 相位字 + 频率字,读出第二点
- 第 3 个时钟:地址 = 相位字 + 2×频率字
- 以此循环往复,持续查表输出波形数字量。
频率字越大,相位每次步进越大,查表地址跳转越快,输出信号频率越高;相位字用来控制波形起始偏移位置。
- DAC数模转换:ROM输出的是数字波形数据,经过DAC转换为模拟电平信号,外接示波器就可以观测波形。
- 后置低通滤波器:滤除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 | 支持调相、调频、调幅、多波形切换 | 状态机复杂,逻辑较多 | 可配置信号源,项目工程使用 |