为什么我需要"fftshift" DFTs的乘积来恢复卷积乘积

Why do I need to "fftshift" the product of DFTs to recover the convolution product

我需要使用卷积定理计算卷积积。但是,我不明白为什么我需要在傅立叶逆变换上应用 fftshift 以获得正确的结果。否则,结果将被交换(好吧,我知道这就是 fftshift 的用途,但我不明白为什么我从逆 fft 获得交换结果)。这是一个最小的示例,其中包含两个快速减少的函数,因此我不会添加填充来打扰。根据 scipy.signal.convolve:

检查结果
    import numpy as np
    import scipy.signal as sig

    Nx = 400
    xp = np.arange(Nx) - Nx/2.
    Lg = 20
    Lb = 25

    ff = np.exp(-(xp/Lg)**2) * xp/Lg    # function (two bumps of opposite signs)
    gg = np.zeros(Nx)                   # convolution kernel (just a box)
    gg[abs(xp)<Lb] = 1

    conv_pure = sig.convolve(ff, gg, mode="same")  # that is the correct one

    tff = np.fft.rfft(ff)             # DFT of the function
    tfg = np.fft.rfft(gg)             # DFT of the kernel

    conv_dfts = np.fft.irfft(tff*tfg).real  # should be the convolution product
    conv_dftshift = np.fft.fftshift(conv_dfts)

And here is how it looks like

那么,为什么 conv_dfts 交换了?

为了正确定义 scipy.signal.convolvemode='full'mode='same' 中的计算,第一个参数中的数据(有效地)用零扩展。另一方面,您的 FFT 计算执行循环卷积,这对应于使用数据的周期性扩展。要查看此差异的后果,请考虑如何计算结果的第一个点。

(记住通常的 "sliding window" 卷积视图很有帮助,例如 http://mathworld.wolfram.com/Convolution.html or https://en.wikipedia.org/wiki/Convolution#Visual_explanation 所示。在您的情况下,滑动 window 是 gg.)

对于 scipy.signal.convolvemode='same',您可以通过将 gg 的右半部分与 ff 的左端对齐来可视化第一个点的计算,并且将这两个信号的元素乘积相加。 ff 在它的左端非常小,所以这个计算非常接近于 0。卷积的后续点保持为零,直到滑动 window 开始遇到更大的 ff 值。所以结果的"interesting"部分在卷积的中间。

对于 FFT 计算的第一个点,假设 gg 的右端与 ff 的左端对齐。再次取元素乘积的总和。这里有两个很大的不同。首先,gg 不像 scipy.signal.convolve 中的 mode='same' 那样移动一半长度。其次,gg 乘以的值不全为零——它们是 ff 的周期性扩展,所以在这个 "sliding window" 可视化中,我们有矩形 window直接对准双脉冲的中心(在周期性扩展中)。由于 gg 的对称性和 ff 的反对称性,第一个值为 0。随着 gg 向右滑动,对称性被打破,正脉冲主导计算,并且非平凡值被计算。一旦window通过双脉冲,卷积的值就会变得很小。当矩形脉冲遇到双脉冲的另一侧时,它们在卷积结束附近再次变得非常大。

为了使您的 FFT 计算与 scipy.signal.convolve 计算匹配,您可以调整 gg 中矩形脉冲的相位。例如(假设 Nx 是偶数)。例如,如果您添加此行

gg2 = np.roll(gg, -(Nx//2 - 1))

并在 tfg 的计算中使用 gg2 代替 gg:

tfg = np.fft.rfft(gg2)             # DFT of the kernel

然后 conv_dftsconv_pure 同意。您还可以通过其他方式调整事物以使结果与您预期的一致。这个答案的重点是解释为什么你计算的结果不同。