在数字信号处理系统中,经常需要使用不同的数值对正弦波信号进行描述,如图3.17所示。
很显然,这需要对非整数数值进行处理。对这种非整数数值的处理方法是允许正弦波的幅度按比例增加,并使用整数形式来表示。如图3.18所示,二进制补码使用的并不多,如使用两个比特位表示所得到的值是-2、-1、0和1,使得存在较大的量化误差。显然,需要处理非整数数值的情况。
图3.17 正弦波信号的表示
图3.18 正弦波的整数量化表示
这种方法很常见,但在某些情况下,需要表示0到1之间的数值,也需要表示整数之间的数值。
用十进制表示小数很容易。通过引入十进制小数点来描述非整数的值,并在小数点的右边插入数字。例如:
12.34=1×10 1 +2×10 0 +3×10 -1 +4×10 -2
定点数是介于整数和浮点数之间的一种用于表示数的格式,是二进制小数点在固定位置的数。将二进制小数点左边部分的位定义为整数位,而将该点右边部分的位定义为小数位。例如,对于二进制定点小数101.01011而言,有3个二进制整数位101,5个二进制小数位01011。通常,定点数表示为 Qm . n 格式,即
b n + m b n + m -1 … b n . b n -1 … b 1 b 0
其中:(1) m 为整数部分二进制的位数。 m 越大,所表示数的动态范围越大; m 越小,表示数的范围越小。
(2) n 为小数部分二进制的位数。 n 越大,表示数的精度越高; n 越小,表示数的精度就越低。
注 :当表示的定点数为有符号数时,整数部分的最高位为符号位。
由于定点数的字长 m + n 为定值(可用字长的宽度),因此只能根据设计要求,在动态范围和精度之间进行权衡。
例如,对于一个字长为8位的有符号定点数而言,用不同的格式表示为:
① 11010.110( m =5, n =3)所表示的数为-5.25;
② 110.10110( m =3, n =5)所表示的数为-1.3125。
很明显,只要有足够的字长,可以提供足够的精度,对于大多数的DSP应用而言,定点就足够了。因为它基于整数数学,所以它非常有效-只要数据的幅度变化不大即可。
对于有符号数而言,使用Q3.5格式的定点数表示方法,如表3.5所示。
表3.5 有符号定点数的表示
对于以Q7.5格式(字长为12位,5个二进制小数位,7个二进制整数位)表示的定点数1100011.01011,其所对应的十进制数为
2 6 -2 5 -2 1 -2 0 +2 -2 +2 -4 +2 -5 =-29+0.25+0.0625+0.03125=-28.65625
思考与练习3-19 :若表示的最大值为278、最小值为-138,使用11位字长的二进制数表示时,定点数的格式为____。
用Q1.5格式(整数部分为一位符号位)的定点数表示范围为[-1,1]的小数,如表3.6所示。
表3.6 一位整数的定点数表示
例如,Motorola StarCore 和TI C62x DSP处理器都使用只有一个整数位的定点表示法。这种格式可能是有问题的,因为它不能表示+1.0。实际上,任何定点格式都不能表示其负数最小值的相反数。
所以,在使用定点数时要多加注意。一些DSPs结构允许通过扩展位对格式进行1个整数位的扩展(这些扩展位就是附加的整数位)。
思考与练习3-20 :若表示的最大数为+1、最小数为-1,使用12位的二进制数表示,则定点数的格式为____。
思考与练习3-21 :若表示的最大数为0.8、最小数为0.2,使用10位的二进制数表示,则定点数的格式为____。
考虑以Q3.5格式表示的有符号定点数,该格式有3个二进制整数位和5个二进制小数位。很明显,该格式可以表示-4~+3.96785之间的十进制小数,每个数字之间的步长为0.03125。在这种表示格式中,共有8位二进制位,因此可表示2 8 =256个不同的值。
注 :使用定点时的量化将有±1/2LSB(最低有效位)的误差。
量化就是使用有限的字长来表示无限精度的数。在十进制中,已经知道对于给定位数的十进制小数的处理方法。例如,实数π可以表示为3.14159265…,对该实数采用四舍五入的方法进行处理,则该实数可以量化为包含4个十进制小数位的小数3.1416,则误差为
Δ =3.1416-3.14159265…=0.00000735
如果使用截断法(直接舍去第4位小数以后的位数),则该实数可以量化为包含4个十进制小数位的小数,则误差为
Δ =3.14159265…-3.1415=0.00009265
从上面的例子可知,四舍五入是处理实数比较合适的方法,因为该处理方法能够得到预期的精度,但是该方法也会带来一些硬件开销。
当乘以小数时,需要对最后的结果进行处理以满足位数的要求,如计算两个十进制小数,计算过程如下:
0.57×0.43=0.2451
对最终计算结果可采用上面给出的两种处理方法:
(1)四舍五入。则乘积的最终结果为0.25,误差为0.25-0.2451=0.0049。
(2)截断。则乘积的最终结果为0.24,误差为0.2451-0.24=0.0051。
从上面的处理过程可知,一旦采用定点数格式,则当在数字信号处理系统中进行上亿次的乘加运算时,就不难发现这些微小的误差会因为累积效应而对最后的计算结果造成严重的影响,会最终得到错误的计算结果。
二进制小数会使得算术运算变得容易,也易于处理字长。例如,考虑这样一个机器表示方法,它有4位十进制数和具有4个数字位的一个算术单元,其表示范围为-9999~+9999。两个这样的4位十进制数相乘将产生最多8个有效数字,范围为-99980001~+99980001,例如:
6787×4198=28491826
如果想把这个数送到该机器的下一级,假设其算术运算具有4位的精度,则:
(1)标定。按比例将乘积缩小10000倍,即28491826/10000=2849.1826。
(2)截断。对标定后的数据,只保留整数部分,而舍去小数部分,即2849。
当把这个处理结果送到机器下一级的时候,进行下面的处理。
(1)计算。两个数相乘,即2849×1627=4635323。
(2)标定。将计算得到的乘积扩大10000倍,即4635323×10000=46353230000;
当不采用上面的处理过程而只进行乘积运算时,得到真实的乘积结果为
6867×4198×1627=46902612582
而在乘积过程中采用标定得到的最终计算结果为46353230000,这个结果接近真实的乘积结果46902612582。很明显,由于标定出现截断误差。因此,就需要对这个计算结果进行修正。除了这个以外,主要问题就是需要跟踪标定,这非常不方便。那还有其他方便的方法吗?答案肯定是有,那就是通过归一化进行处理。
在进行乘法运算之前,先将乘数和被乘数进行归一化处理(归一化后的数据的表示范围为-0.9999~+0.9999),然后再进行乘法运算,即
(1)6787归一化后表示为0.6787,4198归一化后表示为0.4198。
(2)将两个归一化的数相乘的结果表示为0.6787×0.4198=0.28491826。
若对运算结果进行截断处理,则最终的结果表示为0.2849。现在,截断到4位的操作变得相当容易。当然两种结果严格一致,差别仅仅存在于如何执行截断和标定操作。
当对输入数据进行归一化操作时,所有的输入值都在-1~+1的范围内。很明显,在该范围内,任意两个数的乘积同样也在-1~+1的范围内。
类似地,将归一化操作应用于二进制运算中。由于大多数数字信号处理系统也使用二进制运算,因此将使得数字信号处理更加便捷。
下面考虑字长为8位且使用补码表示的二进制系统,该系统表示数的范围在(10000000) 2 =(-128) 10 ~(01111111) 2 =(+127) 10 之间。如果将这个范围内的有符号数归一化到-1~1的范围内,则需要将有符号数除以128,则归一化后的数据的表示范围在(1.0000000) 2 =(-1) 10 ~(0.1111111) 2 =(0.9921875) 10 之间,其中127/128=0.9921875。
这样,就把十进制乘法中归一化的概念应用到二进制系统中了。
对于一个十进制乘法36×97=3492而言,它等价于下面的二进制乘法,即
(00100100) 2 ×(01100001) 2 =(000011011010010) 2 。
当把乘数和被乘数归一化后,应用于二进制系统时,二进制的乘法运算将变成:
(0.0100100) 2 ×(0.1100001) 2 =(0.00110110100100) 2
该运算结果等价于十进制的乘法运算结果,即
0.28125×0.7578125=0.213134765625
注 :在数字信号处理系统中,二进制定点是存在的。然而,没有实际的连接或连线。这只是使得跟踪字长增长,以及通过扔掉小数位使截断变得更加容易。当然,如果更愿意使用整数并且跟踪定标等,也可以这样做。所得到的答案是一致的,并且硬件开销也是相同的。
在采用二进制的数字信号处理系统中,截断就是简单去掉比特位的过程,通常使用这种方法来将较宽的二进制字长变成较短的二进制字长。在截断时,通常需要丢掉最低有效位(Least Significant Bit,LSB),使用该操作将影响数据的精度。
考虑将十进制数7.8992截断到3个有效位7.89。当然,可以截断最低有效位,其结果是损失了精度,即分辨率,但它仍表示了最初的5位十进制数。如果截断最高有效位(MSB)-992(或0.0992),将导致出现不希望的结果,而且也失去了意义。
在二进制中,很少使用截断最高有效位的概念。在十进制的例子中,截断MSB会造成灾难性的后果。然而,在某些极少情况下,一系列的操作将导致整个数值范围的减小。所以去除MSB也是有好处的。
截断MSB通常发生在要截断的位为空的时候。当使用有符号的值时,由于丢失了符号位,截断 MSB 将会带来问题。
四舍五入是一种更准确的方法,但同时也需要更复杂的技术。该技术需要进行一个加法操作(通常是加1/2 LSB),然后再直接截断。该过程等价于十进制的四舍五入,如对于7.89而言,操作过程为7.89+0.05=7.94,然后将其截断到7.9,这样实现四舍五入到一个小数位。因此,简单的四舍五入操作需要一个加法操作。
Trounding是截断和四舍五入之间的一种折中方法。其特点有:
(1)与四舍五入一样,Trounding保留了LSB以上的信息;
(2)它又和四舍五入不同,这种方法不会影响新的LSB以上的任何位。
Trounding的好处是它不需要全加器,而且可以通过或门得到比截断更好的性能,如图3.19所示。
图3.19 Trounding对数据的处理
尽管采用Trounding只有一个很小的优点,但这种节约成本和改善性能的方法对于定点数的运算非常有价值。
在VHDL语言中提供了定点数运算的库,这些库可以用于实现对定点数的各种不同运算。
注 :(1)对于其他更复杂的运算实现方式,读者可以参考文档:<<Fixed point package user’s guide By David Bishop(dbishop@vhdl.org)>>
(2)VHDL可以实现定点数的行为级和RTL级的描述,但是Verilog HDL没有提供定点数RTL级描述的库。
对于定点数的运算而言,其数据宽度需要满足表3.7给出的条件。
表3.7 定点数运算的宽度关系
注 :(1 )对于Quartus Prime Pro集成开发环境的Analysis&Synthesis而言,需要将定点运算库的声明语句设置为
library ieee;
use ieee.fixed_pkg.all;
(2)对于ModelSim-INTEL FPGA STARTR EDITION 2019.2仿真工具而言,需要在设计文件和测试文件中同时将定点运算库的声明语句设置为
Library floatfixlib;
use floatfixlib.fixed_pkg.all;
且在Modelsim仿真工具命令行中输入下面的命令:
vlib floatfixlib
在使用VHDL描述定点数的运算时,需要声明定点数的小数和整数位数的声明格式。例如,无符号定点数的格式声明为
其中:(1)ufixed表示无符号的定点数,即整数部分的最高位不包含符号位;sfixed表示有符号定点数,即整数部分的最高位为符号位。
(2)(5 downto 0)为定点数的整数部分,一共有6个比特位。
(3)(-1 downto-3)为定点数的小数部分,一共有3个比特位。