numpy.fft 频率和幅度错误,光谱绘制奇怪
为了理解ffts的用法,我在python中实现了一个离散信号的低通滤波器。
经过滤波后得到的信号基本上是我想要的,但不幸的是,频谱的结果并不是我预期的。乍一看它们似乎还不错,但如你所见,幅度和频率都不正确。
我期望的频率应该是0Hz、220Hz和660Hz,幅度分别是3、2和1;但实际结果如下面的图所示。请注意,图中的幅度不正确,因为我在绘图命令中写了abs(F)/N
,而不是2*abs(F)/N
。但当我这样做时,直流值变成了6,我觉得这也是不对的。
而且频谱的绘制对我来说也有点奇怪,请看一下这个:
我不知道自己哪里做错了,非常希望能得到一些帮助。
import numpy as np
import matplotlib.pyplot as plt
from math import pi
N = 2048
w0 = 2*pi*220
t = np.linspace(0, 0.1, N)
signal = lambda x: 3 + 2*np.sin(w0*x) + np.sin(3*w0*x)
f = np.array(signal(t))
F = np.fft.fft(f)
Fo = F.copy() # just for printing the unfiltered spectrum
freq = np.fft.fftfreq(len(f), 1/N)
# That's the filter, all parts over the frequency of fg should be damped.
fg = 50
for i in range(0, len(f)):
F[i] *= (1 if abs(freq[i]) < fg else 0)
ff = np.fft.ifft(F)
plt.subplot(3, 1, 1)
plt.plot(t, f, label='f original')
plt.plot(t, ff, label='f filtered')
plt.axis(xmin=0, xmax=16e-3)
plt.legend()
plt.subplot(3, 1, 2)
plt.plot(freq, abs(Fo)/N, label='spec original')
plt.axis(xmin=-200, xmax=200)
plt.legend()
plt.subplot(3, 1, 3)
plt.plot(freq, abs(F)/N, label='spec filtered')
plt.axis(xmin=-200, xmax=200)
plt.legend()
plt.show()
1 个回答
1
这里有两个问题:
1) 你的 freq
轴错了,应该乘以10,因为 fftfreq
需要的是样本间隔(比如说,单位是秒),这个间隔应该是 total_time/N
(在你的例子中是 0.1/N
),而不是你现在用的 1/N
。
2) 那个看起来奇怪的图是因为从fft返回的值没有按频率从小到大排序,而返回值中的最后一个频率正好在图的中间位置,所以那条线就到此为止了。你可以试着只画点(而不是用线把点连起来),这样看起来会更合理;或者使用 fftshift
。