问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 31 人浏览分享

开启左侧

第五章:直接数字合成 (DDS)的使用

[复制链接]
31 0
       在上一章节,我们学习了NCO,这章我们将进一步解释直接数字合成 (DDS),通过Xilinx 的成熟IP来实现数字信号的生成,究竟NCO和DDS有什么区别呢?接下来将为你揭晓!
1 原理剖析
       DDS(Direct Digital Synthesizer,直接数字合成器)和 NCO(Numerically Controlled Oscillator,数控振荡器)是两个相关的概念,通常用于信号生成和频率合成领域。尽管它们有相似之处,但在功能和应用上有一些区别。以下是它们的主要区别和联系:
1. 定义和功能
  • DDS(直接数字合成器)
       DDS 是一种利用数字方法生成信号的技术或系统。它通常包括一个相位累加器、波形查找表、数模转换器(DAC)和后续的滤波器。DDS 可以生成正弦波、方波、三角波等多种波形,具有高频分辨率和快速频率切换的特点。
  • NCO(数控振荡器)
       NCO 是一种专门用于生成正弦波信号的数字振荡器。它是 DDS 的一个子集或特化形式,专注于正弦波的生成。NCO 的核心组件通常包括相位累加器和正弦查找表,设计更加简化,适用于频率合成和信号处理。
2. 波形生成能力
  • DDS
       DDS 可以生成多种波形(正弦波、方波、三角波等),因为它的波形查找表可以存储任意形状的波形数据。这使其在复杂信号生成和多样化应用中非常有用。
  • NCO
       NCO 通常只生成正弦波,主要用于频率合成和相位调制场景。它的设计目标是高效、简化,专注于正弦波的生成。
3. 复杂性
  • DDS
       DDS 的设计更复杂,因为它需要支持多种波形生成和更广泛的功能。它通常包含额外的模块,比如调制器、滤波器等。
  • NCO
       NCO 的设计相对简单,通常只需要相位累加器和正弦查找表即可实现基本功能。它是 DDS 的一个简化版本。
4. 应用场景
  • DDS
       DDS 广泛应用于通信系统、雷达、仪器仪表等需要多种波形生成和频率调制的场景。例如,DDS 可以用于生成调制信号、频率扫描信号等。
  • NCO
       NCO 通常应用于需要纯正弦波的场景,例如数字通信中的载波生成、频率合成器等。由于其设计简单,NCO 适合对资源要求较低的应用。
5. 性能和灵活性
  • DDS
       DDS 的性能和灵活性更高,支持复杂的调制方式和多波形生成,但这也意味着其资源消耗和实现成本更高。
  • NCO
       NCO 更专注于生成正弦波,设计简单,资源消耗较低,但灵活性和功能性不如 DDS。

DDS的工作原理
1.相位累加器
      DDS 的核心部件之一是 相位累加器。它的作用是生成一个不断递增的相位值,控制生成信号的频率。相位值通常以固定的增量递增,增量的大小决定了输出信号的频率。
假设一个基本的正弦波,其相位从0开始递增,周期为 T,相位的变化率为 Δφ = 2π。
如果相位增量Δφ 是固定的,则输出频率 (f) 可以通过相位增量来决定:
       f=Δφ/2πT​
其中,Δφ 是累加器的步长,它与所需的频率成正比。
2.波形查找表(LUT,Look-Up Table)
       波形查找表是 DDS 系统中的另一个关键组成部分。它存储了信号的标准波形,最常见的是 正弦波,也可以包含方波、三角波等。查找表的作用是根据相位累加器的输出值,在查找表中找到对应的波形样本。
       相位累加器生成的相位值会作为查找表的索引,查找表返回相应的波形值。例如,正弦波的查找表会返回正弦波在不同相位下的幅度值。
       由于波形查找表是离散的,因此输出信号是离散的采样点,通常需要后续的数模转换器来平滑输出。
3.数模转换器(DAC)
       数字信号从查找表中获取后,仍然是数字形式的。为了生成连续的模拟信号,DDS 系统需要使用一个 数模转换器(DAC) 将这些数字值转换为连续的模拟信号。DAC 的输出信号就是最终的模拟波形。
4.低通滤波器
       由于从查找表获得的信号是离散的,DAC 输出的信号也可能含有高频噪声(即采样频率的高频成分)。因此,通常会在输出端加一个 低通滤波器,以滤除这些不需要的高频分量,最终得到纯净的模拟信号。

DDS系统的核心组成
       1.相位累加器(Phase Accumulator)
       2.波形查找表(LUT)(Look-Up Table)
       3.数模转换器(DAC)
       4.低通滤波器
image.jpg

2 FPGA实现:使用DDS IP 输出正弦波
1.在Vivado中创建新工程或添加新源文件。
2.添加DDS Compiler IP核:
  • 在 "IP Catalog" 中搜索 "DDS Compiler "。
  • 配置IP核:
       System Clock (MHz): 50
       Parameter Selection: Hardware Parameter
       Hardware Parameter:
              Phase Width: 32
              Output Width: 16
       Implementation :
              Output Selection:Sine
       Control Signals :勾选ARESETn
       Phase Angle Increment Values :这里的值根据Summary 页面的数据以及你要输出的目标频率决定,
              如现在要输出采样率为50MHz,频率为1MHz的正弦波,则这个值为0101000111101011100001010011;
              输出采样率为50MHz,频率为5MHz的正弦波,则这个值为00011001100110011001100110011100。
       Addtional Summary :查看输出的正弦波频率。

IP 原理简要说明:
我们使用的是标准模式(Standard),根据官方手册的操作指南有:
image.jpg
DDS波形的输出频率fout是系统时钟频率fclk、相宽(即相位累加器中的比特数Bθ(n))和相位增量值(phase increment value)Δθ的函数。以赫兹为单位的输出频率定义为:
image.jpg
产生输出频率fout Hz所需的相位增量值(phase increment value)Δθ为:
image.jpg
合成器的频率分辨率(frequency resolution)Δf是时钟频率和相位累加器中采用的位数Bθ(n)的函数。频率分辨率可以通过以下方式确定:
image.jpg
结合上述的公式可得:
       Fout = Δθ * Δf
       由于我们Parameter Selection选择了Hardware Parameters,故我们需要手动算Δθ配置IP,例如我们需要产生采样率为50MHz,频率为1MHz的正弦波,当我们配置好Configuration Tab、Implementation Tab以及Detailed Implementation Tab后,可以从Summary中得到Δf,得到这些我们就可以填写Phase Angle Increment Values的值(Δθ)。
       如现在要输出采样率为50MHz,频率为1MHz的正弦波,则这个值为0101000111101011100001010011;
       输出采样率为50MHz,频率为5MHz的正弦波,则这个值为00011001100110011001100110011100。
3.DDS DDS Compiler IP 配置截图
image.jpg
image.jpg
image.jpg
image.jpg
image.jpg
image.jpg
4.编写dds代码顶层
module top (
    input                               I_sysclk_p                 ,//100Mhz差分时钟
    input                               I_sysclk_n                 ,//100Mhz差分时钟
    input                               I_rst_n                    ,//复位信号
    output               [  15: 0]      O_dds_data_1m                ,
    output               [  15: 0]      O_dds_data_5m               
);

/******************************************************************\
                            信号声明
\******************************************************************/
//clock
    wire                                clk_50m                    ;

//DDS
    wire                                dds_data_1m_valid           ;
    wire                                phase_tvalid_1m             ;
    wire               [  31: 0]        phase_tdata_1m              ;

    wire                                dds_data_5m_valid           ;
    wire                                phase_tvalid_5m             ;
    wire               [  31: 0]        phase_tdata_5m              ;

/******************************************************************\
                          时钟管理模块
\******************************************************************/

    clk_wiz_0 clock_and_reset
    (
      .clk_out1(clk_50m),

      .clk_in1_p(I_sysclk_p),
      .clk_in1_n(I_sysclk_n)
    );  

/******************************************************************\
                          DDS模块
\******************************************************************/

//dds产生采样率为5MHz的1MHz正弦信号

    dds_compiler_0 dds_32_16_1m (
      .aclk(clk_50m),
      .aresetn(I_rst_n),                                                         
      .m_axis_data_tvalid(dds_data_1m_valid),   
      .m_axis_data_tdata(O_dds_data_1m),      
      .m_axis_phase_tvalid(phase_tvalid_1m),  
      .m_axis_phase_tdata(phase_tdata_1m)   
    );

//dds产生采样率为250MHz的49MHz正弦信号

    dds_compiler_1 dds_32_16_49m (
      .aclk(clk_50m),
      .aresetn(I_rst_n),                                                        
      .m_axis_data_tvalid(dds_data_5m_valid),   
      .m_axis_data_tdata(O_dds_data_5m),      
      .m_axis_phase_tvalid(phase_tvalid_5m),  
      .m_axis_phase_tdata(phase_tdata_5m)   
    );

endmodule

代码说明:
1.上述代码实现了两个DDS的波形输出,调用xilinx的官方IP可以简单高效的验证我们的实现结果。
2.关键点在于Phase Angle Increment Values的配置,对于这部分感兴趣的用户可以自行查看官方手册,这里只做简要的介绍。
3 仿真验证:在Vivado中观察生成的正弦波
仿真代码如下:

`timescale 1ns / 1ps

module tb_top();

//变量定义
  reg I_sysclk_p;
  reg I_rst_n;
  wire [15:0] O_dds_data_1m;
  wire [15:0] O_dds_data_5m;

//信号初始化
  initial begin
    I_sysclk_p = 1;
    I_rst_n = 0;
    #1000 I_rst_n = 1;

  end

//100Mhz时钟
  always #5  I_sysclk_p = ! I_sysclk_p ;

  top  top_inst (
    .I_sysclk_p(I_sysclk_p),
    .I_sysclk_n(~I_sysclk_p),
    .I_rst_n(I_rst_n),
    .O_dds_data_1m(O_dds_data_1m),
    .O_dds_data_5m(O_dds_data_5m)
  );

endmodule

仿真现象如下:
image.jpg


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

10

粉丝

150

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版