|
本帖最后由 wqsjob 于 2014-12-17 22:39 编辑
首先,这个算法是我两年前在项目里用的,我直觉这个算法肯定会有人用过或至少是有人类似的用过,首先声明不是抄袭,在此基础上任意拍砖.
因为公司有保密要求 ,只能从原理上大概说明.
在数据采样的系统中,肯定会遇到这样的问题:
1.要求固定(或可变)的采样率,比如10K,还要求有外部的同步信号,在没有同步信号的时候,10K采样率本身是有误差的,有了同步信号(,比如秒脉冲,1588对时信号等),要求按照准确的同步信号来重新分出10K的采样率并且同步信号的0时刻必须为第0个采样点. 这牵扯到内部时钟校准的问题, 2.同时应该还会要求均匀的脉冲输出,举个例子:比如100us采样一次,同步信号为分脉冲或秒脉冲,则在第一个同步信号到来的时候,可能是在一个采样点过后的1us,也可能是在50us,也可能在99us,这时候要保证一直均匀输出采样信号,第一个同步信号到来的时候需要记下相位,逐个的调整,在下一个同步信号到来的时候,正好是0us或100us,或者在起前后很小的误差范围,才能保证脉冲均匀输出.
其实1 和2 实现的原理基本是相同的.所有我就只谈第一个问题,就是用外部信号校准内部时钟的问题.
比如晶体的频率是XMHZ(比如10MHZ),则实现K(假设10K)的采样信号输出,只需要计数Y(按X的假设值,Y=1000)次出一个采样信号即可.但是这个晶体是不准的,假设外部信号为秒脉冲,而一秒的间隔内部晶体的计数值为Z(比如10.013M)个,实际上是内部晶体1秒多出了0.013M,这样我怎么才能均匀分布采样信号呢.
如果人工去算,那么就是计数1001.3次才输出一个脉冲,但是是有小数的,FPGA处理起来要复杂多了.有人说乘以十,那如果多出的是0.0124呢?不是要乘以100了?并且乘法也不容易,乘了又有用吗?所以我们就要找出新的算法.
其实很简单, 第一个采样信号,计时1001次,输出,第二个计算1001次,第三个也计数1001次,到第四个的时候,就要计算1002次了,这样,我只要把小数记下来,整数累积,小数也累积即,我们把计算方法列出来.
每一个采样信号的间隔时间Y= Z/K, 其中Z可以分解为 Z=MK+N,其中M即为Y的整数部分,N/K即为Y的小数部分.
则第一个采样信号输出时,为M个,同时记下 N/K,第二个仍然为M个,这时候 多余出 2*N/K,这时就要判断,2*N/K是否大于1,如果小于1则继续累积,如果大于1,则下一个(或者本次也可以,如果选择下一个,最后一个采样信号始终会有N/K的误差,一般没有影响)采样信号的输出要多计算一个内部周期.
这样算起来其实也有点麻烦,因为我要先把这个小数计算出来,就必须用Z除以K,计算出整数和小数.这对于FPGA来说,也不是一件容易的事.所以我们必须找出更方便的方法.
回到Y= Z/K这个计算上,回忆以上我们说的算法,就是每个内部时钟周期,计数1次(设次数为J,是正整数),计到Y的整数次,同时小数累积不到1的时候,输出一个采样信号,小数累积到1了,就在下一个内部时钟周期输出采样信号.把小数累积的整数部分减去,留小数部分继续累积.
那我们如果每个内部时钟周期计K次呢?把上式换算一下,K*Y=Z. 即每个内部周期计数K次,在第Y周期时,正好等于Z,这时候正好是输出采样信号的时候,但是因为Y是小数,不可能正好,我们把Y用J代替, 则在K*J>=z的时候,输出采样信号,然后将多余的值放入K*J-Z,在下一个脉冲的第一个,则为K*J-Z+K,每次再累积K,一直累积到 K*J-z+另一个J*K>= Z的时候,再输出下一个采样信号,就可以把信号均匀分布了.这个转换,彻底的摆脱了除法运算以及小数运算,只剩下了加减的运算.
有了以上的算法,不光是校准应用,还可以用于对时钟信号的任意分频,且是均匀的.
按照以上的算法,实现所有功能的代码只有几十行.
|
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|