在数字信号处理系统中,经常需要使用不同的数值对正弦波信号进行描述,如图3.16所示为正弦波信号的表示。
图3.16 正弦波信号的表示
很显然,这需要对非整数数值进行处理。对这种非整数数值的处理方法是允许正弦波的幅度按比例增加,并使用整数形式来表示。如图3.17所示,二进制补码使用得并不多,如使用两个比特位表示所得到的值是-2、-1、0和1,使得存在较大的量化误差。显然,需要处理非整数数值的情况。
图3.17 正弦波的整数量化表示
这种方法很常见,但在某些情况下,需要表示0~1之间的数值,也需要表示整数之间的数值。
用十进制表示小数很容易。通过引入十进制小数点来描述非整数的值,并在小数点的右边插入数字。例如:
定点数就是二进制小数点在固定位置的数,将二进制小数点左边部分的位定义为整数位,而将该点右边部分的位定义为小数位。例如,对于定点数(101.01011) 2 而言,有3个二进制整数位101,5个二进制小数位01011。通常,定点数表示为Qm.n格式,即
其中,(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。
很明显,当m增加的时候,所表示数的范围就会增加,但是精度会降低;当n增加的时候,所表示数的精度就会增加,但是动态范围会降低。
有符号定点数的表示方法如表3.5所示。
表3.5 有符号定点数的表示
对于下面给出的定点数表示格式:
(1)格式表示为<FIX_12_5>,即一共12个二进制比特位。其中,5个二进制小数位,7个(12-5=7)二进制整数位。
(2)所表示的十进制整数为
思考与练习3-19 :若表示的最大值为278、最小值为-138,使用11位二进制数表示时,格式为什么?(<FIX_11_1>)
范围在-1~1之间的定点数的表示格式如表3.6所示。
表3.6 范围在-1~1之间的定点数的表示格式
例如,Motorola StarCore 和TI C62x DSP处理器都使用只有一个整数位的定点表示法。这种格式可能是有问题的,因为它不能表示+1.0。实际上,任何定点格式都不能表示其负数最小值的相反数。所以,在使用定点数时要多加注意。一些DSP芯片允许通过扩展位对格式进行1个整数位的扩展(这些扩展位就是附加的整数位)。
思考与练习3-20 :若表示的最大数为+1、最小数为-1,使用12位的二进制数表示,则表示格式为什么?(<FIX_12_10>)
思考与练习3-21 :若表示的最大数为0.8,最小数为0.2,使用10位二进制数表示,则表示格式为什么?(<UFIX_10_10>)
重新考虑数字的格式:
aaa.bbbbb
该格式表示有3个二进制整数位、5个二进制小数位,可以表示-4~+3.96785之间的数,数字之间的步长为0.03125。由于上面的表示格式中共有8位二进制数字,所以可表示2 8 =256个不同的值。
注 :使用定点时的量化将有±1/2LSB(最低有效位)的误差。
量化就是使用有限位数来表示无限精度的数。在十进制中,已经知道定位数的十进制小数的处理方法。实数π可以表示为3.14159265…,该实数可以量化为带4个十进制位的小数3.1416。如果在这里使用四舍五入,则误差为
如果使用截断法,即第4位小数以后的位数被舍弃,则误差将变得更大:
很明显,四舍五入是比较合适的处理方法,该处理方法能够得到预期的精度。然而,该方法也会带来一些硬件开销。
当乘以小数时,需要对最后的结果进行处理以满足位数的要求,如两个十进制小数相乘,计算过程如下:
对最终计算结果的处理方法有两个,即将其四舍五入到0.25,或者直接截断到0.24。很显然,两个处理结果是不同的。
一旦开始在数字信号处理系统中执行上亿次的乘加运算,就不难发现这些微小的误差会因为累积效应而对最后的计算结果造成严重的影响,即最终得到错误的计算结果。
二进制小数使得算术运算变得容易,也易于处理字长。例如,考虑这样一个机器表示方法,它有4位十进制数和具有4个数字位的一个算术单元,其表示范围为-9999~+9999。两个这样的4位十进制数相乘将产生最多8个有效数字,范围为-99980001~+99980001。例如:
如果想把这个数送到该机器的下一级,假设其算术运算具有4位的精度,那么需要按比例缩小10000倍,然后截断:
当送到下一级的时候,计算完后就需要扩大10000倍,即
然后再扩大10000,则最后结果变成46353230000,这个结果接近下面的值:
但是,很明显出现截断误差。因此,需要进行校正。除了这个以外,主要问题就是需要跟踪标定,这非常不方便。那还有其他方便的方法吗?答案是:有的,即通过归一化进行处理。
将上面的整数归一化到范围-0.9999~+0.9999中,然后再进行乘法运算,则得到:
如果对运算结果进行截断,则结果为0.2849。现在,截断到4位的操作变得相当容易。当然,两种结果严格一致,差别仅存在于如何执行截断和定标操作。
然而,对输入执行归一化操作,所有的输入值都在-1~+1的范围内。可以注意到,该范围内任意两个数的乘积同样也在-1~+1的范围内。
同样的归一化操作也适用于二进制运算,而且大多数数字信号处理系统也使用二进制。
下面考虑二进制补码中的8位数值,该数值的表示范围为10000000(=-128 10 )~01111111(=+127 10 )。
如果将这些数归一化到-1~+1的范围内,则需要除以128,则二进制数的表示范围为1.0000000(=-1)~0.1111111(=0.9921875)。其中:
这样,就把十进制乘法中归一化的概念应用到二进制系统中。
十进制乘法36×97=3492等价于二进制乘法:
在二进制中,将数值归一化就是计算0.0100100×0.1100001=0.00110110100100。其等价于十进制:
注 :在数字信号处理系统中,二进制定点是存在的。然而,没有实际的连接或连线。这只是使得跟踪字长增长,以及使通过扔掉小数位来截断变得更加容易。当然,如果更愿意使用整数并且跟踪定标等也可以这样做。所得到的答案是一致的,并且硬件开销也是相同的。
二进制中,截断就是简单地去掉比特位的过程。通常使用这种强制的方法将较宽的二进制字长变小。通常需要去掉最低有效位(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.18所示。尽管是一个很小的优点,但这种成本上的节省,以及性能的改善还是有价值的。
图3.18 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 定点数运算的宽度关系
下面给出在Vivado 2017.2集成开发环境中使用VHDL描述定点运算时添加定点运算支持的详细步骤。
(1)定位到Xilinx的安装路径下(作者将其安装在C:\xilinx下),然后找到下面的路径:
在该目录下,找到fixed_pkg_2008.vhd文件,并将其复制到当前的工程设计目录中。
(2)在当前的设计工程中,将该文件添加到当前的设计工程中。
(3)在“Sources”窗口中,找到并单击“Libraries”标签。在该标签页下,单击fixed_pkg_2008.vhd文件。在下面的“Source File Properties”对话框中,找到并单击“Library:”右侧的 按钮,出现“Set Library”对话框。
(4)在“Set Library”对话框的“Library name”右侧的文本框中输入“ieee”,将该文件编译到ieee库中。
(5)在“Sources”窗口中,找到并单击设计文件,如top.vhd文件。在下面的“Source File Properties”窗口中,找到并单击“Type:”右侧的 按钮,出现“Set Type”对话框。
(6)在“Set Type”对话框“File type”右侧的下拉框中找到并选择“VHDL 2008”,将该文件设置为支持VHDL 2008语法标准。
(7)按照相同的方法,将仿真文件也设置为支持VHDL 2008语法标准。
注 :(1)对于综合而言,需要将定点运算库的声明语句设置为
library ieee;
use ieee.fixed_pkg.all;
(2)对于仿真而言,需要将定点运算库的声明语句设置为
library ieee_proposed;
use ieee_proposed.fixed_pkg.all;
在使用VHDL语言实现定点运算的时候,需要声明定点数的小数位和整数位,如无符号定点数的格式声明为
其中:(1)(5 downto 0)表示定点数的整数部分,一共有6位。
(2)(-1 downto-3)表示定点数的小数部分,一共有3位。
注 :有符号定点数应该声明为sfixed。