DDS信号发生器简介
DDS即为直接数字频率合成(Direct Digital Synthesis)技术,借助DDS技术和数模转换器,能够输出任意形状、任意频率的波形。DDS在实现信号发生器制作、信号倍频,以及在调制系统中产生载波等方面具有重要作用。
DDS信号发生器原理
如何输出任意波形
输出任意波形的过程,就是按照一定的“时间——电压”规律,在特定时间输出特定模拟电压的过程。在模拟电路中,时间和幅值都是连续的,一个周期内存在着无穷多个时间点,各时间点对应各自的模拟电压值,组合成了相应的波形。
通过DDS技术产生波形,同样依赖于各时间点上的电压组合。不同的是,与模拟电路相比,数字电路中存在两个离散量:首先是时间,数字电路中对于时间的记录是通过时钟控制计数器来实现的,计时的精度由时钟频率来决定,这决定了数字电路在一段时间内能取到的时间点是有限的(例:同样是3s内,数字电路采用1Hz时钟计时,对应计时精度是1s,只能取到1s,2s,3s这几个时间点,而模拟电路的时间连续,时间精度无穷小,能取到无穷多个时间点);其次是输出电压,数字电路中只存在代表0和1的高低电平,无法实现模拟电路中的电压任意取值。
由于时间的离散性,DDS合成的信号是由有限个点组成的,这些点被称为“采样点”,选取的采样点数目N会对波形效果及信号频率造成影响。首先,从波形效果角度来说:N过小,会导致相邻采样点间电压跨度太大,导致波形在纵向跨度太大,效果不佳;N越大,波形效果越好,但也会占用更多的逻辑资源;其次,从信号频率角度来说,系统时钟频率f0是固定的,若负责记录时间的计数器在每次系统时钟上升沿进行加1(此情况下的输出信号频率称为基频),则输出所有采样点所需的时间为(1/f0)*N,对应输出信号的频率f0/N。故在选取采样点数目时,应综合考虑波形效果与输出信号的基频要求。
确定好采样点的数目后,下一步要针对各采样点输出相应的模拟电压。由于输出电压的离散性,数字电路需要借助数模转换器(DAC)来输出模拟电压,而DAC输出模拟电压的大小,取决于电路向DAC输入的数字量。因此,问题转化为如何在各采样点向DAC输入特定的数字量。这一过程通常调用ROM核来实现:首先,利用MATLAB,将各采样点作为地址,对应的DAC数字量作为各地址内的数据,生成存储着波形“时间——电压“关系的mif文件;然后调用ROM核,以系统时钟为ROM核的时钟,将负责记录时间的计数器结果作为地址,控制ROM核在每个时钟上升沿根据当前输入的地址对mif文件中相应地址的数据进行读取、输出。
综上,DDS信号源的基础设计框图如下:
图1
2. 如何调整波形频率
系统时钟是固定的,故输出波形的一个完整周期所用时间取决于一个周期内需要输出的采样点数目;而在mif文件生成后,采样点的总数已经固定,所以我们从计数器下手,通过改变计数器的变化步长,改变实际输出的采样点数目,达到改变波形频率的效果。
例如,当计数器的变化步长为1时,cnt<=cnt+1<>,每次时钟上升沿引起ROM核的地址输入变化为1,使ROM核按照顺序依次读取各个采样点的数据进行输出,波形频率=基频=(系统时钟频率f0/采样点总数N);而改变计数器变化步长为2时,cnt<=cnt+2<>,ROM核地址的变化步长也为2,每隔一个采样点读取一次数据,读取了总数一半的采样点,所用时间自然也减半,波形频率=2*基频。依此类推,通过改变计数器的变化步长,即可实现对基频的倍频。
故在图1基础上,修改DDS设计如图2,即可实现对波形频率的调整:
图2
3. 如何生成mif文件
利用MATLAB生成mif文件的步骤,依次分为:针对相位进行采样;根据相位确定波形函数值;将波形函数值扩大到DAC的数字输入量;按照mif文件格式对数据进行输出。
MATLAB源码及注释如下(此处只生成了正弦波的mif文件):
%设定采样点数,DAC位数,ROM深度
N=200;%取采样点数目为200
DAC=12;%DAC的位数取决于实际的DAC芯片,常用的有8,10,12位
depth=256; %设置ROM深度
%对相位进行采样
x=linspace(0,2*pi,N);
%由于DAC只能输出正电压,故需将函数平移到纵轴的正半轴,函数值范围变为[0,2]
y1=sin(x)+1;
%将函数值转化为DAC的数字输入量
a=(2^DAC-1-1)/2;
y2=ceil(y1*a);%sin
%按照mif文件格式,生成sin函数的mif文件
fid = fopen('sin.mif','wt');
fprintf(fid,'DEPTH=%d;\n',depth);
fprintf(fid,'WIDTH=%d;\n',DAC);
fprintf(fid,'ADDRESS_RADIX = UNS;\n');%% 指定地址为无符号十进制
fprintf(fid,'DATA_RADIX = UNS;\n'); %% 指定数据为无符号十进制
fprintf(fid,'CONTENT\t');
fprintf(fid,'BEGIN\n');
if(N<<>depth)
for data_i=0:1:N-1
fprintf(fid,'\t%d\t:\t%d;\n',data_i,y2(data_i+1));
end
for empty_i=N:1:depth-1
fprintf(fid,'\t%d\t:\t%d;\n',empty_i,0);
end
else
for data_i=0:1:N-1
fprintf(fid,'\t%d\t:\t%d;\n',data_i,y2(data_i+1));
end
end
fprintf(fid,'END\n');
fclose(fid);
DDS信号发生器仿真
设定系统时钟为2MHz,采样点数为200,仿真产生基频为10kHz的正弦波和调节频率后得到的20kHz正弦波。(mif文件必须和ROM核放于同一文件内,否则不能读取)
源代码:
module DDS(clk,rst_p,freq,sin_1,sin_2);
input clk; /*2MHz*/
input rst_p; /*高电平复位*/
input[7:0] freq; /*频率控制字*/
/*选取12位DAC*/
output[11:0] sin_1; /*输出基频*/
output[11:0] sin_2; /*输出调节频率后的的波形*/
/*采样点数为200,在0-199计数*/
reg[7:0] dds_cnt1; /*控制输出基频的波形*/
reg[7:0] dds_cnt2; /*控制输出调节频率后的的波形*/
always@(posedge clk orposedge rst_p)
begin
if(rst_p)
dds_cnt1<=<>8'd0;
else
begin
if(dds_cnt1==8'd199)
dds_cnt1<=<>8'd0;
else
dds_cnt1<=<>dds_cnt1+8'd1;
/*在计数器变化步长不为1时,若仍采用判断是否与最大计数值相等的方式来控制计数清零,可能会出现计数值超过最大值的情况。*/
/*例如,当计数器变化步长为2时,计数值直接由198跳到200,没有经过199的状态,会在200的基础上继续增加,导致波形错误。*/
/*所以,此处将“计数值是否大于最大值”作为计数清零的条件。*/
if((dds_cnt2+freq)>8'd199)
dds_cnt2<=<>8'd0;
else
dds_cnt2<=<>dds_cnt2+freq;
end
end
sin_ROM U1(
.address(dds_cnt1),
.clock(clk),
.q(sin_1)
);
sin_ROM U2(
.address(dds_cnt2),
.clock(clk),
.q(sin_2)
);
endmodule
仿真激励:
`timescale1 us/1 ps
module DDS_vlg_tst();
reg eachvec;
reg clk;
reg[7:0] freq;
reg rst_p;
wire[11:0] sin_1;
wire[11:0] sin_2;
DDS i1 (
.clk(clk),
.freq(freq),
.rst_p(rst_p),
.sin_1(sin_1),
.sin_2(sin_2)
);
initial
begin
clk=1;
rst_p=1;
freq=8'd2;
#0.501;
rst_p=0;
end
always
begin
#0.25/*时钟周期=0.25*1us*2=0.5us,2MHz*/
clk=!clk;
end
endmodule
仿真波形: