DDS(Direct Digital Synthesizer)技术是一种全新的频率合成方法,是从相位概念出发直接合成所需波形的一种频率合成技术,通过控制相位的变化速度,直接产生各种不同频率、不同波形信号的一种频率合成方法。
系统的核心是相位累加器,其内容会在每个时钟周期(system clock)更新。相位累加器每次更新时,存储在Δ相位寄存器中的数字字M就会累加至相位寄存器中的数字。假设Δ相位寄存器中的数字为00…01(即M=1),相位累加器中的初始内容为00…00。相位累加器每个时钟周期都会按00…01(M=1)更新。如果累加器为32位宽,则在相位累加器返回至00…00前需要2^32(超过40亿)个时钟周期,周期会不断重复。
相位累加器的截断输出用作正弦(或余弦)查找表的地址。查找表中的每个地址均对应正弦
波的从0°到360°的一个相位点。查找表包括一个完整正弦波周期的相应数字幅度信息。
(实际上,只需要90°的数据,因为两个MSB中包含了正交数据)。因此,查找表可将相位
累加器的相位信息映射至数字幅度字,进而驱动DAC。图3用图形化的“相位轮”显示了这
一情况。
考虑n = 32,M = 1的情况。相位累加器会逐步执行2^ 32 (2^n/M)个可能的输出中的每一个,直至溢出并重新开始。相应的输出正弦波频率等于输入时钟频率 2 ^ 32分频。若M=2,相位累加器寄存器就会以两倍的速度“滚动”计算,输出频率也会增加一倍。以上内容可总结如下:
DDS系统主要由相位累加器、波形存储器、数模(D/A)转换器和低通滤波器等四个大的结构组成,其结构框图如下图所示。
参考时钟:
图中,参考频率f_clk为固定值,一般我们选择系统时钟(system clock),这里设置的是100MHz。
频率控制字:
用来调整输出信号的频率。如何根据参考频率得到输出频率,DDS IP的官方文档给出了相应公式。
相位控制字:
相位累加器:
由N位加法器与N位累加寄存器构成,它根据频率控制字k,完成相位值的累加,并将此累加值输入到波形存储器中。
波形存储器:
将相位累积器的值作为当地址,查找与相位值对应的信号数据,输出到D/A转换器。
D/A转换器:
将波形存储器输出的数字量转换为与之对应的模拟量。
低通滤波器:
由于D/A转换器存在量化误差,输出波形中存在混叠,需要在输出端使用低通滤波器进行滤波,提高信号的输出性能。
需要注意的是,上面的频率分辨率(frequency resolution)的值是算出来的,这个值必须和summer的频率分辨率保持一致。100M/(2^20)=95.36743
`timescale 1ns / 1ps
module top(
input sys_clk ,// 系统时钟
input rst_n ,// 系统复位
input [1:0] key_PINC ,// 频率控制字对应的按键
input [1:0] key_POFF // 相位控制字对应的按键
);
//-----------频率控制字模块
wire [23:0] PINC ; //频率字
Fword_set Fword_set_inst(
//input
.clk (sys_clk ),
.rst_n (rst_n ),
.key_PINC (key_PINC ),
//output
.PINC (PINC )
);
//-----------相位控制字模块
wire [23:0] POFF ; //相位字
POFF_set POFF_set_inst(
//input
.clk (sys_clk ) ,
.rst_n (rst_n ) ,
.key_POFF (key_POFF ) ,
//output
.POFF (POFF )
);
//-------------DDS模块
//input
wire [0:0] fre_ctrl_word_en ;
//output
wire [0:0] m_axis_data_tvalid ;
wire [47:0] m_axis_data_tdata ;
wire [0:0] m_axis_phase_tvalid ;
wire [23:0] m_axis_phase_tdata ;
assign fre_ctrl_word_en=1'b1;
dds_sin dds_sin_inst (
.aclk (sys_clk ), // input wire aclk
.s_axis_config_tvalid (fre_ctrl_word_en ), // input wire s_axis_config_tvalid
.s_axis_config_tdata ({POFF,PINC} ), // input wire [47 : 0] s_axis_config_tdata
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_axis_data_tdata ), // output wire [47 : 0] m_axis_data_tdata
.m_axis_phase_tvalid (m_axis_phase_tvalid ), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata (m_axis_phase_tdata ) // output wire [23 : 0] m_axis_phase_tdata
);
endmodule
`timescale 1ns / 1ps
//
// 通过按键来选择对应的频率控制字,进而选择对应的信号频率
//
module Fword_set(
input clk ,
input rst_n ,
input [1:0] key_PINC ,
output reg [23:0] PINC
);
//always@(posedge clk or negedge rst_n)
//begin
// if(!rst_n)
// key_sel <= 4'd0;
// else
// key_sel <= key_sel;
//end
// The output frequency(f_out ) , of the DDS waveform is a function of the system clock frequency(f_clk ) .
// the phase width, that is, number of bits (B ) in the phase accumulator
// and the phase increment value (deta_theta) .
// The output frequency in Hertz is defined by:f_out=f_clk*deta_theta/(2^B)
// fre_ctrl_word是如何确定的?
// 根据IP核的summery, phase width=20bits Frequency per channel=100MHz
// 输出频率的计算公式f_out=f_clk*deta_theta/(2^B)=100M* 104857/(2^20 )= 10M
always@(*)
begin
case(key_PINC)
0: PINC <= 'h28f5; //1Mhz 10485 每次相位增加的值 deta_theta
1: PINC <= 'h51eb; //2Mhz 20971
2: PINC <= 'ha3d7; //4Mhz 41943
3: PINC <= 'h19999; //10Mhz 104857
endcase
end
endmodule
`timescale 1ns / 1ps
//
// 通过按键来选择对应的相位控制字,进而选择对应的信号初始相位
/
module POFF_set(
input clk ,
input rst_n ,
input [1:0] key_POFF ,
output [23:0] POFF
);
//always@(posedge clk or negedge rst_n)
//begin
// if(!rst_n)
// key_sel <= 4'd0;
// else
// key_sel <= key_sel;
//end
// 根据IP核的summery, phase_width=20bits Frequency per channel=100MHz
// 输出相位的计算公式:POFF=phase*phase_modulus/360
// phase:想要输出的相位,输入0~360即可
// phase_modulus:相位系数为2^phase_width-1=2^20-1,
// phase_width即相位位宽,在生成IP的summary可以查看
reg [8:0] phase; //0-360
always@(*)
begin
case(key_POFF)
0: phase <= 'h0; //0
1: phase <= 'h5a; //90
2: phase <= 'hb4; //180
3: phase <= 'h10e; //270
endcase
end
assign POFF=phase*1048575/360;
endmodule
`timescale 1ns / 1ps
module sim_top;
reg sys_clk ;
reg rst_n ;
reg [1:0] key_PINC;
reg [1:0] key_POFF;
//例化源文件
top top_inst(
.sys_clk (sys_clk ),
.rst_n (rst_n ),
.key_PINC (key_PINC ),
.key_POFF (key_POFF )
);
initial
begin
//初始化
sys_clk=0;
rst_n=0;
key_PINC=2'd0;
key_POFF=2'd0; //30
#100
rst_n=1;
key_PINC=0; //1Mhz 10485 每次相位增加的值 deta_theta
#4000
key_PINC=1; //2Mhz 20971
#4000
key_PINC=2; //4Mhz 41943
#4000
key_PINC=3; //10Mhz 104857
#4000
key_POFF=1; //60
#4000
key_POFF=2; //90
#4000
key_POFF=3; //180
end
// create clock;
always #5 sys_clk=~sys_clk;//每次间隔5ns,取一次反,也就是周期为10ns,所以频率为100MHz
endmodule