C语言实现Biquad低通滤波器输出放大削波问题排查
看起来你遇到的幅值持续增大甚至削波的问题,大概率是代码或者滤波器设计环节出了问题,咱们结合你给出的代码片段一步步排查:
1. 状态数组未初始化的隐患
你定义了float in_state[40];和float out_state[40];但没有做初始化。C语言中,局部数组默认会被分配随机垃圾值,即便是全局数组,显式初始化也更稳妥。这些初始的随机状态值会直接参与滤波计算,很可能导致一开始就出现异常增益,甚至让滤波器进入发散状态。
解决办法:显式将状态数组初始化为0:
float in_state[40] = {0}; float out_state[40] = {0};
2. 滤波器系数的完整性与稳定性问题
你给出的coeff数组只展示了前3个前馈系数(a0、a1、a2),反馈系数b1和b2被截断了。Biquad滤波器的稳定性完全由反馈系数决定:
离散域中,滤波器的特征方程为 z² + b1*z + b2 = 0,只有当方程的所有根都落在单位圆内(根的模长小于1),滤波器才是稳定的。如果b1、b2的取值不符合这个条件,滤波器会直接发散,输出幅值持续增大直到削波。
另外,你可以验证系数的归一化合理性:对于低通滤波器,通常满足 a0 + a1 + a2 = 1 + b1 + b2(保证直流增益为1),如果系数不满足这个关系,也可能导致整体增益过高。
3. 状态数组的使用逻辑可能有误
Biquad滤波器只需要保存最近的2个输入(x[n-1]、x[n-2])和2个输出(y[n-1]、y[n-2]),你定义了长度40的数组,这本身没问题,但如果状态更新逻辑错误,比如没有正确移位保存最新状态,或者错误使用了更早的历史值,就会导致计算异常。
正确的状态更新逻辑应该是这样的(以单个样本处理为例):
// 假设当前输入为x_n,计算得到输出y_n // 更新输入状态:把旧值往后移,最新值放到最前面 in_state[2] = in_state[1]; in_state[1] = in_state[0]; in_state[0] = x_n; // 更新输出状态 out_state[2] = out_state[1]; out_state[1] = out_state[0]; out_state[0] = y_n;
如果你的代码里没有做这样的移位操作,而是随意使用数组元素,肯定会出问题。
4. 块处理的状态延续问题
你设置了#define blocksize 32,在处理每一块数据时,必须确保块与块之间的状态是延续的:比如处理完第32个样本后,下一块的第一个样本需要用上一块最后两个输入和输出的状态。如果你的代码在块处理后重置了状态数组,或者没有保留这些关键的历史值,也会导致计算异常。
建议你先检查反馈系数的完整性和稳定性,然后确保状态数组初始化正确,再核对状态更新的逻辑。如果能提供完整的滤波处理函数,能更精准地定位问题。
内容的提问来源于stack exchange,提问作者thomachan

