当前位置: 首页 > news >正文

FPGA控制DDS产生1CLK周期误差的分析(二)

前文简短的介绍了DDS的产生原理,其实相当的简单,所以也不需要多做解释,本文详细阐述一下在调试DDS的过程中所产生的一个bug

问题发现

正如上文所述,再用FPGA控制存储在rom中的波形信号输出之后,在上板之前,我们可以先用仿真软件仿真一下,看看波形是否有误。我们的测试条件要求为:从2550Hz开始,每间隔1s的周期以20Hz的步长向下递减至2310Hz的频率,仿真波形如下所示(为节省仿真时间,我们将扫频间隔缩短):
整体时序图
不知大家是否能看清上图中的周期结果分析,按照上图所示,2550Hz、2530Hz除开频率交接处会有一定的抖动之外,在扫频周期中的频率是比较稳定的,但是当我们看到2510Hz的扫频周期过程中却发现,波形的周期呈现为398420ns、398400ns的周期变化,虽然说二者的周期对应基本上都为2510Hz,但是对频率信号敏感的场合是不能接受的。本文便对这一问题进行考究。
问题时序

问题探究

首先,我们追根溯源,DDS信号发生的来源就是ROM当中存储的波形数据,而波形数据的来源是所输入的地址addr,这么一来我们就将目光放在addr上面。
addr是一个12位的变量,来源于频率信号叠加寄存器的高12位,为什么要设置叠加器为32位,就像前文所述,为了提高但个周期的分辨率,使得输出更加精确。接下来让我们分别来看看398420 ns和398400 ns的波形细节。
误差细节时序图
我们发现多的20ns(一个CLK周期)来源于高电平期间的差异,所以我们进一步的查看高电平的细节。先来看看199220ns的这个高电平。
多一个CLK周期高电平开始细节
多一个CLK周期高电平结束细节
可见,高电平的持续时间应该为 20ns × 5 × (2048-0) = 204800ns,这和我们的波形图上实现显示的差了204800ns - 199220ns = 5,580ns。我们记为error1。
然后再来看199200ns的这个高电平。
少一个CLK周期高电平开始细节
少一个CLK周期高电平结束细节
上面两幅图的高电平的持续时间应该为 20ns × 5 × (2048-0) = 204800ns,这和我们的波形图上实现显示的差了204800ns - 199200ns = 5600ns。我们记为error2。
好了,通过分析波形我们发现逻辑设计上是没有问题的,该在什么时候下降,什么时候上升都符合要求,那么其中的error1、2是从何而来的呢?这时候我们注意到上面的这个5,代表5个时钟周期变化一次地址,那么此时我们不禁要问,这个5个时钟周期变化一次,它真的那么诚实可靠,人畜无害吗,答案是否定的。
问题图1
问题图2
像上面两幅这样的问题时序还有很多,相信数量也是5600ns / 20ns = 280个。好了接下来问题就是分析问什么会少一个了。
讲了这么久,终于该回到代码层面了。让我们看一下地址递增的部分代码。

reg     [31:0]  freq_cnt;
assign addr = freq_cnt[31:20] + phase_offset;
always @(posedge sys_clk or posedge sys_rst)beginif(sys_rst)freq_cnt <= 32'd0;elsefreq_cnt <= freq_cnt + freq_k;
end

从上图中可以看到。此时的freq_k为215607,而我们的地址是从220开始进位的,也就是说计数220 = 1,048,576次之后,addr + 1。那么215607需要加多少次呢?如下表所示:(表中标红表示进位)
在这里插入图片描述
上表我想已经表示的很明白了,因为每一轮都会有一个误差叠加,最后不断累积起来就会造成每一个周期输出的周期数不一样,虽然每一次都只是一个CLK的误差,但是总归是有误差的。目前我们给的频率参数是2510Hz,有这个现象,那前面2550、2530Hz有没有这个情况呢?答案是有的,如下图所示:
2550Hz的情况高电平开始时
2550Hz的情况高电平结束时
同样的,2048 × 20 × 5 = 204800ns,但是实际上仿真结果为:196080ns,也是有这个误差的。至于为什么此时没有出现前面那样子一个CLK周期的误差,原因我想就是刚刚好误差的次数为偶数,根据差分原理消除了。不论怎样,这个问题我们都应该消除,下面探讨一下解决办法。

问题解决

知道了问题所在,接下来找找解决办法,既然已经确定这个是算法的问题,就从算法设计上下功夫。首先可以确定的一点是,我们既然已经得到对应的freq_k即每一次叠加的值,那么每一次就应该叠加这么多,也就是说每一次就应该加这么多才能得到正确的输出频率,如果修改了这个输出的频率值也就是错的了。
解决办法1:一开始我想的办法是,依旧按照这个计数值叠加,如果叠加的值超过了220 = 1,048,576马上让叠加的值清0,然后让addr+1。这样子相当于舍弃了每一次的叠加误差。但是后来想了想,这样子的频率输出误差也太大了,分析如下:假设我刚好要计数5次,那么每一次计数的值就是1048576 / 5 = 209,715.2 ≈209716(必须要向上取整);而如若要计数计数6次,对应的就是174,763;4次对应262,144。这样子按照之前根据频率计算次数的公式对应回去的频率分别为:3,051.8Hz、2,441Hz和2,034.5Hz,也就是说,位于这三个点之间的设定频率都会被忽略,然后变成上述的固定点的频率值,有点类似于模数转换中的量化误差。而如若要减少量化误差,办法是降低addr跳变的临界值也就是1048576,即在N不变的前提下,提高ROM的深度,但这总归不是个好办法。
解决办法2:通过上述分析我们知道,叠加误差不能够省略,那么我们又如何让叠加误差“进场”呢?通过思考,我发现叠加误差本来就要进去的,那么转变枪头,将目光从叠加误差转移到波形误差,为什么上一个周期的叠加误差和下一个周期的叠加误差会不同?如何才能让它们变得相同?为什么会不同,因为每一个周期在结束的时候,对应的freq_cnt的不为0,这边就也会有一个误差(freq_cnt就是那个32位的寄存器,取高12位作为ROM的寻址信息)。还是上面那个例子,地址+1所需要的叠加量为1 048 576,然后我们每一次始终到来时给它 +215 607,但是如果每一个周期结束时都会有一个会累加的误差,当这个误差累加到215 607时,就省了一个时钟周期的叠加,此时误差重新回0,这就是为什么会出现周期之间会有一个CLK周期的误差的原因,之所以前面2550Hz和2530Hz没有出现,是因为他们每一次叠加的误差量太小,而仿真的时间太短,还没来得及叠加上去就跳到下一个频率周期了!针对这个周期间的误差,我想到解决办法是,检测到一个周期输出完毕之后,手动的将叠加器变量给清空,也就是说人为消除周期叠加误差。这个误差和上面那个不同,上面那个累加误差决定着输出的精度,这个周期误差的值不会超过一个地址周期,可以忽略不计,虽然精度会受损,但总归是消除了这个误差了。
误差消除

结语

起始本次设计的bug来源就是算法的问题,最后的解决办法也想但简单就是清个0就好了。啰嗦了这么多总归是讲完了,说实话,当初在调DDS的时候,根本就没想这么多,只觉得输出的时候频率正确即可。也根本发现不了这个问题,毕竟1个CLK周期的误差,真的太难发现了。所幸一位朋友发现了这个问题,在与他交流许久后才做了这次的实验,最终也是不负使命,找出了问题所在,也于此感谢他的细心观察的结果。

资源链接

百度网盘链接:链接:https://pan.baidu.com/s/1LqOMz0f9FBW-6bxZFUzlQA?pwd=wvq6
提取码:wvq6
CSDN链接:FPGA控制AD9767实现DDS信号发生器

http://www.lryc.cn/news/41640.html

相关文章:

  • 这一次,吃了Redis的亏,也败给了GPT
  • 第一章 信息化知识
  • 如何用matlab工具箱训练一个SOM神经网络
  • 音视频技术开发周刊 | 285
  • 安装flume
  • 为工作排好优先级
  • 超专业解析!10分钟带你搞懂Linux中直接I/O原理
  • 【C++】面试101,用两个栈实现队列,包含min函数的栈,有效括号序列,滑动窗口的最大值,最小的K个数,倒置字符串,排序子序列,跳跃,数字三角形,蓝肽子序列
  • WPF 认识WPF
  • 【建议收藏】PHP单例模式详解以及实际运用
  • 【十二天学java】day04-流程控制语句
  • Pandas 与 PySpark 强强联手,功能与速度齐飞
  • 【Zabbix实战之部署篇】docker部署Zabbix+grafana监控平台
  • acm省赛:高桥和低桥(三种做法:区间计数、树状数组、线段树)
  • stm32-定时器详解
  • 《硬件架构的艺术》读书笔记:Chapter 1 亚稳态的世界
  • 开箱即用的密码框组件
  • ChatGPT能否取代程序员?
  • 案例分享 | 金融微服务场景下如何提升运维可观测性
  • CentOS8提高篇3:Centos8安装播放器(mplayer vlc)
  • MySQL-存储过程
  • 经典七大比较排序算法 · 下 + 附计数和基数排序
  • HTTPS协议,看这篇就够了
  • C语言学习之路--结构体篇
  • 【LINUX】初识文件系统
  • 金三银四Java面试题及答案整理(2023最新版) 持续更新
  • 7个角度,用 ChatGPT 玩转机器学习
  • 关于多层板,你了解多少?
  • 使用sqlalchemy-gbasedbt连接GBase 8s数据库
  • 前端如何丢掉你的饭碗?