通过 FFT 实现的 FIR - 低通效果很好,高通会产生失真的结果。怎么了?

信息处理 fft
2022-01-29 14:11:04

我正在实现(在软件中)FIR 滤波器。我已经完成了两种实现:卷积一种和基于 FFT/IFFT 的频域乘法。我正在使用标准的 FFT 实现(不是我自己的)和重叠相加处理。

FFT 参数会自动选择如下:fftSize=22log2(nTaps)samplesPerOp=fftSizenTaps+1overlapSize=nTaps1

现在我正在测试我的实现。我生成的信号为,其中另外,我通过 windowed-sinc 方法设计了两组抽头:一组用于低通,过渡带为,另一组具有相同过渡带的高通。我尝试过不同的窗口——Hamming、Blackman-Harris 等。cos(F12pin/Fs)+cos(F22pin/Fs)F1=10F2=1000Fs=44100110Hz900Hz

我将这两个滤波器应用于信号,具有卷积和 FFT 实现。低通滤波器在这两种情况下都能很好地工作:当我选择时(通过教科书中的估计公式 - frederic j. harris 的“多速率信号处理”,对于 90dB 衰减,它给了我抽头)我得到了干净的 10Hz来自两种实现的信号(它们在信号的边缘上有所不同,但这是预期的,当然)nTapsnTaps=327

但是高通滤波器的行为很奇怪。卷积实现工作。它提供几乎不受干扰的 1000Hz 正弦波。FFT 实现返回一团糟。FFT 滤波的结果看起来像 1000Hz 信号,但它非常损坏 - 相位抖动、幅度抖动等。

看起来,我做错了什么,但我不明白是什么。每本关于使用 FFT 进行 FIR 滤波的教科书、教程和文章都没有提到这样的事情。

哦,我使用的是double,而不是定点算术,所以精度损失应该不是问题。

而且,不,它不是硬件 :)

以下是来自 gnuplot 的图片(«秒»的 1/5):

低通,顶部卷积,向下 FFT:http: //lev.serebryakov.spb.ru/dsp/dsp-low-pass-side-by-side.png
高通,顶部卷积,向下 FFT : http: //lev.serebryakov.spb.ru/dsp/dsp-high-pass-side-by-side.png

2个回答

好的,我在我的代码中发现了错误,在这里发布答案可能很有用,因为我使用“标准”FFT 库,将来有人可能会重复我的错误。

我正在使用 Java 的 JTransforms 库来进行 FFT。它对纯实信号的 FFT 使用了非常紧凑的结果表示:它只返回一半的分量,并且在这里真正重要的是,结果数组的前两个元素不是(re, im) 对,而是的两个实(在纯实数据的情况下是实数)。X0XN/2

我的错误是,我将两个向量 (fft(taps)fft(signal)) 相乘为复数向量,然后对这两个第一个分量进行处理!在低通版本中它并不重要,但对于高通来说它是至关重要的。

因此,如果您使用 JTransform 的结果,正确的程序是将前两个元素作为实数进行复数,并且仅将接下来元素作为个复数进行复数。N2N/21

有用!

看起来你的方法在原则上是正确的,所以它可能是实际实现中的一个错误。

您损坏的输出显然是“块状的”,因此看起来像是某种框架错误。您损坏的高通输出具有明显的恒定幅度块,看起来长度相同。该长度很可能与滤波器长度或 FFT 大小有关。还值得检查您是否在块边界处也存在相位不连续性。您可以提供的信息越多,就越容易推测潜在的问题。

没有实际看到代码很难说。