为什么我需要“移除”DFT的产品来恢复卷积产品

时间:2018-04-07 09:39:09

标签: python numpy scipy fft

我需要使用卷积定理计算卷积积。但是,我不明白为什么我需要在逆傅里叶变换上应用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

1 个答案:

答案 0 :(得分:2)

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

(记住卷积的常用“滑动窗口”视图很有帮助,例如http://mathworld.wolfram.com/Convolution.htmlhttps://en.wikipedia.org/wiki/Convolution#Visual_explanation所示。在您的情况下,滑动窗口为gg 。)

对于scipy.signal.convolve的{​​{1}},您可以通过将mode='same'的右半部分对齐gg的左端,并将总和进行求和来可视化第一个点的计算这两个信号的元素乘积。 ff在其左端非常小,因此该计算非常接近0.卷积的后续点保持为零,直到滑动窗口开始遇到更大的ff值。所以结果的“有趣”部分是在卷积的中间。

对于FFT计算的第一点,假设ff的右端与gg的左端对齐。再次取元素乘积的总和。这里有两个很大的不同。首先,ff的长度不会像gg中的mode='same'那样移动一半。其次,scipy.signal.convolve乘以的值并非都为零 - 它们是gg的周期性扩展,因此在这个“滑动窗口”可视化中,我们将矩形窗口直接对齐在中心上方双脉冲的(在周期性延伸中)。由于ff的对称性和gg的反对称性,第一个值为0.当ff向右滑动时,对称性被打破,正脉冲在计算中占主导地位,而非平凡值计算。一旦窗口通过双脉冲,卷积的值变得非常小。当矩形脉冲遇到双脉冲的另一侧时,它们在卷积结束时再次变得非常大。

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

Nx

并在计算gg2 = np.roll(gg, -(Nx//2 - 1)) 时使用gg2代替gg

tfg

然后tfg = np.fft.rfft(gg2) # DFT of the kernel conv_dfts同意。还有其他方法可以调整内容以使结果按预期对齐。这个答案的要点是解释为什么你计算的结果不同。