直接数字频率合成器(Direct Digital Synthesizer,DDS),是一种频率合成技术,具有相对带宽大、频率转换速度快、相位分辨率高、连续性好等优点,在数字信号处理中常用于调制信号的生成,模块设计较为简单,频率、相位容易控制,多用于无线通信领域。
DDS发生器的组成原理精髓在于对“模板”信号在单个周期内的采样,在系统工作频率一定的情况下,输出信号频率和周期内的取样点数有着直接的关系,举个栗子,假设基波信号 U(t)=sin(2pift+θ )=sin( 2pit ) ,* 在0~2Π内
等分周期,在相同的系统时钟下采用不同的抽样点数进行抽样,如下图所示:
以*Π/4 *为步进在单个周期内抽样
以*Π/8 *为步进在单个周期内抽样
可以很明显看出,相同系统时钟下使用不同的抽样点数,可以得到不同的输出频率;基本组成架构如下,系统时钟驱动频率控制字(抽样间隔)逐次累加生成存储着基波数据ROM的对应抽样地址,相位控制字主要用来决定基波的起始相位;
在FPGA中开辟一块Block RAM用于存储对应的“模板”信号,也就是要输周期信号的一个完整周期,输出数据位数决定采样波形存储ROM的宽度,数据深度与采样精度有关,累加器用于按频率控制字步长控制等间隔采样精度,相位寄存器用于锁定波形发生起始的位置,生成的周期数列作为ROM表的驱动地址,完成对"模板"信号不同频率的抽样;
模块设计前需要先准备ROM初始化文件“ .coe ”,生成方式可以使用工具或者MATLAB,下面是个人使用的一个基于MATLAB的coe文件生成代码;
clc;clear;close all;
width = 10;
depth = 2048;
t = linspace(0,2*pi,depth);
sin_val = sin(t);
% %cos_val = cos(t);
plot(t,sin_val,'--');
sin_val = fix(sin_val*(2^width-1)/2 + 0.5); %四舍五入
% %cos_val = fix(cos_val*(2^width-1)/2 + 0.5);
sin_val(find(sin_val< 0))=sin_val(find(sin_val< 0)) + 2^width; %求补码
addr = [0:depth - 1];
file = fopen('sin1024.coe','wt');
fprintf(file,'MEMORY_INITIALIZATION_RADIX=10;n);
fprintf(file,'MEMORY_INITIALIZATION_VECTOR=n');
for i=1:depth
fprintf(file,'%04X : %04X;n',addr(i), sin_val(i));
end
fprintf(file,'END;n');
fclose(file);
模块设计为便于修改添加部分参数定义,在有不同位宽需求时可以只修改参数和ROM模块IP即可实现;频率计算公式不在推到,直接给出:
其中K为频率控制字,N为相位累加器位宽,f0为模块输出频率,fC为系统时钟频率;举个例子,设系统时钟为50Mhz,相位宽度10Bit,要输出1Mhz的信号,则K=(2^101)/50; *设计代码如下,使用时只需添加ROM模块的IP,然后就可以例化工程使用:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: nhike
// Engineer: chenyivi
//
// Create Date: 2019/11/03 19:25:35
// Design Name:DDS_ROM_IP
// Module Name: DDS_ROM
// Project Name: DDS_ROM_IP
// Target Devices: zynq7010
// Tool Versions:1.0
// Description: WaveFrom
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DDS_ROM(
clk, //系统时钟
rst_n, //系统复位
Freword, //频率控制参数
Phaword, //初始相位控制参数
WaveDataOut //输出信号
);
parameter FrequencyBitWidth = 32;
parameter PhaseBitWidth =10;
parameter DataOutBitWidth= 10;
input clk;
input rst_n;
input [FrequencyBitWidth-1:0] Freword;
input [PhaseBitWidth-1:0] Phaword;
output [DataOutBitWidth-1:0] WaveDataOut;
reg [FrequencyBitWidth-1:0] Freword_temp;
reg [PhaseBitWidth-1:0] Phaword_temp;
wire [PhaseBitWidth-1:0] WaveAddData;
always@(posedge clk or negedge rst_n)begin //data latch.
if(!rst_n)begin
Freword_temp <= 32'b0;
Phaword_temp <= 10'b0;
end
else begin
Freword_temp <= Freword;
Phaword_temp <= Phaword;
end
end
reg [FrequencyBitWidth-1:0] cnt;
always @(posedge clk or negedge rst_n)begin //Sampling control.
if(!rst_n)
cnt <= 0;
else
cnt <= cnt + Freword_temp;
end
assign WaveAddData = cnt[FrequencyBitWidth-1:FrequencyBitWidth-(DataOutBitWidth + 1)] + Phaword_temp; //Data precision interception
WaveRom WaveRomBase (
.clka(clk),
.addra(WaveAddData),
.douta(WaveDataOut)
);
endmodule
下面是仿真结果和RTL:
以上实现均在Vivado中验证,Quartus使用方法与上述一致;
全部0条评论
快来发表一下你的评论吧 !