Math 定点数学中的溢出

Math 定点数学中的溢出,math,signal-processing,fixed-point,Math,Signal Processing,Fixed Point,作为部分学习练习,部分爱好项目,我正在使用定点数学在AVR上实现我自己对Cooley Tukey FFT算法的解释。我以前没怎么处理过定点数学,我想知道如何最好地进行部分实现。我想这个问题的要点是要求确认我正确地思考了所涉及的问题 C-T算法的核心是以以下方式(在psedoocode中)对复值数据进行一组乘法和加法: 余弦和正弦数据将是形式为S.XXX'XXXX的8位有符号二进制分数,输入数据也将是形式为SXXX.XXXX的8位有符号二进制分数,乘法将生成16位有符号分数乘积。在我看来,对于正弦

作为部分学习练习,部分爱好项目,我正在使用定点数学在AVR上实现我自己对Cooley Tukey FFT算法的解释。我以前没怎么处理过定点数学,我想知道如何最好地进行部分实现。我想这个问题的要点是要求确认我正确地思考了所涉及的问题

C-T算法的核心是以以下方式(在psedoocode中)对复值数据进行一组乘法和加法:

余弦和正弦数据将是形式为S.XXX'XXXX的8位有符号二进制分数,输入数据也将是形式为SXXX.XXXX的8位有符号二进制分数,乘法将生成16位有符号分数乘积。在我看来,对于正弦和余弦以及数据的实部和虚部的“坏”值,temp1或temp2将非常接近16位有符号整数的极限。
如果数据的实部和虚部都是(比如)b0111.1111,Wolfram Alpha中的一些工作表明,对于正弦和余弦的“坏”值,输出可能比简单地将正弦的最大值乘以输入的最大值要大1.4倍

例如,如果正弦参数为b0111.1111,输入值为b0111.111,则输出将为b0111111.00000001或十进制的16129。1.4倍,约为22580。这不会使有符号16位整数的正范围溢出,但在接下来的几行中,这些乘积将从输入数据中进行加减,并且假设此处的输入数据转换为16位,则很可能会发生溢出


在我看来,权衡是:要么提高数据的内部处理分辨率,这会增加处理时间,要么确保输入数据保持低于导致溢出的振幅,从而降低信噪比。这与事物的大小有关吗?

一个选择是将正弦和余弦值减少到Q6(小数点右边的6位),这将使它们变成+/-64。请注意,如果精度再高一点,-1是可表示的,但+1不是(即+128)。此外,相乘后,结果中将有2个符号位,这意味着2个乘积的总和可能可以毫无问题地相加。通过降低分辨率得到的额外信息,您应该能够真正避免溢出。另一点-如果你的复数值被限制在1的量级(real*real+img*img我知道这是很久以前的事了,但这里有一些我写的库中关于定点数学的注释

使用定点数学的概述 在量化或DSP类型数学区域的实现中出现的关键思想包括如何表示分数单位,以及当数学运算导致整数寄存器溢出时该怎么做

浮点(C、C++中的浮点或双精度类型)最常用于表示分数单位,但它们并不总是可用(不支持硬件或在低端微控制器上不支持库软件)。如果硬件支持不可用,则可以通过软件库提供浮点,但这些库通常比硬件实现慢至少一个数量级。如果程序员聪明,则可以使用整数数学代替软件浮点,从而产生更快的代码。在这些情况下,分馏如果使用比例因子,l单位可以用整数寄存器(短、int、长)表示

缩放和环绕 创建数字的缩放整数表示时出现的两个常见问题是

缩放-程序员必须手动跟踪分数缩放因子,而使用浮点数时,编译器和浮点库会为程序员执行此操作

溢出和环绕-如果添加两个大数字,结果可能大于整数表示形式,从而导致环绕或溢出错误。更糟糕的是,根据编译器警告设置或操作类型,这些错误可能不会被注意到。例如,两个8位数字(通常是C/C++中的字符)

字符a=34,b=3,c

//并计算

c=a*b

//将它们相乘,结果是102,这仍然适合8位的结果 //如果b=5会发生什么

c=a*b;//实际答案是170,但结果是-86

这种类型的错误称为溢出或环绕错误,可以用几种方法处理。我们可以使用较大的整数类型,如shorts或int,或者我们可以事先测试这些数字,看看结果是否会产生溢出。哪一种更好?这取决于具体情况。如果我们已经使用最大的自然类型(例如32位CPU上的32位整数)然后,我们可能必须在执行操作之前测试该值,即使这会导致一些运行时性能损失

精度损失 真正的浮点表示法可以在一系列操作中保持相对任意的精度,但是在使用定点(缩放)时数学-缩放过程意味着我们最终将可用比特的一部分用于所需的精度。这意味着小于缩放因子的数学信息将丢失,从而导致量化错误

一个简单的简单缩放示例让我们尝试用一个整数表示数字10.25,我们可以做一些简单的事情,比如将值乘以100,然后将结果存储在一个整数变量中。因此我们有:

10.25*100==>1025

如果我们想再加一个数字,比如说0.55,我们会取1.55,再放大100倍

0.55*100=>155

现在把它们加在一起,我们加上整数

1025+55==>1070

但让我们通过一些代码来了解这一点:

void main (void)
{
    int myIntegerizedNumber  = 1025;
    int myIntegerizedNumber2 =  155;
    int myIntegerizedNumber3;

    myIntegerizedNumber3 = myIntegerizedNumber1 + myIntegerizedNumber2;

    printf("%d + %d = %d\n",myIntegerizedNumber1,myIntegerizedNumber2,myIntegerizedNumber3);
}
但现在是几杯酒中的第一杯
void main (void)
{
    int myIntegerizedNumber  = 1025;
    int myIntegerizedNumber2 =  155;
    int myIntegerizedNumber3;

    myIntegerizedNumber3 = myIntegerizedNumber1 + myIntegerizedNumber2;

    printf("%d + %d = %d\n",myIntegerizedNumber1,myIntegerizedNumber2,myIntegerizedNumber3);
}