将 [-1,+1] 浮点映射到 Q31 定点

Dan*_*jel 5 c signal-processing fixed-point

我需要将浮点数转换为Q31定点,Q31表示1个符号位,0位表示整数部分,31位表示小数部分。这意味着Q31只能表示范围内的数字[-1,0.9999]

\n\n

根据定义,从浮点转换为定点时,乘以2\xcb\x87N会进行乘法,其中 N 是小数部分大小,在本例中为 31。

\n\n

但是,我对这段代码感到困惑,它看起来不正确,但有效:

\n\n
#define q31_float_to_int(x) ( (int) ( (float)(x)*(float)0x7FFFFFFF ) )\n
Run Code Online (Sandbox Code Playgroud)\n\n

而且似乎工作正常。例如:

\n\n
int a = q31_float_to_int(0.5f); \n
Run Code Online (Sandbox Code Playgroud)\n\n

给出Hex: 0x40000000,这没问题。

\n\n

为什么这里的乘法是用 完成的2\xcb\x8731 - 1,而不仅仅是2\xcb\x8731完成的?

\n

Aya*_*qat 3

上面的代码不是从浮点转换为定点的好解决方案。我猜测编写代码的人使用比例因子0x7FFFFFFF来避免输入为 时溢出1.0。正确的缩放因子是2^31,而不是2^31 - 1float请注意,将 a (24 位精度)转换为 an Q1.31(31 位精度)时也存在精度问题。考虑在乘法之前使输入数据饱和:

const float Q31_MAX_F =  0x0.FFFFFFp0F;
const float Q31_MIN_F = -1.0F;
float clamped = fmaxf(fminf(input, Q31_MAX_F), Q31_MIN_F);
Run Code Online (Sandbox Code Playgroud)

上面的代码将限制input在 的范围内[-1.0, 1.0)。考虑到 24 位精度,该常数Q31_MAX_F约为,并且为。然后您可以乘以,或者更好的是,使用scalbnfldexpf1 - (2 ^ -24)Q31_MIN_F-1clamped2^31

int result = (int) scalbnf(clamped, 31);
Run Code Online (Sandbox Code Playgroud)

如果你想要四舍五入:

int result = (int) roundf(scalbnf(clamped, 31)));
Run Code Online (Sandbox Code Playgroud)