如何从信号的FFT中获取频率和对应的幅度?
我有一个信号,频率是 1.2Hz/9Hz/15Hz
。
import numpy as np
total_time = 5
sampling_frequency = 100
t = np.linspace(0, total_time, total_time * sampling_frequency, endpoint=False)
signal = np.sin(2 * np.pi * 1.2 * t) + 0.5*np.cos(2 * np.pi * 9 * t) + 0.75*np.sin(2 * np.pi * 15.0 * t)
plt.plot(t, signal)
还有这个离散傅里叶变换(FFT)的结果。
fft_spectrum = np.fft.rfft(signal)
fft_spectrum_abs = np.abs(fft_spectrum) * 2 / (total_time * sampling_frequency)
freq = np.fft.rfftfreq(signal.size, d=1./sampling_frequency)
plt.plot(freq, fft_spectrum_abs)
plt.xlabel("frequency, Hz")
plt.ylabel("amplitude, units")
plt.show()
我该如何得到FFT的频率和幅度呢?
我正在使用
[
(amp, freq) for amp, freq in sorted(zip(fft_spectrum_abs, freq),
key=lambda pair: pair[0]) if amp > 0.1
]
# [(0.4999999999999984, 9.0), (0.749999999999999, 15.0), (1.0, 1.2000000000000002)]
这个方法是对的,但感觉有点像是临时凑合的办法,有没有更好的方法来解决这个问题呢?
2 个回答
2
你可以使用 np.where
来找到索引,并同时筛选频率和幅度:
peaks_indices = np.where(fft_spectrum_abs > 0.1)[0]
freq_and_magnitudes = list(zip(freq[peaks_indices],
fft_spectrum_abs[peaks_indices]))
1
你可以使用 scipy 里的 scipy.signal.find_peaks
这个功能。假设你想找的峰值高度至少要有 0.1,那你可以通过 heights
这个参数来设置。当你指定了 heights
后,返回的 properties
字典里会有一个 "peak_heights"
的键,里面会包含一个 numpy 数组,这个数组就是你找到的峰值高度(名字就说明了)。
from scipy.signal import find_peaks
peaks, properties = find_peaks(fft_spectrum_abs, height=0.1)
peak_freq = freq[peaks]
peak_amp = properties["peak_heights"]
print(peak_freq) # [ 1.2 9. 15. ]
print(peak_amp) # [1. 0.5 0.75]
如果你的数据比较杂乱或者有噪声,这个方法可能会更有效。