我想用Python3计算功率谱。从另一个关于这个主题的主题我得到了基本的成分。我认为它应该是这样的:
ps = np.abs(np.fft.fft(x))**2
timeres = t[1]-t[0]
freqs = np.fft.fftfreq(x.size, timeres)
idx = np.argsort(freqs)
plt.plot(freqs[idx], ps[idx])
plt.show()
此处t
是时间,x
是光子数。我也尝试过:
W = fftfreq(x.size, timeres=t[1]-t[0])
f_x = rfft(x)
plt.plot(W,f_x)
plt.show()
但两者大多只是给我一个零左右的峰值(尽管它们不一样)。我试图从这个计算功率谱:
哪个应该给我一个大约580Hz的信号。我在这里做错了什么?
答案 0 :(得分:5)
我觉得 @kwinkunks '回答:
你提到看到一个大的零峰值。正如我在上面的评论中所说,如果您的输入信号具有非零均值,则可以预期这种情况。如果你想摆脱DC component那么你应该在进行DFT之前去掉你的信号,例如减去平均值。
在进行DFT之前,您应该始终在信号中应用window function以避免spectral leakage的问题。
虽然采用DFT的模数平方将给出粗略估计的谱密度,但这对信号中的任何噪声都非常敏感。针对噪声数据的更稳健的方法是计算信号的多个较小段的周期图,然后对这些段进行平均。这在频域中交换了一些分辨率以提高鲁棒性。 Welch's method使用此原则。
我个人会使用scipy.signal.welch
,它解决了我上面提到的所有问题:
from scipy.signal import welch
f, psd = welch(x,
fs=1./(t[1]-t[0]), # sample rate
window='hanning', # apply a Hanning window before taking the DFT
nperseg=256, # compute periodograms of 256-long segments of x
detrend='constant') # detrend x by subtracting the mean
答案 1 :(得分:1)
为了它的价值,我的方法如下:
from scipy.fftpack import fft, fftfreq
import matplotlib.pyplot as plt
dt = 0.001
X = fft(x)
freq = fftfreq(x.size, d=dt)
# Only keep positive frequencies.
keep = freq>=0
X = X[keep]
freq = freq[keep]
ax1 = plt.subplot(111)
ax1.plot(freq, np.absolute(X)/3000.)
ax1.set_xlim(0,60)
plt.show()
例如,使用此信号......
T = 10
f = 2
f1 = 5
t = np.linspace(0, T, T/dt)
x = 0.4 * np.cos(2*np.pi*f*t) + np.cos(2*np.pi*f1*t)
我得到了这个频谱: