DDS的相关实现方法

 DDS基本原理

DDS(Direct Digitial Synthesis):直接数字信号合成器

从图中我们可以看出DDS是由相位累加器、相位调制器、查找表(数据波形存储表ROM)以及D/A转换器组成。

相位累加器:相位以系统时钟周期为间隔进行等量增加,每个时钟周期相位增加一次,所有时钟周期累加在一起就构成了相位累加,故此将上述结构称为相位累加器。其映射关系式为

\Delta \theta =2\pi *\frac{​{N}'}{2^{n}}

上图中\Delta \theta为4个相位增量,即经过4个时钟周期相位的增量。

相位调制器:决定了输出信号的初始相位。

数据波形存储表:一个周期内的信号用多少位去存储,例如8位,它使用256个点存储一个周期的信号的幅值。

相位量化器:利用相位累加器输出的相位去寻址波形的查找表,由于在数字计算机中存储的数据类型是数字信息,故需要将模拟波形抽样量化

DDS的Matlab仿真

%% 利用Matalb对DDS进行仿真

clc;clear all;
f_out  = 1e6;       %输出频率
fs =  100e6 ;       %采样率 = 时钟频率
N=256;              %256个点,8位               
sin_rom = sin(2*pi*(0:N-1)/N);
figure(1);
plot((0:N-1),sin_rom, xlabel('点数'),title('单位周期正弦波'));%给出单位周期的正弦波

%假设用32位去存储单位周期的正弦波 实际只使用了8位存储
F_WORD=f_out/fs*(2^32);              %1Mhz 载波的频率控制字 f_out=fs*W/(N)
len = length(sin_rom)*fs/f_out;      % 在单位周期内输出信号的数据长度  fs/f_out表示一个周期采样几个点
F_ADDR = 0;                          %初始相位
rom_addr = 0;                        %ROM地址初始化
sin_1m = zeros(1,len);
for i = 1:len
    F_ADDR = F_ADDR + F_WORD;       %相位累加
    if(F_ADDR > 2^32)
        F_ADDR =  F_ADDR - 2^32;    %相位溢出
    end
    rom_addr = round(F_ADDR /2^24);
    %因此处F_WORD用32位宽的二进制表示 但ROM只有8位 依据数学计算 其ROM地址仅有高8位变化 所以上式要除以2的24次方
    if rom_addr == 0 
        rom_addr = 1;
    end
	sin_1m(i) =  sin_rom(rom_addr);
end
figure(2);
plot(sin_1m(1:len)), xlabel('点数'),title('一个周期的正弦波'); 

存储波形如下

通过DDS模拟仿真得图像

FPGA实现——基于ROM的DDS

使用matlab生成存储信号的COE文件

%% 创建一个含有N个点的频率为F的单位周期正弦信号(余弦、方波、锯齿波),用M位宽的二进制文本存储
%此处频率F不应该大于N,若大于就违反了奈奎斯特定理 即一个周期至少采样两个点才能完全恢复信号
%必须满足N/F>2;
clear all;clc
F=1;
N = 256 ;
M=8;
y = zeros(N , 1) ;%生成256行*1列的矩阵 
y_integer = zeros(N , 1) ;%生成256行*1列的矩阵
y_hex = zeros(N , 1) ;%生成256行*1列的矩阵,十六进制
x=cos(2*pi*F*(0:N-1)/N);%正弦信号
% x=sin(2*pi*F*(0:N-1)/N);%余弦信号
% x=square(2*pi*F*(0:N-1)/N,50);%square(t,duty_cycle)为产生周期为2*pi,占空比为0~100的方波信号  
% x = sawtooth(2*pi*F*(0:N-1)/N,0.5);%sawtooth(t,bia)产生周期为2*pi,峰尖值偏移度为0-1的锯齿波信号
for i = 1:1:N %循环1~256,累加1
    y(i,1) = round((2^(M-1)-1)*x(i))  ;%round为四舍五入函数,输出范围为-127~127的余弦波数据
end          
plot(y);%画图预览
fid = fopen('cos.coe','wt');    %创建一个名为cos_1024point.coe的文件 wt表示擦除里面内容重新写入数据以文本形式打开
%- COE 文件前置格式
fprintf( fid, 'MEMORY_INITIALIZATION_RADIX = 16;\n');                     
fprintf( fid, 'MEMORY_INITIALIZATION_VECTOR =\n');
%- 写数据
for i = 1:1:N
    if (y(i,1)<0)
       y_integer(i,1)=y(i,1)+2^M;%负数用补码表示
    else
       y_integer(i,1)=y(i,1);%正数的补码为原码
    end   
end    
%进制转换
y_hex= dec2hex(y_integer);%因为dec2hex只能转换正数,因此先将y取补码 因取值-127~127 故用两位16进制的数表示
for i = 1:1:N
    if(i == N)
        %最后一个点时,标点为分号,其余时候为逗号   
        fprintf(fid,'%c%c;',y_hex(i,1),y_hex(i,2));  %输出16进制数据
%       fprintf(fid,'%d,\n',y(i,1));  %输出10进制数据
    else
        fprintf(fid,'%c%c,\n',y_hex(i,1),y_hex(i,2));  %输出16进制数据
%       fprintf(fid,'%d,\n',y(i,1));  %输出10进制数据
    end
end
fclose(fid);%关闭文件
文件结构
 

顶层文件

module top_dds(
    input clk,
    input rst_n,
    output [7:0]signal
    );
    parameter F_WORD=32'd42949672,P_WORD=32'd0;
    wire [7:0] addr;
    reg [31:0] reg_addr;
    always@(posedge clk)begin
    if(!rst_n)
        reg_addr<=P_WORD;
    else
        reg_addr<=reg_addr+F_WORD;
    end
    
    assign addr=reg_addr[31:24];
    blk_mem_gen_0 dds_cos (
        .clka(clk),    // input wire clka
        .addra(addr),  // input wire [7 : 0] addra
        .douta(signal)  // output wire [7 : 0] douta
);  
endmodule

仿真文件

`timescale 1ns / 1ps
module tb_dds(

    );
    reg clk;
    reg rst_n;
    wire [7:0]signal;
    
 parameter PERIOD = 4'd10;

   always begin
      clk = 1'b0;
      #(PERIOD/2) clk = 1'b1;
      #(PERIOD/2);
   end
    
    initial begin
    rst_n=1'b0;
    #30
    rst_n=1'b1;
    end

top_dds u_top_dds(
     . clk(clk),
     . rst_n(rst_n),
     .signal(signal)
    );

endmodule

FPGA实现——基于IP核

顶层文件

`timescale 1ns / 1ps

module top_DDS_IP(
input clk,
output [7:0]out_data
    );
    wire data_tvalid=1'b1;
 dds_compiler_0 your_instance_name (
  .aclk(clk),                              // input wire aclk
  .m_axis_data_tvalid(data_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(out_data)    // output wire [7 : 0] m_axis_data_tdata
);
endmodule

仿真文件

`timescale 1ns / 1ps

module tb_top_dds_ip(

    );
    reg CLK;
    wire [7:0]out_data;
    
   parameter PERIOD = 5'd20;

   initial begin
      CLK = 1'b0;
      #(PERIOD/2);
      forever
         #(PERIOD/2) CLK = ~CLK;
   end
   
   top_DDS_IP u_top_DDS_IP(
    .clk(CLK),
    .out_data(out_data)
    );
endmodule


 本文参考

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值