numpy.fft 频率和幅度错误,光谱绘制奇怪

1 投票
1 回答
2666 浏览
提问于 2025-04-17 23:18

为了理解ffts的用法,我在python中实现了一个离散信号的低通滤波器。

经过滤波后得到的信号基本上是我想要的,但不幸的是,频谱的结果并不是我预期的。乍一看它们似乎还不错,但如你所见,幅度和频率都不正确。

我期望的频率应该是0Hz、220Hz和660Hz,幅度分别是3、2和1;但实际结果如下面的图所示。请注意,图中的幅度不正确,因为我在绘图命令中写了abs(F)/N,而不是2*abs(F)/N。但当我这样做时,直流值变成了6,我觉得这也是不对的。

enter image description here

而且频谱的绘制对我来说也有点奇怪,请看一下这个:

enter image description here

我不知道自己哪里做错了,非常希望能得到一些帮助。

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

撰写回答