基于FPGA的DDS设计(一)
最近在学习基于FPGA的DDS设计,借此机会把学习过程记录下来,当作自己的学习笔记也希望能够帮助到学习DDS的小伙伴。
DDS(Direct Digital Synthesizer)直接数字合成器,这是直译过来的名字。设计人员一般把它叫做信号发生器,用它来产生一些数字意义上的波形。它的意义还是挺大的,例如我们学习滤波器,就需要一个高低频率叠加的波形,现时生活中到处都是,可以在设计中,怎么能做出这样的波形呢?学习各种载波调制,需要将信息加载到载波上,而载波也一般都是一定频率的正弦波。DDS就是能够产生这种波形,对于学习数字信号处理以及信号调制解调等有很大的作用。
FPGA是数字电路,怎么产生模拟的波形呢?如果单纯的使用FPGA是无论如何也产生不了连续不断的波形,一般都是使用FPGA产生数字信号,再利用DAC(Digital-to-Analog Converter)转化成为模拟的波形(如图1)。DAC芯片是一堆模拟电路的东西了,如果感兴趣的小伙伴可以在自己学习一下数字信号转化为模拟信号的过程。

图1
FPGA是数字信号,通过DAC转化为模拟值,笔者在进行学习的时候一直有个疑问:既然FPGA是数字信号,那么也就只能输出数字信号,输出相邻的两个点中间一定是有一定距离的,输出的模拟波形应该像楼梯一样(有一定的幅值跳跃),而不是连续变化的,像这种情况下还是我们还可以用吗?答案是肯定的,如果“楼梯”的高度跳跃很小,并且在一个周期中有很多小的跳跃,那么就是可以用的。其实微积分的概念和这个道理应该差不多就是用无限多的矩形来近似曲线(如图2)。

图2
所以在设计时,只要将波形的一个周期(周期波形)中分成N段输出就可以了。
DDS的实现一般都是由频率控制器、相位累加器和波形存储器构成(如图3)。

图3
刚刚开始的时候接触到这个信息,笔者也不太理解,经过一段的时间思考,大概明白了其中的设计原理。我们直接从最终的输出开始分析,要输出的一个波形(数字意义上),例如正弦波。那么怎么输出呢,可以给出一个公式sin(2*pi*n/256),将n从0增长到255,就可以输出一个波形。如果这么写的话,就已经把一个周期分成了256份,也可以分成任意份,为了方便数字电路设计,一般都是2的整数次幂份。以下分析都当作一个周期分为256份。n等于一个数值就会输出一个值,把n所对应的位置看作是相位。例如n等于64时,输出的值正好对应于相位pi/2时。在FPGA中去计算sin,一般都是利用查表法,也就是说将一个周期分为N份,当输入的值比较接近与某一个相位时,就把这个相位点的值输出。那其实也就是把波形等分多份,存储在存储器中,而此时存储器就叫做波形存储器。存储器的输出是按照输入地址来决定的,如果想要输出一个完整的不断的波形,就需要地址从最小到最大不变循环,而存储器就会不断的输出波形。地址从最小到最大的累加,就被成为相位累加器。如果相位累加器1S从最小到最大循环了1000次,那么输出的波形的频率就为1KHz。故而相位累加器累加的速度决定输出波形的频率,而累加速度是由外部控制器来决定,所以此控制器被称作频率控制器。
原理就是上述的那样,下面可以考虑如何来实现上述的过程。
在设计中,笔者采用INTEL FPGA来实现,故此采用Quartus Prime 18。首先制作波形存储器,在FPGA中有很多存储器资源可以来用,在此选择ROM来当作存储器。利用ROM当存储需要制作初始化文件.mif或者.hex,这两种都可以,在这里采用.mif文件。
.mif在Quartus 中显示为一个一个小区域(如图4),但是其实就是一种文件格式(如图5)。

图4

图5
利用某些计算工具将数值计算出来,然后填入表格中,这种速度太慢,也太麻烦。我们一般采用下面所述的两种方法:
利用mifmaker软件生成(QQ群:173560979群文件中),此软件用起来比较简单。只需要简单的设置“设定波形”即可。在设定成功后,点击“文件->保存”即可生成对应的.mif文件(如图6)。

图6
另外一种方法就是利用matlab实现,此方法要求设计者要有一定的matlab基础。源码如下:
clear;
clc; width = ;
depth = ; file_handle = fopen('sin.mif','w+');
fprintf(file_handle,'--Created by Author xxx\r\n');
fprintf(file_handle,'WIDTH = %d;\r\n',width);
fprintf(file_handle,'DEPTH = %d;\r\n',depth);
fprintf(file_handle,'ADDRESS_RADIX = HEX;\r\n');
fprintf(file_handle,'DATA_RADIX = HEX;\r\n');
fprintf(file_handle,'CONTENT BEGIN\r\n');
for i = : depth-
fprintf(file_handle,'%4x : %4x ; \r\n',i,floor((0.5+0.5*sin(*pi*i/depth) ) *(^width - 1)));
end
fprintf(file_handle,'END;\r\n');
fclose(file_handle);
产生了.mif后,就可以加载到ROM中。在quartus工程中,采用50MHz的时钟来进行驱动整个设计,让rom的地址每个时钟周期增加1。经过仿真可以得到正弦波(如图7)。

图7
产生了正弦波,在设置modelsim时,因为波形是按照无符号生成的数据,所以在设置成为模拟之前要先把进制改为无符号类型。即可产生图7波形。经过使用modelsim工具测试,产生的波形的频率为195.313KHz。我们自己也算以下:系统的驱动时钟为50MHz,一个周期为20ns,256个周期输出一个完整的波形。所以波形的周期为256x20ns=5120ns,经过计算频率为195.3125KHz,与上述使用modelsim工具测试结果一直,只是modelsim测试保留了频率的两位小数而已。
相位累加器每次累加1,产生的波形的频率为195.313KHz,那么只要改变每次累加的数字就可以得到其他频率。如果每次增加的是整数比较好办,那如果每次增加的是带有小数呢?又该如何实现呢?
笔者水平有限,如有不妥之处,恳请大佬指出。
欢迎加好友探讨QQ:746833924,QQ群:173560979。
基于FPGA的DDS设计(一)的更多相关文章
- 基于FPGA的DDS设计(二)
在DDS设计中,如果相位累加器每个时钟周期累加1,就会输出频率为195.313KHz的波形.如果每个时钟周期累加2,就会输出频率为2*195.313KHz的波形·······,如果每两个时钟周期累加1 ...
- 基于FPGA的DDS任意波形发生器设计
一.简介 DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG).基于DDS技术的任 ...
- 基于FPGA(DDS)的正弦波发生器
记录背景:昨晚快下班时,与同事rk聊起怎么用FPGA实现正弦波的输出.我第一反应是利用高频的PWM波去滤波,但感觉这样的波形精度肯定很差:后来想起之前由看过怎么用FPGA产生正弦波的技术,但怎么都想不 ...
- 38.基于FPGA的FIR设计二
利用fdatool工具生成的滤波器系数与用代码生成的系数不一致,在网上查询得知,fdatool生成的滤波器系数是有符号小数,而且是浮点型,而代码生成的滤波器系数是定点型有符号数,故不一样. 浮点型数据 ...
- 优化基于FPGA的深度卷积神经网络的加速器设计
英文论文链接:http://cadlab.cs.ucla.edu/~cong/slides/fpga2015_chen.pdf 翻译:卜居 转载请注明出处:http://blog.csdn.net/k ...
- 自己动手写CPU(基于FPGA与Verilog)
大三上学期开展了数字系统设计的课程,下学期便要求自己写一个单周期CPU和一个多周期CPU,既然要学,就记录一下学习的过程. CPU--中央处理器,顾名思义,是计算机中最重要的一部分,功能就是周而复始地 ...
- 基于FPGA的XPT2046触摸控制器设计
基于FPGA的XPT2046触摸控制器设计 小梅哥编写,未经许可,文章内容和所涉及代码不得用于其他商业销售的板卡 本实例所涉及代码均可通过向 xiaomeige_fpga@foxmail.com 发 ...
- 基于FPGA的HDMI显示设计(三)
上一篇:基于FPGA的VGA显示设计(二) 10月10日 ~ 20日期间实习,令我万万没想到的是实习题目是 “便携式高清电视显示屏测试系统原型设计” 也就是 “基于FPGA的视频显示”. 实习要求用 ...
- 基于FPGA的VGA显示设计(二)
上一篇:基于FPGA的VGA显示设计(一) 参照 CrazyBingo 的 基于FPGA的VGA可移植模块终极设计代码 的工程代码风格,模块化处理了上一篇的代码,并增加了一点其它图形. 顶层 ...
随机推荐
- 【Python】Java程序员学习Python(五)— 函数的定义和使用
不想做一个待宰的羔羊!!!!要自己变得强大.... 函数的定义和使用放在最前边还是有原因的,现在语言趋于通用,基本类型基本都是那些,重点还是学习对象的使用方法,而最根本的还是方法的使用,因此优先介绍, ...
- Oracle 查看锁情况
/*查看锁(lock)情况*/ SELECT ls.osuser os_user_name, ls.username user_name, decode(ls.type, 'RW', 'Row wai ...
- Linux内核态和用户态
两张图说明Linux内核态和用户态之间的关系
- September 16th 2017 Week 37th Saturday
We are all in the gutter, but some of us are looking at the stars. 身处艰难,但仍有人仰望星空. When standing on t ...
- GNSS基础(持续更新)
1.整周模糊度成功率 可参考文献:GNSS整周模糊度概率特性 2.正太分布 见百度百科 https://baike.baidu.com/item/%E6%AD%A3%E6%80%81%E5%88%86 ...
- .Net WebApi 支持跨域访问使用 Microsoft.AspNet.WebApi.Cors
首先导入Cors库,通过程序包管理控制台导入 Install-Package Microsoft.AspNet.WebApi.Cors 引用库之后,我们需要进行简单的配置. 现在WebApiConfi ...
- Kubernetes-dns 域名解析问题
问题描述:nginx不能解析域名,但是使用nslookup却可以解析域名 ./sbin/nginx -t nginx: [emerg] host not found in upstream " ...
- 【CF1009F】Dominant Indices
题目 长链剖分板子题啊 长链剖分有几个神奇的性质 所有长链的总点数为\(n\) 任意一个点的\(k\)级祖先所在长链的长度肯定不小于\(k\) 从任意点到根经过的短边数量不超过\(\sqrt{n}\) ...
- ASP.NET MVC编程——路由
框架自动生成的路由配置 上图中,路由配置文件为App_Start文件夹下的RouteConfig.cs. 代码如下: public class RouteConfig { public static ...
- 基于swoole的聊天室模型
client.html: <!doctype html><html><head> <meta charset="utf-8"> &l ...