前言
用RAM实现一个DDS,从原理上来说很简单,在实际使用的时候,可能没有直接使用官方提供的IP核来的方便。这个博客就记录一下,最近使用到的这个DDS IP。
1 基于相位截断的DDS
DDS IP核的内部的基本结构如下图所示,主要是一个基于相位截断的DDS。在数字信号处理中,经常会使用到DDS,其内部主要有一个相位累加器,一个ROM存储这正弦波的查找表。相位累加器在时钟的作用下对相位进行累加,每次的累加值是通过phase increment 来指定的。累加得到的结果,通过量化器,取其高位,低位舍去,再将这个量化后的相位值,输出到查找表,从查找表中得到最终的波形。
DDS的最终输出的信号的频率和系统时钟,相位宽度和相位自增量之间满足如下关系:
其中ΔΘ 是相位自增量,BΘ(n)是相位的位宽,也就对应这查找表的深度为2^BΘ(n)
手册中也给出了一个例子,来举例说明DDS的输出频率和这几个系统参数之间的关系,其中系统时钟120MHz,相位宽度为10bit,相位增量为12,输出的频率通过上面的式子就可以计算出来。
在实际的工程中,一般希望DDS能够生成不停频率的信号,例如在DDC或者DUC中,希望产生一个高频的载波频率,通常使用DDS来产生一个高频的正弦信号。因此在实际使用的时候更加关注DDS的相位增量。因为通过控制相位增量就能过后产生不同的频率。相位增量的计算公式如下。
下面以一个具体的例子来说明DDS是如何工作的。
2 DDS IP的使用和参数配置
在配置这一TAB,需要设置系统的时钟,这个时钟也就是上面公式当中的参考时钟,然后可以选通道数和模式,这里就保持默认就可以了。
再之后就是期望最终生成的信号的一些参数的设置。可选选择系统参数模式,或者选择硬件参数模式,一般都选择系统参数模式,直接方便。
在系统参数中,动态范围最终对应这输出信号的幅度,其计算公式如下:20lg(Amp),其中AMP就是信号的幅度。比如下图中,动态范围为72,那么他就可以表示幅度为4096的一个正弦信号。[20lg(4096)] = 72dB;
在下面是频率分辨率,对应这最小的频率变化,是由系统时钟和相位深度计算得到的,比如系统时钟40MHz,相位宽度为32bit,那么计算的频率分辨率就是[40*106/(232)] = 0.01。
在实现这一TAB,可以设置相位增量是固定的还是可以更改的,相位增量能够控制输出的正余弦信号的频率,这里选择可更改的,便于在之后的使用中生成不同频率的信号。需要注意的时候,生成的信号需要满足奈奎斯特抽样定理,也就是抽样时钟必须是被采样信号频率的两倍。以这个例子来说,系统时钟为40M,那么,最多可以生成频率为20MHz的正余弦信号。
除了相位自增量外,初始的相位也是可以通过参数来修改的,在这里就默认不修改了。
在输出信号的时候,可以同时输出正余弦信号,这在正交调制解调的过程中十分有用。
除此之外,还可以输出当前的相位。
在具体实现这一TAB中,保持默认就可以,是用来配置接口。根据手册上描述的,可以选择这些信号来生成不同类型的接口。这些接口都是AXI-Stream 类型的接口,只需要满足AXIS的规则就好了。
在输出频率这一TAB,可以输入期望的输出频率,若有多个通道,可以选择给多个通道设定初始的频率输出值。这个期望频率在前面选择了相位增量式可编程的时候就没什么用了。因为最终输出的信号的频率是通过相位增量来控制的。
到这里这个IP基本就配置完了。可以看一下总结,和最终输出信号的接口信息。需要特别注意的就是输出的正余弦信号在输出总线上所占据的bit‘位。DDS IP通过一个AXIS接口同时输出正弦信号和余弦信号。就比如在这个例子中,m_axis_data[11:0]传输的就是余弦信号,其中m_axis_data[11]是余弦信号的符号位。
m_axis_data[27:16]传输的是正弦信号,其中m_axis_data[27]是正弦信号的符号位。
3 DDS IP测试
写个Testbench测试一下:
`timescale1ns/1ps moduletb_test_dds(); regclk; reg[31:0]frequency; regfreq_vld; wirem_axis_data_tvalid; wire[31:0]m_axis_data_tdata; wiredds_vld; wire[11:0]dds_cos; wire[11:0]dds_sin; assigndds_vld=m_axis_data_tvalid; assigndds_cos=m_axis_data_tdata[11:0]; assigndds_sin=m_axis_data_tdata[27:16]; //parameterSYS_CLK=40000000;//systemclock40M //parameterCLK_6M=6000000;//frequency6M //parameterCLK_400K=400000;//frequency400K //parameterCLK_2M=2000000;//frquency2M //parameterPHASE_WIDTH=32;//相位宽度为32bit //clock initialbegin clk=0; forever#(12.5)clk=~clk;//40Msystemclokc end initialbegin frequency='d0; freq_vld=1'b0; repeat(3000)@(posedgeclk); //产生一个频率为400KHz的复指数 frequency=32'd42949672;//CLK_400K*(2^PHASE_WIDTH)/SYS_CLK freq_vld=1'b1; @(posedgeclk) freq_vld=1'b0; repeat(3000)@(posedgeclk); //产生一个频率为4MHz的复指数 frequency=32'd214748364;//CLK_4M*(2^PHASE_WIDTH)/SYS_CLK freq_vld=1'b1; @(posedgeclk) freq_vld=1'b0; repeat(3000)@(posedgeclk); //产生一个频率为6M的复指数 frequency=32'd644245094;//CLK_6M*(2^PHASE_WIDTH)/SYS_CLK freq_vld=1'b1; @(posedgeclk) freq_vld=1'b0; end dds_compiler_0inst_dds( .aclk(clk),//inputwireaclk .s_axis_config_tvalid(freq_vld),//inputwires_axis_config_tvalid .s_axis_config_tdata(frequency),//inputwire[31:0]s_axis_config_tdata .m_axis_data_tvalid(m_axis_data_tvalid),//outputwirem_axis_data_tvalid .m_axis_data_tdata(m_axis_data_tdata)//outputwire[31:0]m_axis_data_tdata ); endmodule
可以看到生成了不同频率的正余弦信号。一开时的时候。没有给出相位增量,所以固定输出2M的信号,之后给出了相位增量后,输出了400K 信号。
-
Xilinx
+关注
关注
71文章
2153浏览量
120795 -
DDS
+关注
关注
21文章
629浏览量
152461 -
IP核
+关注
关注
4文章
324浏览量
49364
原文标题:Xilinx DDS IP使用
文章出处:【微信号:Hack电子,微信公众号:Hack电子】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论