记录背景:昨晚快下班时,与同事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中只能存储整数。

相位累加器举例:

//-----------------------------------
//phase adder
reg [:] fre_cnt;
always @ ( posedge clk or negedge rst_n )
begin
if ( ! rst_n )
fre_cnt <= 'd0;
else if ( DDS_en )
fre_cnt <= fre_cnt + 'b1;
else
fre_cnt <= 'd0;
end

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

DDS_rom u_DDS_ddsrom
(
.clock (clk),
.address (fre_cnt),
.q (DAC_data)
);

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

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

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

//-----------------------------------
//phase adder
reg [:] fre_cnt;
always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
begin
if ( ! rst_n )
fre_cnt <= 'd0;
else if ( DDS_en )
fre_cnt <= fre_cnt + 'd2;
else
fre_cnt <= 'd0;
end DDS_rom u_DDS_ddsrom
(
.clock (clk),
.address (fre_cnt),
.q (DAC_data)
);

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

//-----------------------------------
//phase adder
reg [:] fre_cnt;
always @ ( posedge clk_ref or negedge rst_n ) //clk_ref为25Mhz
begin
if ( ! rst_n )
fre_cnt <= 'd0;
else if ( DDS_en )
fre_cnt <= fre_cnt + 'b1;
else
fre_cnt <= 'd0;
end DDS_rom u_DDS_ddsrom
(
.clock (clk),
.address (fre_cnt),
.q (DAC_data)
);

注意:上述的clk_ref为25MHz;

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

//-----------------------------------
//phase adder
reg [:] fre_cnt;
always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
begin
if ( ! rst_n )
fre_cnt <= 'd0;
else if ( DDS_en )
fre_cnt <= fre_cnt + fre_value;
else
fre_cnt <= 'd0;
end wire [:] rom_addr = fre_cnt[:]; DDS_rom u_DDS_ddsrom
(
.clock (clk),
.address (rom_addr),
.q (DAC_data)
);

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

//-----------------------------------
//phase adder
reg [:] fre_cnt;
always @ ( posedge clk or negedge rst_n ) //clk为50Mhz
begin
if ( ! rst_n )
fre_cnt <= 'd0;
else if ( DDS_en )
fre_cnt <= fre_cnt + fre_value;
else
fre_cnt <= 'd0;
end wire [:] rom_addr = fre_cnt[:] + pha_value; DDS_rom u_DDS_ddsrom
(
.clock (clk),
.address (rom_addr),
.q (DAC_data)
);

就是增加一个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. img 分区响应图

    ---恢复内容开始--- a标签的target为_blank属性,意为跳转到新的页面. shape要和coords配合使用,shape为rect时意义为矩形.shape 为不同属性时意为不同的形态触碰 ...

  2. [Java]Object有哪些公用方法?

    1.clone方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种基本类型传 ...

  3. Helm 安装 wordpress

    1. 前置需要安装 storageclass 然后 安装helm 客户端 helm tiller 服务端 2. 设置 当前的位阿里云的 repo 3. 查找 wordpress的镜像 helm sea ...

  4. Jenkins之手动安装

    Download and run Jenkins Download Jenkins. Open up a terminal in the download directory. Run java -j ...

  5. Sublime Text 3 插件整理

    Sublime Text作为一个尽为人知的代码编辑器,其优点不用赘述.界面整洁美观.文本功能强大,且运行速度极快,非常适合编写代码,写文章做笔记.Sublime Text还支持Mac.Windows和 ...

  6. jquery 绑定文本即时查询功能

    bindFilterFunc: function () {             if ("\v" == "v") { // IE only          ...

  7. 【BZOJ2067】SZN(二分,动态规划,贪心)

    [BZOJ2067]SZN(二分,动态规划,贪心) 题面 权限题额 Description String-Toys joint-stock 公司需要你帮他们解决一个问题. 他们想制造一个没有环的连通图 ...

  8. python 用Threading创建多线程

    #-*-coding:utf-8-*- '''python标准库提供了两个多线程模块,分别为thread和threading, 其中thread模块是低级模块,threading是高级模块,对thre ...

  9. 【洛谷P1101】单词方阵

    题目大意:给一 \(n \times n\) 的字母方阵,内可能蕴含多个 \("yizhong"\) 单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着 8 个方向的任一方向, ...

  10. DCT变换、DCT反变换、分块DCT变换

    一.引言 DCT变换的全称是离散余弦变换(Discrete Cosine Transform),主要用于将数据或图像的压缩,能够将空域的信号转换到频域上,具有良好的去相关性的性能.DCT变换本身是无损 ...