我知道在python中使用快速傅里叶变换(FFT)方法有几个问题,但遗憾的是,它们都不能帮我解决问题:
我想用python来计算给定二维信号f的快速傅里叶变换,即f(x,y)。 Pythons文档有很多帮助,解决了FFT带来的一些问题,但与我期望它显示的频率相比,我的最终频率仍然略有偏移。这是我的python代码:
from scipy.fftpack import fft, fftfreq, fftshift
import matplotlib.pyplot as plt
import numpy as np
import math
fq = 3.0 # frequency of signal to be sampled
N = 100.0 # Number of sample points within interval, on which signal is considered
x = np.linspace(0, 2.0 * np.pi, N) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N
y = x
xx, yy = np.meshgrid(x, y) # create 2D meshgrid
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction
ft = np.fft.fft2(fnc) # calculating the fft coefficients
dx = x[1] - x[0] # spacing in x (and also y) direction (real space)
sampleFrequency = 2.0 * np.pi / dx
nyquisitFrequency = sampleFrequency / 2.0
freq_x = np.fft.fftfreq(ft.shape[0], d = dx) # return the DFT sample frequencies
freq_y = np.fft.fftfreq(ft.shape[1], d = dx)
freq_x = np.fft.fftshift(freq_x) # order sample frequencies, such that 0-th frequency is at center of spectrum
freq_y = np.fft.fftshift(freq_y)
half = len(ft) / 2 + 1 # calculate half of spectrum length, in order to only show positive frequencies
plt.imshow(
2 * abs(ft[:half,:half]) / half,
aspect = 'auto',
extent = (0, freq_x.max(), 0, freq_y.max()),
origin = 'lower',
interpolation = 'nearest',
)
plt.grid()
plt.colorbar()
plt.show()
运行它时我得到的是:
现在您看到x方向的频率不完全在fq = 3
,但略微向左移动。为什么是这样?
我认为这与事实有关,即FFT是一种使用对称参数和
half = len(ft) / 2 + 1
用于显示适当位置的频率。但我不太明白究竟是什么问题以及如何解决它。
编辑:我也尝试使用更高的采样频率(N = 10000.0),这并没有解决问题,而是将频率稍微偏移到右边。所以我很确定问题不是采样频率。
注意:我意识到泄漏效应会导致非物理振幅,但在这篇文章中,我主要对正确的频率感兴趣。
答案 0 :(得分:2)
我发现了一些问题
你使用2 * np.pi
两次,如果你想要一个很好的整数个周期,你应该选择linspace或arg中的一个作为弧度正弦
另外np.linspace
默认为endpoint=True
,为您提供101而非100的额外积分
fq = 3.0 # frequency of signal to be sampled
N = 100 # Number of sample points within interval, on which signal is considered
x = np.linspace(0, 1, N, endpoint=False) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N
y = x
xx, yy = np.meshgrid(x, y) # create 2D meshgrid
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction
你可以检查这些问题:
len(x)
Out[228]: 100
plt.plot(fnc[0])
现在修复linspace端点意味着你有一个偶数个fft箱,所以你将+ 1
放在half
calc
matshow()
似乎有更好的默认设置,extent = (0, freq_x.max(), 0, freq_y.max()),
中的imshow
似乎会影响fft bin编号
from scipy.fftpack import fft, fftfreq, fftshift
import matplotlib.pyplot as plt
import numpy as np
import math
fq = 3.0 # frequency of signal to be sampled
N = 100 # Number of sample points within interval, on which signal is considered
x = np.linspace(0, 1, N, endpoint=False) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N
y = x
xx, yy = np.meshgrid(x, y) # create 2D meshgrid
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction
plt.plot(fnc[0])
ft = np.fft.fft2(fnc) # calculating the fft coefficients
#dx = x[1] - x[0] # spacing in x (and also y) direction (real space)
#sampleFrequency = 2.0 * np.pi / dx
#nyquisitFrequency = sampleFrequency / 2.0
#
#freq_x = np.fft.fftfreq(ft.shape[0], d=dx) # return the DFT sample frequencies
#freq_y = np.fft.fftfreq(ft.shape[1], d=dx)
#
#freq_x = np.fft.fftshift(freq_x) # order sample frequencies, such that 0-th frequency is at center of spectrum
#freq_y = np.fft.fftshift(freq_y)
half = len(ft) // 2 # calculate half of spectrum length, in order to only show positive frequencies
plt.matshow(
2 * abs(ft[:half, :half]) / half,
aspect='auto',
origin='lower'
)
plt.grid()
plt.colorbar()
plt.show()