记录背景:昨晚快下班时,与同事rk聊起怎么用FPGA实现正弦波的输出。我第一反应是利用高频的PWM波去滤波,但感觉这样的波形精度肯定很差;后来想起之前由看过怎么用FPGA产生正弦波的技术,但怎么都想不起来这个技术的名称是叫什么了。后来搜索后才知道就是DDS(Direct Digital Synthesizer),即:直接数字频率合成器。

最近(好吧,不是最近,是一直)发现自己记东西记不牢,究竟是自己老了,记忆力下退;还是自己不用心去记;还是因为看得少,缺少实践(毕竟纸上得来终觉浅、绝知此事要躬行)。

-----------------------------分割线-----------------------------------

以下内容主要转自:http://blog.chinaaet.com/lincoding/p/5100050592,如有侵权,请告知删除。抱歉!

DDS的主要组成部分:相位累加器、相位调制器、波形数据表、DAC和低通滤波器四大部分组成。如下图:

DDS的原理:

1、首先ROM中要存放好要显示的正弦波数据;

2、然后由相位累加器(其实就是个计数器)一直累加,这个累加器的值作为ROM的地址

3、DAC根据ROM输出的数据输出对应的电压值

4、由于上述输出的电压值是个离散值,无法构成平滑的正弦波,因此需要在后级增加一个低通滤波器才能输出完美的正弦波。

那么,怎么实现上述的功能呢?

首先,我们要考虑两个问题:

A、相位累加器(计数器)的位宽是多少?

B、ROM的数据位宽和深度(深度:2^地址位宽)是多少?

对于第一个问题:相位累加器的位宽一般是24~32bits,一般选32bits(因为这样的位宽能满足绝大部分的应用场合了);

对于第二个问题:

ROM的数据位宽选择要看DAC模块,比如我的DAC模块的数据输入数据范围是0~1023,那么ROM的数据位宽就要选择10位;

ROM的深度也要取决于你的DAC模块,因为ROM中只能存储整数。

相位累加器举例:

  1. //-----------------------------------
  2. //phase adder
  3. reg [:] fre_cnt;
  4. always @ ( posedge clk or negedge rst_n )
  5. begin
  6. if ( ! rst_n )
  7. fre_cnt <= 'd0;
  8. else if ( DDS_en )
  9. fre_cnt <= fre_cnt + 'b1;
  10. else
  11. fre_cnt <= 'd0;
  12. end

这就是所谓的相位累加器,在DDS_en是能以后就一直技术,直到记满,然后重新又开始计数。

  1. DDS_rom u_DDS_ddsrom
  2. (
  3. .clock (clk),
  4. .address (fre_cnt),
  5. .q (DAC_data)
  6. );

然后,将计数的值作为ROM的地址送给ROM,ROM输出相应的正弦波数据,这是,会把2048个点(假设ROM中存了一个正弦波周期的数据,共2048个数据)全部输出。而2048个点全部输出需要的实践为:2048*20ns(假设时钟为50MHz)=40960ns(24414.0625Hz),这就是DDS的基本频率,我们将其称为基频。

***********************************************************************************************************

如果我们希望能将频率翻倍,可以这样:

  1. //-----------------------------------
  2. //phase adder
  3. reg [:] fre_cnt;
  4. always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
  5. begin
  6. if ( ! rst_n )
  7. fre_cnt <= 'd0;
  8. else if ( DDS_en )
  9. fre_cnt <= fre_cnt + 'd2;
  10. else
  11. fre_cnt <= 'd0;
  12. end
  13.  
  14. DDS_rom u_DDS_ddsrom
  15. (
  16. .clock (clk),
  17. .address (fre_cnt),
  18. .q (DAC_data)
  19. );

如果我们希望把频率减半,我们可以这样:

  1. //-----------------------------------
  2. //phase adder
  3. reg [:] fre_cnt;
  4. always @ ( posedge clk_ref or negedge rst_n ) //clk_ref为25Mhz
  5. begin
  6. if ( ! rst_n )
  7. fre_cnt <= 'd0;
  8. else if ( DDS_en )
  9. fre_cnt <= fre_cnt + 'b1;
  10. else
  11. fre_cnt <= 'd0;
  12. end
  13.  
  14. DDS_rom u_DDS_ddsrom
  15. (
  16. .clock (clk),
  17. .address (fre_cnt),
  18. .q (DAC_data)
  19. );

注意:上述的clk_ref为25MHz;

但由于上述需要用到另外的时钟,clk_ref,这会让代码不好维护,改良代码如下:

  1. //-----------------------------------
  2. //phase adder
  3. reg [:] fre_cnt;
  4. always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
  5. begin
  6. if ( ! rst_n )
  7. fre_cnt <= 'd0;
  8. else if ( DDS_en )
  9. fre_cnt <= fre_cnt + fre_value;
  10. else
  11. fre_cnt <= 'd0;
  12. end
  13.  
  14. wire [:] rom_addr = fre_cnt[:];
  15.  
  16. DDS_rom u_DDS_ddsrom
  17. (
  18. .clock (clk),
  19. .address (rom_addr),
  20. .q (DAC_data)
  21. );

为了更进一步完善DDS,我们可以再增加一个相位调节的功能:

  1. //-----------------------------------
  2. //phase adder
  3. reg [:] fre_cnt;
  4. always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
  5. begin
  6. if ( ! rst_n )
  7. fre_cnt <= 'd0;
  8. else if ( DDS_en )
  9. fre_cnt <= fre_cnt + fre_value;
  10. else
  11. fre_cnt <= 'd0;
  12. end
  13.  
  14. wire [:] rom_addr = fre_cnt[:] + pha_value;
  15.  
  16. DDS_rom u_DDS_ddsrom
  17. (
  18. .clock (clk),
  19. .address (rom_addr),
  20. .q (DAC_data)
  21. );

就是增加一个pha_value的相位控制字,它的位宽需与ROM中DAC模块的位宽相同。

Summary:

1、相位累加器的位宽为24~32bites,一般选32bits;

2、频率控制字位宽与相位累加器位宽相同;

3、ROM的数据位宽选择取决于DAC模块;

4、ROM的深度(2^地址位宽)有标准深度,但可任意;

5、相位控制字位宽选择取决于DAC模块。

基于FPGA(DDS)的正弦波发生器的更多相关文章

  1. 基于FPGA的DDS设计(一)

    最近在学习基于FPGA的DDS设计,借此机会把学习过程记录下来,当作自己的学习笔记也希望能够帮助到学习DDS的小伙伴. DDS(Direct Digital Synthesizer)直接数字合成器,这 ...

  2. 基于FPGA的音频信号的FIR滤波(Matlab+Modelsim验证)

    1 设计内容 本设计是基于FPGA的音频信号FIR低通滤波,根据要求,采用Matlab对WAV音频文件进行读取和添加噪声信号.FFT分析.FIR滤波处理,并分析滤波的效果.通过Matlab的分析验证滤 ...

  3. 基于FPGA的VGA显示静态图片

    终于熬到暑假了,记过三四周的突击带考试,终于为我的大二画上了一个完整的句号,接下来终于可以静心去做自己想做的事情了,前一阵子报了一个线上培训班,学学Sobel边缘检测,之前一直在学习图像处理,但是因为 ...

  4. (DDS)正弦波形发生器——幅值、频率、相位可调(二)

    (DDS)正弦波形发生器--幅值.频率.相位可调(二) 主要关于调相方面 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加10kHz 相位每次增加 PI/2 幅值每次增加两 ...

  5. (DDS)正弦波形发生器——幅值、频率、相位可调(一)

    (DDS)正弦波形发生器--幅值.频率.相位可调 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加1kHz. 相位每次增加 2*PI/256 幅值每次增加两倍 二.文章内容 ...

  6. 基于FPGA的飞机的小游戏

    基于FPGA的飞机的小游戏 实验原理 该实验主要分为4个模块,采用至上而下的设计方法进行设计.由50M的晶振电路提供时钟源,VGA显示控制模块.图形显示控制模块.移动模块的时钟为25M,由时钟分频电路 ...

  7. 基于FPGA的图像去噪

    目录 结构图 其中FPGA 控制模块为核心,通过它实现视频图像数据的获取.缓存.处理和控制各模块间通讯[1].由CCD 相机对目标成像,高速图像数据由camera link 实时传输[2],经信号转换 ...

  8. 基于FPGA的线阵CCD图像测量系统研究——笔记

    本文是对基于FPGA的线阵CCD图像测量系统研究(作者:高尚)的阅读笔记 第一章绪论 1. 读读看 读了前面的摘要依然没有看懂作者要做什么.接着往下读....终于看到了一个字眼“基于机器视觉的图像测量 ...

  9. 基于FPGA的按键扫描程序

    最近在学习FPGA,就试着写了个按键扫描的程序.虽说有过基于单片机的按键扫描处理经验,对于按键的处理还是有一些概念.但是单片机程序的编写通常都采用C写,也有用汇编,而FPGA却是采用VHDL或者Ver ...

  10. 基于FPGA的DW8051移植(三)

    总结一下问题: 1) http://www.cnblogs.com/sepeng/p/4137405.html  基于FPGA的DW8051移植(一)里面用modelsim观测波形发现程序进入了ida ...

随机推荐

  1. 我们的团队-IT梦想队

    IT梦想队 队长:李遇塘 队员:王长.周兴荣.朱岭杰.马婧婧 团队宣言:  一匹狼战斗力低,但一群狼的我们无所畏惧!李遇塘http://www.cnblogs.com/Liyutang/ 王 长htt ...

  2. php学习部分总结

    php Apache 阿帕奇PHP 解释器MySQL 数据库 php php文件后缀就是.php 比如1.php 2.phpphp代码 要写在<?php echo "assss&quo ...

  3. phaser3 微信小游戏入门

    phaser与eget, laya, pixi.js本质上没什么区别. 都是渲染引擎.  其它的都是配角.  phaser的特点是.代码容易理解 功能比较全面. 个人比较喜欢phaser的地方 twe ...

  4. angular浏览器滚动条滚动到指定element 触发事件

    angular.module('app').directive('ScrollTrigger', () => { return { restrict: "A", link:f ...

  5. 远程显示(操作) 服务器 GUI 程序(图形化界面) (基于 X11 Forwarding + Centos + MobaXterm)

    在做 数据分析(数据挖掘 或 机器学习)的时候,我们经常需要绘制一些统计相关的图表,这些统计.绘图的程序常常是跑在服务器上的,可是服务器出于性能和效率的考虑,通常都是没有安装图形化界面的,于是这些统计 ...

  6. Hbase之JavaAPI连接池

    源码: package HbaseOperation; import com.alibaba.fastjson.JSON; import org.apache.hadoop.conf.Configur ...

  7. NOI&&NOIP知识点集萃

    更新日志 \(update:2019-3-4\) 更新了自为风月马前卒的后缀数组(省选不到一个月了,我才开始学后缀数组怕是要凉凉) \(update:2019-2-21\) 更新了一篇李超线段树的讲解 ...

  8. win10 Jmeter下载安装与使用教程

    1.下载 2.安装 下载完成后解压文件(不需要安装) 之后需要配置jmeter环境变量 1)新增新增JMETER_HOME系统变量 2)编辑CLASSPATH变量,加上%JMETER_HOME%\li ...

  9. Minimum Sum LCM UVA - 10791(分解质因子)

    对于一个数n 设它有两个不是互质的因子a和b   即lcm(a,b) = n 且gcd为a和b的最大公约数 则n = a/gcd * b: 因为a/gcd 与 b 的最大公约数也是n 且 a/gcd ...

  10. 【刷题】BZOJ 2935 [Poi1999]原始生物

    Description 原始生物的遗传密码是一个自然数的序列K=(a1,...,an).原始生物的特征是指在遗传密码中连续出现的数对(l,r),即存在自然数i使得l=ai且r=ai+1.在原始生物的遗 ...