低通滤波函数输出异常尖峰问题排查求助
低通滤波过零时刻出现尖峰问题
已更换更清晰的图片以便更好地展示问题。我的低通滤波函数在信号每次经过“地电平”时都会产生奇怪的尖峰。已尝试多种输入范围(-1 - 1)、(-127 - 128)、(0 - 255),低通滤波功能正常,但这些尖峰始终存在。
这并非显示问题,我已将数据写入文件并在Audacity中打开,显示结果一致。
数据通过SDL2从WAV文件加载并转换为8位单声道格式。我希望该函数读取wav_buffer中的数据,应用低通滤波后复制到loud_buffer中。
相关代码
// for reference Uint8 *wav_buffer; int wav_length; Uint8 *loud_buffer; const int filter_cutoff = 2000; const int sRate = 44100; void low_pass() { float prevOutput = 0; float prevInput = 0; float x = tanf(M_PI * filter_cutoff / sRate); float output; for (int p = 0; p < wav_length; p++) { output = x * wav_buffer[p] + x * prevInput - (x-1) * prevOutput; output /= (x+1); loud_buffer[p] = output; prevOutput = output; prevInput = wav_buffer[p]; } }
数据对比
原始wav_buffer数据(正常):
经过low_pass处理后的loud_buffer数据(存在尖峰):
问题解决
问题根源在于8位单声道WAV的无符号格式未正确转换,以及初始状态设置不合理:
- 8位WAV的
Uint8是无符号值,范围0-255,实际音频的“地电平”是128而非0。直接用原始值参与滤波会引入128的直流偏移,导致滤波算法在信号跨越128时产生异常尖峰。 - 初始
prevInput和prevOutput设为0,与实际信号的直流基线(128)不匹配,加剧了瞬态尖峰。
修改后的函数如下:
void low_pass() { if (wav_length == 0) return; // 转换第一个输入为有符号值,初始化状态匹配信号基线 float prevInput = wav_buffer[0] - 128.0f; float prevOutput = prevInput; float x = tanf(M_PI * filter_cutoff / (float)sRate); float a = x / (x + 1.0f); float b = (x - 1.0f) / (x + 1.0f); // 处理第一个样本 loud_buffer[0] = (Uint8)(prevOutput + 128.0f + 0.5f); for (int p = 1; p < wav_length; p++) { float input = wav_buffer[p] - 128.0f; float output = a * input + a * prevInput - b * prevOutput; // 转换回无符号格式并四舍五入,避免截断误差 loud_buffer[p] = (Uint8)(output + 128.0f + 0.5f); prevOutput = output; prevInput = input; } }
关键修改点:
- 将无符号输入转换为以128为0点的有符号浮点值,消除直流偏移影响
- 初始状态设为第一个转换后的输入值,匹配信号基线,避免初始瞬态
- 处理后输出转换回无符号格式时添加0.5做四舍五入,减少截断带来的误差
内容的提问来源于stack exchange,提问作者Jake A
相关产品推荐
相关产品推荐

