为何利用卷积定理计算卷积时需用fftshift处理DFT/逆FFT结果?
为什么逆FFT后需要fftshift才能得到正确的卷积结果?
我来给你把这个问题掰碎了说——其实这背后全是DFT(离散傅里叶变换)的「周期性执念」在作祟,和我们对「卷积」的直观理解产生了错位,才导致你必须用fftshift来修正结果。
核心根源:DFT默认处理的是周期信号
你用numpy.fft.fft或者ifft的时候,一定要记住一个关键前提:DFT把你输入的有限长信号,当成了某个无限周期信号的单个周期。而卷积定理里的「频域乘积逆变换」,得到的其实是循环卷积,不是我们平时直觉里的线性卷积。
循环卷积和线性卷积的错位问题
假设你有两个长度都是N的信号:
- 线性卷积的结果长度是
2N-1,是我们认知里「滑动相乘求和」的自然结果,从信号的起始点开始逐步叠加。 - 循环卷积的结果长度还是
N,它相当于把线性卷积的结果做周期延拓(周期为N),然后截取了从0到N-1的主周期区间。这就导致线性卷积的后半部分会「绕回来」,和前半部分叠加在主周期里——这就是你看到的「错位交换」的直接原因。
fftshift到底在修正什么?
fftshift的本质是把DFT/逆DFT结果的「原点」(也就是信号的中心)从数组的第0位,移到数组的中间位置。对于循环卷积的结果来说,这个操作相当于把周期延拓后的信号的中心,对齐到我们直观认知里线性卷积的中心位置。
因为你的信号衰减很快,线性卷积里那些「绕回来」叠加的边缘部分幅值极小,几乎可以忽略,所以fftshift之后的循环卷积结果,就和scipy计算的线性卷积的核心部分完全一致了。
极简代码验证
我们用两个衰减指数信号来测试,对比有无fftshift的结果差异:
import numpy as np from scipy.signal import convolve # 定义两个快速衰减的信号,长度均为100 x = np.exp(-np.linspace(0, 6, 100)) h = np.exp(-np.linspace(0, 4, 100)) # 1. 线性卷积(作为正确结果参考) linear_conv = convolve(x, h, mode='full') # 2. 卷积定理:不使用fftshift X = np.fft.fft(x) H = np.fft.fft(h) Y = X * H conv_no_shift = np.fft.ifft(Y).real # 3. 卷积定理:使用fftshift conv_with_shift = np.fft.fftshift(conv_no_shift) # 对比线性卷积的中间100个点(和循环卷积长度一致) linear_mid = linear_conv[49:149] # 线性卷积长度199,取中心100个点 print("无fftshift时的最大误差:", np.max(np.abs(conv_no_shift - linear_mid))) print("有fftshift时的最大误差:", np.max(np.abs(conv_with_shift - linear_mid)))
运行后你会发现:无fftshift的误差极大,结果完全错位;而有fftshift的误差几乎为0,和线性卷积的核心结果完全对齐。
一句话总结
DFT的周期性假设让逆FFT返回的是线性卷积的周期延拓主值,fftshift帮你把这个主值的中心对齐到线性卷积的中心,从而得到符合直觉的正确结果。
内容的提问来源于stack exchange,提问作者M. Alborne
相关产品推荐
相关产品推荐

