c中定点算术二阶IIR实现的问题

信息处理 过滤器 无限脉冲响应 C 固定点
2022-02-16 19:13:06

DSP新人来了!

我正在修补 TI DSP 并尝试在 C 中实现二阶 IIR 滤波器。输入是 16 位 2 的补码,输出也是如此,累加器是 32 位宽。我尝试了几种结构:直接形式 I、转置直接形式 II、Gold & Rader 结构。但是,我似乎无法工作,我不确定这是否是我所有过滤器实现的代码中的拼写错误,还是因为我误解了定点算术的原理。我假设 - 或者更好:希望 - 这是影响所有实现的同一个错误。

这是我的转置 df II 实现的代码:

// state variables
int w[3] = {0};

short filter_dfii(short value) {
    w[0] = ((value * sos_filter_coeffs_b[0] + w[1]) >> 15 ) & 0xffff;
    w[1] = value * sos_filter_coeffs_b[1]
       - w[0] * sos_filter_coeffs_a[1]
       + w[2];
    w[2] = value * sos_filter_coeffs_b[2]
       - w[0] * sos_filter_coeffs_a[2];

    return (short) w[0];
}

我的 df I 实现如下所示:

int last_value[2] = {0};

short filter_dfi(short value) {
    w[0] =
        ((value * sos_filter_coeffs_b[0]
        + last_value[0] * sos_filter_coeffs_b[1]
        + last_value[1] * sos_filter_coeffs_b[2]
        - w[1] * sos_filter_coeffs_a[1]
        - w[2] * sos_filter_coeffs_a[2])
        >> 15) & 0xffff;
    last_value[1] = last_value[0];
    last_value[0] = value;
    w[2] = w[1];
    w[1] = w[0];
    return (short) w[0];
}

滤波器系数为:

int sos_filter_coefficients_a = {32767, -51150, 21015};
int sos_filter_coefficients_b = {658, 1316, 658};

我是如何得到这些系数的?我使用了 Matlab 的“黄油”功能,并在我的具体情况下指定了截止频率为 0.05*fs 或 2400 kHz 的二阶巴特沃斯低通。然后我将每个系数乘以 32767 并将其四舍五入为整数值。如果我用这些量化系数调用 Matlab freqz 函数,我会得到一个带有预期结果的波特图,所以我相信量化误差不是这里的问题。

但是,结果不是低通,而是垃圾。不幸的是,我缺乏适当的测试设备来科学地描述结果,但它听起来像数字振荡,受实际输入信号的轻微调制,即使完全没有输入也存在。

所以,在我看来,这不可能是一个不稳定的过滤器,因为极点在单位圆内。它也不能是溢出限制循环,因为当只有低输入电平或根本没有输入时它不应该发生......对吗?

如果我将系数更改为

int sos_filter_coefficients_a = {32767, 0, 0};
int sos_filter_coefficients_b = {32767, 0, 0};

输入基本上没有按预期返回,所以我的问题很可能不是由任何外部因素引起的——我的系数、函数本身或两者都有问题。

任何帮助深表感谢!

2个回答

“&0xffff”操作是有问题的。它适用于正数,但对于负数,它也会掩盖符号位,因此您会将所有内容都转换为正数。

对于 DF1,最好延迟移位和屏蔽,直到您返回实际输出并转换为短路。这样,您可以将状态变量保持为全双精度。

对于初学者来说,“int”的大小是多少?16位还是32位?您的系数之一是“-51150”,它需要 17 位来表示,因此需要 32 位整数来表示系数。

确保“int”确实是一个 32 位整数,否则它将不起作用。或者,您可以将系数乘以 16384 而不是 32768,以使它们适合 16 位。