基于FPGA的DDS算法实现(附ISE联合Modelsim仿真结果)

声明:这篇博客是在充分参考前人成果的基础上写成的,如有侵权,请联系我作进一步处理。此外,这是我第一次写博客,描述不准确之处敬请指出。如有疑问,可在下方留言。祝好。

1.DDS原理介绍

随着数字技术在仪器仪表和通信系统中的广泛使用,可从参考频率源产生多个频率的数字控制方法诞生了,即直接数字频率合成DDS(Direct Digital Frequency Synthesis)[1]。DDS可根据需要产生指定频率的波形信号,如正弦波、三角波、锯齿波、方波等,其结构框图如下图所示。
如上图所示,通过串口发送频率控制字、幅值控制字、波形选择,就能在DAC处得到相应的波形信号。其具体过程如下:首先,给定的频率控制字作为累加值,每当时钟信号1有效时,相位累加器就进行一次累加;然后,对相位累加器的输出值进行截位操作,并将截位的结果赋给相位寄存器;相位寄存器的输入值作为地址值读取事先存储在查找表上的波形信息,其输出进入幅值放大器并结合给定的幅值控制字调整波形幅值,最后将信号输入到DAC进行输出,得到对应的指定频率和幅值的波形。简而言之,就是事先将不同波形存储在不同的ROM上,通过改变频率控制字来控制波形频率,实现变频的功能,再通过幅值控制器进行相应增益处理,可实现调幅功能。

2.数学分析

DDS的数学过程比较简单,主要的几个参数为输入时钟频率fc,输出频率fo,相位累加器位宽n,频率控制字K,幅值控制字A。输出信号的频率计算公式如下[2]:
fo=fc* K/2^n

记DDS输出最小频率,即分辨率为vf,则其表达式为[3]:
vf=fc/2^n

记DDS输出最大频率为fmax,它由奈奎斯特定理决定,即fmax=fc/2。实际中考虑有其它影响因素,一般有不超过时钟频率的40%。

记输出为y(t),以Waveform表示所选波形,则最终波形表达式如下:
y(t)=AWaveform(2πfot)

3.DDS实现

下面分别介绍相位累加器(包含相位寄存器部分内容)、查找表、幅值控制器的实现方法,并给出关键代码语句。
相位累加器[4]

module PHASE_ADDER
(//inputclk,rst,fre_value,//output   cnt
);input           clk;
input         rst;
input  [15:0] fre_value;//频率控制字
output [15:0] cnt;wire   [15:0] fre_value;
reg      [15:0] cnt; //相位累加寄存器always @(posedge clk or posedge rst) if(rst)cnt <= 0;elsecnt <= cnt + fre_value;  //计数器步长Kendmodule

查找表

module DDS_Table
(//inputclk,addr,//outputdout_sin,dout_triangel,dout_saw,sin_Test,dout_square
);input          clk;
input  [9:0] addr;
output [9:0] dout_sin;
output [9:0] dout_triangel;
output [9:0] dout_saw;
output [9:0] sin_Test;
output [9:0] dout_square;wire   [9:0]  sin;
wire     [9:0]  triangel;
wire   [9:0]  saw;
wire   [9:0]  square;assign  dout_sin        = sin;
assign  dout_triangel = triangel;
assign  dout_saw         = saw;
assign  sin_Test         = sin;
assign  dout_square   =square;
ROM_IP_CORE04 Sin
(//input.clka   (clk ),  // input clka.addra    (addr),  // input [9 : 0] addra//output.douta   (sin )   // output [9 : 0] douta
); //addr作为地址值,读取存储在ROM里的正弦波幅度信息ROM_IP_CORE09 Triangel
(//input.clka   (clk         ), // input clka.addra (addr        ), // input [9 : 0] addra//output.douta    (triangel )  // output [9 : 0] douta
);//addr作为地址值,读取存储在ROM里的三角波幅度信息ROM_IP_CORE06 Saw
(//input.clka   (clk         ), // input clka.addra (addr        ), // input [9 : 0] addra//output.douta    (saw      )  // output [9 : 0] douta
);//addr作为地址值,读取存储在ROM里的锯齿波幅度信息ROM_IP_CORE12 Square
(//input.clka   (clk         ), // input clka.addra (addr        ), // input [9 : 0] addra//output.douta    (square   )  // output [9 : 0] douta
);//addr作为地址值,读取存储在ROM里的方波幅度信息
endmodule

程序运行时,事先需要把波形存储在ROM中,具体做法如下[5]:
1)首先生成几种波形的coe文件。
以正弦波为例,coe文件可用MATLAB生成:

x=linspace(0,2*pi,1024);%一个周期采样点取1024个点,取多少个点由ROM地址线位宽决定,N为地址线可采样2^N个点。
y1=sin(x);
y2=ceil(y2*511);
%生成sin函数coe文件
fid = fopen('sin.coe','wt');
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n');
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');//这两句是生成coe文件所需要的
for i = 1:1:2^10fprintf(fid,'%16.0f',y2(i));if i==2^10fprintf(fid,';');elsefprintf(fid,',');endif i%15==0fprintf(fid,'\n');end
end
fclose(fid);

2)调用ROM的IP核时,把存储了波形信息的coe文件加载到ROM中,如下图所示:

幅值放大器

module Amplifier
(//inputgain_o,sin_o,triangel_o,saw_o,square_o,//output sin_f,triangel_f,saw_f,square_f);
input [3 :0] gain_o;
input [9:0] sin_o;
input [9:0] triangel_o;
input [9:0] saw_o;
input [9:0] square_o;
output[13:0] sin_f;
output[13:0] triangel_f;
output[13:0] saw_f;
output[13:0] square_f;wire [13:0] sin;
wire [13:0] triangel;
wire [13:0] saw;
wire [13:0] square;assign sin_f         =sin;
assign triangel_f    =triangel;
assign saw_f            =saw;
assign square_f     =square;Multiplier Multiplier_sin
(.a(sin_o), // input  [9 : 0] a.b(gain_o),// input  [3 : 0] b.p(sin)     // output [13: 0] p
);Multiplier Multiplier_triangel
(.a(triangel_o), // input  [9 : 0] a.b(gain_o),     // input  [3 : 0] b.p(triangel)    // output [13: 0] p
);Multiplier Multiplier_saw
(.a(saw_o),  // input  [9 : 0] a.b(gain_o), // input  [3 : 0] b.p(saw)     // output [13: 0] p
);Multiplier Multiplier_square
(.a(square_o), // input  [9 : 0] a.b(gain_o),   // input  [3 : 0] b.p(square)    // output [13: 0] p
);
endmodule

顶层文件

module dds_top
(input                   rst,input                   gclk,input             [15:0] fre_value,input  signed  [15:0] gain_o,output signed [13:0] sin_ok,output signed [13:0] triangel_ok,output signed [13:0] saw_ok,output signed [ 9:0] sin_Test,output signed [13:0] square_ok
); wire [15:0]  phase;          //32bit内部连接线,传递相位增量
wire [ 9:0]  addr;          //10bit相位信息
wire [ 3:0]  gain;
wire         clk_4_096;
wire         CLK_4_096;
assign gain=gain_o[3:0];
ClockingWizard Clock
(//input.gclk        (gclk),//output.clk_4_096   (clk_4_096),.RESET       (),.LOCKED      ()
);
assign CLK_4_096=clk_4_096;
PHASE_ADDER PHASE_ADDER_Sin
(//input.clk         (CLK_4_096),.rst        (rst      ),.fre_value  (fre_value),//output.cnt        (phase    )
);assign addr = phase[15:6];//addr 10bit
wire [9:0] sin_o;
wire [9:0] triangel_o;
wire [9:0] saw_o;
wire [9:0] square_o; DDS_Table U_DDS_Table
(//input.clk            (CLK_4_096),    // input  wire           clka.addr          (addr  ),        // input  wire [9 : 0 ] addra//output.dout_sin     (sin_o),         // output wire [13 : 0] dout_sin.dout_triangel(triangel_o),     // output wire [13 : 0] dout_tri.dout_saw     (saw_o),          // output wire [13 : 0] dout_saw.sin_Test     (sin_Test),.dout_square  (square_o)       // output wire [13 : 0] dout_square
);Amplifier Amplifier
(//input.gain_o         (gain),.sin_o            (sin_o),        // output wire [13 : 0] dout_sin.triangel_o     (triangel_o ),  // output wire [13 : 0] dout_tri.saw_o          (saw_o ),           // output wire [13 : 0] dout_saw.square_o       (square_o),        // output wire [13 : 0] dout_square//output.sin_f          (sin_ok),.triangel_f     (triangel_ok),.saw_f             (saw_ok),.square_f       (square_ok)
);
endmodule

至此,只需再通过DAC,即可输出所需的波形信号。

4.ISE联合Modelsim仿真

在ISE中调用Modelsim进行波形仿真,由于工程中调用了IP核,所以在Modelsim中需要额外对几个.v文件进行编译,具体是哪几个可以在Modelsim中的transcript中得知,寻找这些文件的路径大概是ISE_DS\ISE\verilog\src,编译好需要的文件后,得出结果如下图所示:

参考资料

[1]: 直接数字频率合成(DDS)基本原理 MT-085 指南
[2]: https://www.cnblogs.com/christsong/p/5506127.html
[3]: 基于 FPGA 的幅值可调信号发生器设计 张有志, 张 鹍
[4]:https://www.cnblogs.com/christsong/p/5506127.html
[5]:https://blog.csdn.net/qq_30866297/article/details/52330140?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158444860819724848348300%2522%252C%2522scm%2522%253A%252220140713.130056874…%2522%257D&request_id=158444860819724848348300&biz_id=0&utm_source=distribute.pc_search_result.none-task

基于FPGA的DDS算法实现(可调幅值,附ISE联合Modelsim仿真结果)相关推荐

  1. 基于FPGA实现DDS正弦波发生器

    名言:学无止境. 1 开发环境 操作系统:win7 开发软件:ISE14.7 硬件平台:Xilinx FPGA Spartan6 2 DDS简介 DDS(Direct Digital Synthesi ...

  2. lms算法的verilog实现_基于FPGA和LMS算法的系统建模

    © 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved.    http://www.c ...

  3. 基于FPGA的DDS信号发生器

    基于FPGA的DDS信号发生器     两个礼拜前就像写这个文档了,但是一直鸽到现在,主要是人摆了.还有个技术上的原因是,我想用串口屏显示波形,在串口调试助手上返回的数据是对的,但是发到串口屏上啥反应 ...

  4. 【FPGA实例】基于FPGA的DDS信号发生器设计

    原文链接来源:www.runoob.com 基于FPGA的DDS信号发生器设计 DDS 原理 ------DDS(直接频率合成) 技术是根据奈奎斯特抽样定理及数字处理技术,把一系列的模拟信号进行不失真 ...

  5. 基于FPGA的DDS实现

    DDS(Direct DIgital Synthesizer)-直接数字频率合成,是一种用于通过单个固定频率的参考时钟信号生成任意波形的频率合成器,被广泛用于测试测量仪表和通信系统中 一.DDS的主要 ...

  6. 紫光同创 FPGA 开发跳坑指南(三)—— 联合 Modelsim 仿真

        Modelsim 是 FPGA 开发中重要的 EDA 设计仿真工具,主要用于验证数字电路设计是否正确.紫光 Pango Design Suite 开发套件支持联合 Modelsim 仿真,这里 ...

  7. CASE_05 基于FPGA的DDS信号发生器

             该系类博客序言和资源简介可浏览该博客:PREFACE FPGA经典案例序言 快速了解该系列博客的内容与可用 资源. 目录 1 简介 2 DDS原理与方案 2.1 方案一:基于CORD ...

  8. 基于FPGA的前向纠错算法

    目前,无线产品的广泛应用使无线音频和视频的高质量传输成为可能.蓝牙.无限局域网等无线传输设备比较复杂,成本较高,急需 开发一种简便的.仅用于流媒体的无线传输平台,将音频数据实时地发送到移动终端.由于音 ...

  9. 基于FPGA的DDS直接数字频率合成器,频率和相位控制字可配置,在vivado2019.2平台中verilog开发.含testbench

    目录 1.算法概述 2.仿真效果 3.verilog程序 1.算法概述 DDS同DSP(数字信号处理)一样,也是一项关键的数字化技术.DDS是直接数字式频率合成器(Direct Digital Syn ...

最新文章

  1. Docker Dirty Cow逃逸
  2. 在Ubuntu 14.04上安装 Webmin
  3. Iphone革了谁的命?
  4. java圆角矩形_[转]c# 画圆角矩形
  5. 班尼路信息化系统基础选型的简单分析
  6. 五校联考R1 Day2T2 矩阵matrix(容斥)
  7. The remote system refused the connection.
  8. 医学图像分割--U-Net: Convolutional Networks for Biomedical Image Segmentation
  9. 解决办法:java.lang.UnsatisfiedLinkError ... Can't find dependent libraries
  10. 使用TortoiseGit自带的puttygen生成ssh密钥
  11. JavaScript练习题
  12. 保龄球计分java代码_从 保龄球得分计算方法 浅析 深度学习
  13. java提取图片文字
  14. 03-Minisys-1的典型指令详解
  15. 一步一步带你了解Hybrid开发框架之DsBridge
  16. 【JS】AMD,CMD,CommenJS和ES6
  17. 淘汰了80%的Android面试者,搞懂这些直接来阿里入职
  18. Go学习——使用MongoDB
  19. 开环放大倍数和闭环放大倍数的区别
  20. 《互联网时代》 第十集 眺望

热门文章

  1. [转]屏幕录相专家常见问题
  2. 几种outofmemory的解决方法
  3. jar包、war包和ear包的介绍与区别
  4. 转载-高斯函数-正态分布函数
  5. 缺乏实战经验?机会来了,这十个练手项目测测你的实战水平
  6. 数学知识 --- 乘积、点积、内积
  7. SD3.0协议解读一
  8. P1230 智力大冲浪
  9. Android应用OneAPM测评
  10. 这是把 GitHub 当网盘了么?中国高校攻占榜单