如何将 hann 窗口应用于无符号整数 ADC

信息处理 模数 C 固定点 嵌入式系统
2022-02-05 22:56:14

我正在使用 Arm-Cortex M3 微控制器和 CMSIS 进行 FFT,我的微控制器不支持浮点单元,因此我必须使用定点(Q15 或 Q31)进行计算。在计算 FFT 之前,我需要对从 ADC 12 位 (0-4095) 收集的数据应用汉宁窗。我的 ADC 数据范围为 1800 ~ 3200。这是我迄今为止尝试过的示例代码。我正确申请了吗?

double hann[512];
uint32_t ADC[512]; /* data range 1800 ~ 3200 */
q31_t input[512]; /* fixed point */

// Hann window
for (int i = 0; i < 512; i++)
{
    hann[i] = 0.5 * (1 - cos(2*PI*i/511));
}

// apply hann window to ADC data
for (int j = 0; j < 512; j++)
{
    ADC[j] = (ADC[j] - DC) * hann[j];
    input[j] = (q31_t)ADC[j] << 19; // convert to fixed point Q31 from 12-bit
}
1个回答

我正确申请了吗?

不,至少不是按照你的计划:

ADC[j] = (ADC[j] - DC) * hann[j];

在这里,您将整数ADC[j]-DC与 a相乘double这是一个浮点运算。如果您的处理器没有浮点硬件,这意味着您的编译器必须在软件中模拟该乘法。此外,保存回 ADC 读出区域听起来不是一个好主意。(它不会“节省内存”,无论如何您的计算都是在寄存器中完成的,并且您实际上是在告诉编译器您希望内存ADC指向具有特定值,这可能会作为实际存储该值的提示一次性价值。)

然后将其转换回无符号整数以将其保存在ADC[j]? 你的编译器应该告诉你这是个坏主意。如果有的话,在截断为整数值之前,你仍然可以缩放浮点数。

因此,您需要首先在定点版本中创建您的 Hann 窗口。几乎没有理由在微控制器本身上这样做。cos在 CPU 时间和程序内存方面都是一项昂贵的功能,因此在 Cortex-M 上,您通常会避免使用它。

相反,您可能会在 PC 上使用您最喜欢的语言,并计算一个 Hann 窗口,将其放大以适合您所需的符号范围,将其四舍五入并将其保存为您选择的 Q 格式。您将采用前半部分(对称意味着您实际上并不需要两半)并将其作为常量集成到您的程序中。

在运行时,您将与这些正确的预缩放整数相乘,这样您就不必单独移动 - 节省了不必要的单独操作。(记住:与整数<<1相同*2。)

我的 ADC 数据范围为 1800 ~ 3200。

因此,您实际上只有 400 的动态范围,即少于 9 位。在这种情况下,使用 32 位二进制数字的数字格式您将获得很少的收益。Q1.15 绰绰有余。

顺便说一句,在进行 FFT 之前减去 DC 分量几乎没有意义。只需忽略转换后 FFT 的 0. bin - 那是 DC 分量。

第二个“顺便说一句” q31_t类型只是int32_t. 最好不要把它当作什么特别的东西来对待。不是特别喜欢那种类型,“Q1.31”是对整数数据的解释,实际上不是它的类型(就像“香蕉计数”是对整数的解释,而不是特殊的整数计数)。