
1. 从模拟到数字频率合成技术的演进与DDS的诞生在电子工程和信号处理领域生成一个纯净、稳定且频率可编程的信号是无数应用场景的基石。无论是无线通信中的载波、雷达系统的脉冲、音频设备的测试音还是医疗成像设备的激励源都离不开一个核心部件频率合成器。传统的频率合成技术比如锁相环大家应该都不陌生。它通过一个模拟的反馈环路将压控振荡器的输出频率锁定在一个高稳定度的参考频率上通过分频比的变化来实现不同频率的输出。这种方法成熟、可靠在很多场合依然是首选。但PLL有一个绕不开的问题频率切换速度。当你需要从一个频率快速跳变到另一个频率时PLL的反馈环路需要时间重新建立锁定这个“频率捷变”时间可能达到毫秒甚至更长。在一些对实时性要求极高的场景比如跳频通信、快速扫描的频谱分析仪里这个延迟是无法接受的。此外模拟环路本身会引入相位噪声和杂散频率分辨率也受限于分频器的步进。于是一种更“数字化”的思路应运而生既然我们最终处理的是数字信号为什么不直接在数字域“合成”出我们想要的波形再把它转换成模拟信号呢这就是直接数字频率合成技术的核心思想。我第一次接触DDS是在一个需要快速生成线性调频信号的雷达模拟项目中PLL的切换速度成了瓶颈团队决定转向DDS方案。当看到仅仅通过修改一个寄存器的值输出频率就在几个时钟周期内瞬间改变时那种“指哪打哪”的利落感让我对这项技术留下了深刻印象。DDS不像PLL那样依赖于模拟器件的物理特性它完全在数字域运作其核心是一个查表操作。你可以把它想象成一个非常智能的“音乐播放器”。这个播放器里存有一首固定曲目比如一个完整的正弦波周期数据我们通过控制播放指针的移动速度来决定播放出来的音调高低。指针移动得快音调就高频率高移动得慢音调就低频率低。而这个移动速度就是我们通过数字方式精确设定的。这种全数字化的架构带来了几个颠覆性的优势极高的频率分辨率可达微赫兹量级、极快的频率切换速度通常在纳秒到微秒级、以及出色的相位连续性。当然它也有其局限比如输出频率上限受制于数字系统的时钟速率以及由数字量化带来的杂散信号。但无论如何DDS为工程师提供了一种前所未有的、灵活且精确的频率控制手段。2. DDS的核心架构相位累加器与波形查找表要理解DDS如何工作我们必须深入其最核心的两个数字模块相位累加器和波形查找表。整个DDS系统可以看作一个以固定时钟f_clk驱动的数字信号处理流水线。2.1 相位累加器频率控制字与相位生成相位累加器是DDS的“心脏”它是一个位宽为N的寄存器。在每个系统时钟上升沿这个寄存器都会累加一个固定的值这个值被称为频率控制字。频率控制字本质上是一个无符号整数它直接决定了输出信号的频率。我们来打个比方。假设相位累加器是一个有2^N个刻度的圆盘对应一个周期2π的相位频率控制字就是每次转动圆盘的“步长”。如果步长很小比如每次只转动1个刻度那么要转完整个圆盘经历2π相位需要2^N个时钟周期输出的信号周期很长频率就很低。如果步长很大比如每次转动2^(N-1)个刻度那么只需要2个时钟周期就能转完整个圆盘输出的频率就接近时钟频率的一半。其数学关系非常清晰f_out (FTW * f_clk) / 2^N其中f_out 输出的模拟信号频率。FTW 频率控制字。f_clk DDS系统的工作时钟频率。N 相位累加器的位宽。这个公式是DDS设计的起点。例如假设系统时钟f_clk 100 MHz相位累加器位宽N 32。那么频率分辨率Δf f_clk / 2^N 100e6 / 4294967296 ≈ 0.02328 Hz。这意味着你可以通过设置FTW以大约0.023 Hz的步进来精确控制输出频率。如果你想输出一个10 MHz的信号那么FTW f_out * 2^N / f_clk 10e6 * 4294967296 / 100e6 429,496,730取整。将这个值写入控制寄存器DDS就会开始合成10 MHz的信号。2.2 波形查找表从相位到幅度的映射相位累加器的输出是一个线性增长的相位值0 到2^N-1。但我们需要的是正弦波、余弦波或者其他波形的幅度值。这个转换工作就由波形查找表来完成。查找表本质上是一个只读存储器它预先存储了一个周期波形的离散幅度样本。通常我们存储一个完整的正弦波周期。相位累加器输出的高M位M通常小于N例如取高12-16位被用作查找表的地址。这个截断操作是必要的因为如果直接用32位的相位值作为地址查找表将大得不可思议2^32个条目。查找表根据这个地址输出对应的波形幅度值。这个幅度值仍然是数字量通常是有符号的二进制补码格式。例如一个深度为4096地址位宽12位、宽度为14位的正弦查找表可以输出从-8192到8191的幅度值对应正弦波从-1到1。这里有一个关键的设计权衡查找表的深度地址位宽M和宽度幅度数据位宽。深度决定了波形的相位分辨率。深度越深一个周期内采样的点数越多合成的波形相位精度越高由相位截断引入的杂散信号就越小。宽度决定了波形的幅度分辨率。宽度越宽幅度的量化误差越小信噪比越高。但两者都直接消耗FPGA内部的Block RAM资源。在实际项目中我通常根据系统对杂散和噪声的要求来反推。对于通信系统可能需要14位幅度、12位地址以上的配置对于一些要求不高的函数发生器10位地址、10位幅度可能也够用。2.3 数模转换器数字世界的最后一步查找表输出的数字幅度序列经过一个寄存器同步后被送入数模转换器。DAC将这个数字序列转换成阶梯状的模拟电压。这个阶梯波包含了我们所需频率的主信号也包含了大量的高频谐波分量由于采样和量化产生。因此在DAC之后必须连接一个低通滤波器。这个滤波器的截止频率需要精心设计它必须能让所需的主信号频率f_out无衰减地通过同时尽可能多地抑制高于f_clk/2奈奎斯特频率的高频镜像和谐波。这个滤波器性能的好坏直接决定了最终输出模拟信号的质量。在很多集成DDS芯片或IP核中内部会包含一个简单的滤波器但对于高性能应用外置一个高阶的模拟低通滤波器仍然是标准做法。3. DDS的输出频谱与关键性能指标分析理解了DDS的工作原理我们就能预判它的输出信号并非理想纯净的正弦波而是带有各种“瑕疵”。这些“瑕疵”主要来源于两个数字域的量化过程相位的截断和幅度的量化。分析这些非理想特性是设计一个高性能DDS系统的关键。3.1 理想DDS的输出频谱在理想情况下假设相位累加器位宽无限、查找表深度无限、幅度分辨率无限DDS的输出在频域上应该只有一根谱线位于我们设定的频率f_out处。但这是不可能的数字系统的有限字长效应决定了其输出频谱必然包含杂散。3.2 相位截断杂散这是DDS中最主要的杂散来源。如前所述我们用相位累加器输出的高M位去寻址查找表而低(N-M)位被丢弃了。这个丢弃操作称为相位截断。它导致寻址地址的周期性误差这个误差会以调制的方式体现在输出信号上产生杂散分量。这些杂散分量的频率位置和幅度可以通过数学公式进行估算。通常最严重的杂散出现在f_spur |K * f_clk / 2^(N-M) ± f_out|附近其中K为整数。其幅度与相位截断的位数(N-M)有关位数越多杂散越低。经验上每增加1位相位截断位杂散电平改善约6 dB。因此为了获得更纯净的频谱在资源允许的情况下应尽可能增大相位累加器位宽N并让查找表使用其尽可能多的高位即减小截断位数N-M。3.3 幅度量化杂散与信噪比即使相位是完美的查找表输出的幅度值也是经过量化的。一个B位的幅度量化会将一个理想的正弦波变成有台阶的波形这相当于引入了量化噪声。这个噪声在频域上近似为白噪声均匀分布在0到f_clk/2的频带内。DAC输出信号的信噪比主要由幅度量化位数B决定。理想情况下对于一个满量程的正弦波信噪比的理论公式为SNR 6.02B 1.76 dB。例如一个14位的DAC其理论信噪比约为6.02*14 1.76 86 dB。这是DDS输出信号动态范围的上限。在实际FPGA实现中由于其他噪声源如电源噪声、DAC非线性等实际信噪比会低于这个理论值。3.4 镜像频率分量由于DDS本质是一个采样系统根据奈奎斯特采样定理在DAC输出中除了基波f_out还会在f_clk ± f_out2*f_clk ± f_out等处产生镜像频率分量。这些分量的幅度可能与主信号相当。这就是为什么必须在DAC之后使用低通滤波器的根本原因。滤波器的任务就是滤除这些高频镜像只留下我们需要的基波信号。注意在设计DDS系统时必须遵守f_out f_clk / 2的原则否则会发生混叠基波频率本身就无法被正确重建。通常为了给滤波留出过渡带实际使用的最高输出频率f_out_max会设定在f_clk * 40%左右例如f_clk 100 MHz时f_out_max通常取40 MHz。3.5 无杂散动态范围这是衡量DDS频谱纯净度的核心指标指主信号幅度与最大杂散分量幅度之间的差值。SFDR受到相位截断杂散、DAC非线性、电源噪声等多种因素影响。在FPGA内部实现DDS时我们主要能优化的是相位截断带来的杂散。通过增加相位累加器位宽和采用一些相位抖动技术可以在一定程度上改善SFDR。4. 在FPGA中实现DDS资源、精度与速度的权衡用FPGA实现DDS具有极大的灵活性我们可以根据需求定制相位累加器位宽、查找表内容、甚至算法。但这也意味着我们需要在资源消耗、性能指标和设计复杂度之间做出权衡。4.1 核心模块的Verilog实现要点一个最基本的DDS核心模块的Verilog代码结构非常清晰。下面是一个简化示例展示了关键部分module dds_core #( parameter PHASE_WIDTH 32, // 相位累加器位宽 parameter ADDR_WIDTH 12, // 查找表地址位宽 parameter DATA_WIDTH 14 // 输出数据位宽 )( input wire clk, // 系统时钟 input wire rst_n, // 异步低电平复位 input wire [PHASE_WIDTH-1:0] ftw, // 频率控制字 output reg [DATA_WIDTH-1:0] sine_out // 正弦波输出 ); // 相位累加器寄存器 reg [PHASE_WIDTH-1:0] phase_acc; // 相位累加过程 always (posedge clk or negedge rst_n) begin if (!rst_n) phase_acc 0; else phase_acc phase_acc ftw; // 核心累加操作 end // 相位截断取高ADDR_WIDTH位作为查找表地址 wire [ADDR_WIDTH-1:0] lut_addr phase_acc[PHASE_WIDTH-1:PHASE_WIDTH-ADDR_WIDTH]; // 正弦查找表ROM // 通常使用FPGA的IP核如Block Memory Generator生成这里用寄存器数组示意 reg [DATA_WIDTH-1:0] sine_lut [0:(1ADDR_WIDTH)-1]; initial begin // 此处应通过$readmemh或IP核加载正弦波数据文件 // sine_lut[addr] sin(2*PI*addr/2^ADDR_WIDTH) * (2^(DATA_WIDTH-1)-1) end // 查找表输出 always (posedge clk) begin sine_out sine_lut[lut_addr]; end endmodule在实际工程中查找表不会用initial块和寄存器数组来初始化而是使用Vivado或Quartus提供的ROM IP核。我们可以用MATLAB或Python生成一个包含正弦波数据的.coe或.mif文件然后在IP核配置中加载这个文件。这样做的好处是ROM由FPGA的高效Block RAM实现并且工具会自动优化其布局布线。4.2 资源优化策略DDS消耗的主要是逻辑资源用于相位累加器和存储资源用于查找表。当需要很高的无杂散动态范围时相位累加器位宽N可能需要48位甚至更高但这会消耗大量逻辑资源。一个优化技巧是使用DSP48切片来实现高精度加法。Xilinx的DSP48E1/E2切片本身就是一个高性能的乘加器也可以配置为纯加法器非常适合实现超宽位的相位累加。对于查找表当需要很大的深度和宽度时一块Block RAM可能不够。这时可以采用“ coarse-fine”双表法。将相位的高几位用于一个粗糙的、存储少量点的查找表低几位用于一个精细的、存储差值或修正值的查找表通过插值算法计算出最终幅度。这可以在保证精度的前提下大幅减少ROM容量。另一种常见方法是利用正弦波的对称性只存储0到π/2的第一象限数据然后通过相位的高两位来判断当前相位所在的象限并对输出数据进行取反或取补操作这样可以将ROM容量减少到原来的1/4。4.3 利用CORDIC算法替代查找表对于某些应用如果对输出频率的纯度要求不是极端苛刻或者FPGA的Block RAM资源非常紧张可以考虑使用CORDIC算法来实时计算正弦/余弦值。CORDIC是一种通过迭代旋转向量来计算三角函数值的算法它只使用移位和加法操作不消耗ROM资源。在FPGA中实现一个流水线型的CORDIC每个时钟周期都能输出一组正弦/余弦值吞吐率高。但其缺点是存在固定的计算延迟流水线级数并且输出精度受迭代次数限制。每次迭代大约提供1位精度增益。例如要实现14位精度可能需要14级以上的流水线。这会消耗相当的逻辑资源并带来固定的延迟。因此CORDIC方案更适合于对资源敏感、对固定延迟不敏感、且需要同时产生正余弦信号的场合如数字下变频中的本振生成。5. 超越基础DDS的高级应用模式与实战技巧掌握了基本DDS原理和实现后我们可以玩出更多花样解决更复杂的工程问题。DDS的灵活性正体现在这些扩展应用上。5.1 频率/相位/幅度调制由于DDS的频率、相位和幅度都是通过数字寄存器控制的因此实现各种调制易如反掌。调频 动态改变频率控制字FTW。你可以根据调制信号例如音频信号实时计算并更新FTW就能产生FM信号。在FPGA中这通常需要一个高速的乘法累加单元。调相 动态改变相位累加器的输出值或者在送入查找表前给相位地址加上一个偏移量。这个偏移量寄存器就是相位控制字。通过改变它可以实现PSK相移键控调制。调幅 在查找表输出之后乘上一个幅度控制字。这可以直接用DSP切片实现产生ASK幅移键控或AM信号。在通信系统的FPGA原型验证中我经常用DDS来生成可编程的载波并结合数字调制器如QPSK, 16QAM快速搭建一个发射机链路。这种全数字化的方式使得修改调制方式、符号率等参数变得非常快捷。5.2 线性扫频与任意波形生成DDS是生成线性调频信号的理想选择。只需要让频率控制字FTW以一个固定的斜率即二阶的频率变化率随时间累加即可。这可以通过在FTW寄存器前再加一个累加器来实现这个累加器的输入是“频率步进字”。这种架构被称为“DDS with Chirp”。更进一步DDS的波形查找表里存储的可以不是正弦波而是任何你想要的波形数据。只要把一个周期的任意波形数据存入ROMDDS就能将它周期性播放出来这就是任意波形发生器的基础。在医疗超声成像系统中就需要DDS产生特定形状的激励脉冲以优化成像效果。5.3 多通道与正交输出在很多通信和雷达应用中需要一对相位严格相差90度的正交信号。用DDS实现这一点非常优雅。我们可以让一个查找表输出正弦值另一个查找表输出余弦值。更高效的做法是利用正弦/余弦的相位关系只存储一个正弦表然后通过相位偏移来获得余弦值。例如余弦地址 正弦地址 2^(ADDR_WIDTH-2)对应π/2的相位差。如果需要多个相干的本振信号可以实例化多个DDS核心并让它们共享同一个相位累加器但使用不同的相位偏移地址。这样可以确保所有输出信号同源同频具有确定的相位关系这对于相控阵雷达等应用至关重要。5.4 实战中的时钟与同步设计DDS的性能极度依赖于时钟质量。一个抖动很大的时钟会直接将抖动传递给输出信号恶化其相位噪声。在PCB设计时必须为FPGA提供一颗低相位噪声的晶振或时钟发生器作为DDS的系统时钟源。在FPGA内部这个时钟应通过全局时钟网络分配到DDS模块以最小化时钟偏斜。另一个容易忽略的问题是跨时钟域。如果频率控制字FTW来自一个较慢的配置总线如AXI-Lite而DDS核心运行在高速时钟域那么FTW的更新必须经过可靠的跨时钟域同步处理如使用两级同步器否则可能导致相位累加器在错误的时间采样到不稳定的FTW值引起输出频率的毛刺。5.5 利用厂商IP核加速开发虽然自己写DDS代码很有成就感但在时间紧迫的商业项目中直接使用Xilinx的DDS Compiler IP核或Intel的NCO IP核往往是更明智的选择。这些IP核经过高度优化支持几乎所有高级功能调制、扫频、多通道、可编程相位偏移等并且提供了友好的图形化配置界面和详细的仿真模型。以Xilinx DDS Compiler IP为例你只需要在Vivado中配置输出频率范围、相位位宽、输出位宽、是否需要正余弦对、是否需要相位通道等参数工具就会自动生成最优的架构可能混合使用查找表和CORDIC。它还会自动生成AXI4-Stream或AXI4-Lite接口方便与处理器或其他逻辑集成。使用IP核不仅能节省大量开发和调试时间还能获得更佳的面积和性能。我的经验是除非有非常特殊的定制化需求例如非标准的波形、奇特的相位累加算法否则优先考虑使用成熟的IP核。