离散傅里叶变换:如何正确使用fftshift与fft

8 投票
3 回答
22169 浏览
提问于 2025-04-17 04:10

我想在一个numpy数组Y上计算快速傅里叶变换(FFT)。为了测试,我使用了高斯函数Y = exp(-x^2)。它的傅里叶变换结果是Y' = 常数 * exp(-k^2/4)。

import numpy
X = numpy.arange(-100,100)
Y = numpy.exp(-(X/5.0)**2)

直接的方法失败了:

from numpy.fft import *
from matplotlib import pyplot

def plotReIm(x,y):
    f = pyplot.figure()
    ax = f.add_subplot(111)
    ax.plot(x, numpy.real(y), 'b', label='R()')
    ax.plot(x, numpy.imag(y), 'r:', label='I()')
    ax.plot(x, numpy.abs(y), 'k--', label='abs()')
    ax.legend()


Y_k = fftshift(fft(Y))
k = fftshift(fftfreq(len(Y)))
plotReIm(k,Y_k)

real(Y_k)的值在正负之间跳动,这对应于一个跳跃的相位,而在符号结果中并不存在这种情况。这显然是不理想的。(从技术上讲,结果是正确的,因为abs(Y_k)给出的幅度是符合预期的,ifft(Y_k)的结果是Y。)

这里,fftshift()函数使数组k单调递增,并相应地改变Y_k。对这两个向量应用这个操作不会改变成对的zip(k, Y_k)。

这种变化似乎解决了问题:

Y_k = fftshift(fft(ifftshift(Y)))
k = fftshift(fftfreq(len(Y)))
plotReIm(k,Y_k)

如果需要单调递增的Y和Y_k,这样使用fft()函数是正确的吗?

上述操作的反向操作是:

Yx = fftshift(ifft(ifftshift(Y_k)))
x = fftshift(fftfreq(len(Y_k), k[1] - k[0]))
plotReIm(x,Yx) 

在这种情况下,文档明确指出,Y_k必须按照fft()和fftfreq()的输出进行排序,我们可以通过应用ifftshift()来实现。

这些问题困扰了我很久:fft()和ifft()的输入和输出数组是否总是满足这样的条件:a[0]应该包含零频率项,a[1:n/2+1]应该包含正频率项,a[n/2+1:]应该包含负频率项,按频率从负到正的顺序排列 [numpy参考],其中“频率”是自变量?

高斯的傅里叶变换不是高斯上的回答并没有解答我的问题。

3 个回答

3

关于fft(快速傅里叶变换)和ifft(逆快速傅里叶变换)输出的定义可以在这里找到:http://docs.scipy.org/doc/numpy/reference/routines.fft.html#background-information

这些程序计算的就是这些内容,没多也没少。要注意,离散傅里叶变换和连续傅里叶变换是有很大不同的。对于一个采样非常密集的函数,它们之间有一定的关系,但这个关系还涉及到相位因子和缩放,除了fftshift之外。这就是你在图表中看到的波动的原因。你可以根据上面的离散傅里叶变换的数学公式自己算出所需的相位因子。

4

快速傅里叶变换(FFT)可以理解为生成一组向量,每个向量都有一个幅度和相位。fft_shift操作是将相位角为零的参考点,从FFT的边缘移动到原始输入数据向量的中心。

这样做后,结果的相位(也就是复向量的实部)有时会显得不那么“跳跃”,特别是当输入函数在FFT边缘处不连续时。或者如果输入在FFT的中心对称,那么经过fft_shift后,FFT结果的相位总是会变成零。

fft_shift可以通过将向量旋转N/2来实现,或者简单地翻转FFT结果中的交替符号位,这样可能对CPU的缓存更友好。

撰写回答