FPGA数据在进行乘加过程中会面临这数据位宽变大的问题,然而硬件资源是有限的,需要对数据最终位宽进行设计,这就会面临着位宽的选择和如何截位的问题。
对多位数据进行截位处理,是一个从高量化精度向低量化精度的转换过程,由于量化位数的减少,产生截位误差,导致运算结果在时域上出现直流分量,频域出现由谐波失真造成的尖峰,降低了信号的无杂散动态范围。
比如:模拟信号经过16位ADC量化后变为数字信号,且数据类型为整型,且均采用补码形式表示如按照16 bit 量化,则15 =0000 0000 0000 1111;而-15=1111 1111 1111
0001。直接截位法是对数据直接截掉低位。以2 bit 截位为例,则15 截位后为0000 0000 0000 11=3,而-15 截位后为1111 1111 111100=-4。可以看出,在FPGA 中采用直接截位法对数据进行截位,截位是按照向下取整的方式进行的,由截位导致的近似方式对正数和负数来言是不同的,即15/(22)=3.75≈3,而-15/(22)=-3.75≈-4,因此截位后的信号会整体向下偏移,导致出现直流偏置,频谱上表现为在0 频出现误差尖峰。对截位后的信号,再进行变频等处理,就会将尖峰搬移到其他的频率。如果出现多次截位,则将增加误差尖峰的个数,影响信号产生和信号处理的效果。因此在对信号处理要求较高的场合,采用直接截位法是不合适的。
常见的截位方式有:1、负数直接截位后+1,就是所有数都按绝对值取floor
2、Truncate:直接截位,就是正数取floor,负数按绝对值取ceil
3、Rounding:舍入截位,就是所有数按绝对值取四舍五入
这三种截位方式都是可以的,其中舍入截位精度相对较高。而(《数字信号截位影响分析》– 焦庆君,解剑)这篇论文中的数据截位误差抑制方法就是用的四舍五入的思想,通过加上或者减去一个数来实现的,实现方法比较简单,我个人也是用这种方法来进行数据的截位的。具体实现方式是:①
判断数据的符号;② 如果符号为正,则将数据加上2^ (n-1);③ 如果符号为负,则将数据加上2^(n-1)-1;④ 截掉数据的低n 位。
在一些数字信号处理的IP核中数据的截位也是可选的,一般选择近似截位。
然而上述的几种方法截位误差基本上是可以满足绝大多数需求,然而对特殊的要求时以上几种方式难以满足时,就需要对截位误差进行特殊的设计。笔者根据自身项目的调试经验,总结出来一个经过实际测试有效的方法。这个方法成为误差传递。这里设置进位上线为0.75,向下截位下线为0.25.如下图所示
1、 若数据大于设置的则数据直接置1,如图中B点,如果小于下线,则直接置0,如图中A点。这里的上线和下线是可以根据实际的需求进行调整的,但调整的原则是数据超出上下限的点的个数应当是一直的,并且上下限内的数据应当关于上下限中点对称的。
2、 如果数据在上线和下线之间,则把数据直接截位,截下的数据与下一个数据相加后再进行直接截位,这样依次进行下去即可。即若L1+L2+L3=LS>1,则把数据点E置1,然后把LS-1=LD作为新的误差传递下去,若LD+L4+L5>1则把G点置1,产生新的误差继续传递下去,如果LD+L4+L5<1,则继续加入新的数据,判断LD+L4+L5+L6是否大于1,直至产生大于1的那个点进行近卫,然后继续把新产生的误差进行传递。
通过误差传递的方式在数据量相对大一些的情况下,使得信号的原始值与截位后数据的值在时域上做差产生的差值是0,在频域上也没有引入低频信息。这种方式在实际的应用测试中很好用,因此就简单的写了出来,严格的证明毕竟麻烦,需要很大的篇幅来写,这里就不详细写了,但是这个结果是通过MATLAB仿真和实际的应用测试验证的,是能直接用的。
在实际系统中存在着加和乘的运算,这样就导致数据位宽发生变化,有时候为了保证数据的精度不进行截位,但硬件资源有限,适当的截位对最终结果影响较小,因此合理的位宽设计既要满足精度要求也要满足资源要求。
一个典型的例子就是有限脉冲响应(FIR)滤波器的设计就会面临上面的问题。
假设滤波器系数位[15、17、-88、103、75、75、103、-88、17、15],输入数据位宽位N,而输出位宽最佳是如何设计呢?要想数据全精度的运算,针对上面的滤波器系数位宽应该为N+8(系数最大值103的有符号二进制位宽)+4(系数个数的二进制值)。然而在实际运算中通常先得到系数绝对值的和596,而596至少需要10位二进制数表示,因此实际位宽设计为N+10。但是在系数较多或者运算次数较多的系统中,要求输入位宽为N而输出位宽为N+1时,就需要进行截位处理。合理的截位能提升系统的实际运行性能,最佳的截位是定点的运算达到浮点运算的效果。
没有回复内容