为何Python中仅对傅里叶变换取绝对值才能正常绘图?
为什么直接绘制np.fft.fft结果会异常,取绝对值后恢复正常?
核心原因
np.fft.fft()返回的是复数数组,而matplotlib的plot()函数直接绘制复数时只会取实部,导致图形混乱;取绝对值(复数的模)后,我们得到的是各频率分量的振幅强度,这才是频域分析中需要观察的有效信息。
详细拆解
- 傅里叶变换的复数本质
傅里叶变换的作用是把时域信号分解成不同频率的正弦/余弦分量,每个分量用复数来描述:
- 复数的**模(绝对值)**对应该频率分量的振幅大小
- 复数的辐角对应该频率分量的相位
对于你使用的正弦信号sin(2π*50t),它的傅里叶变换会在+50Hz和-50Hz处各出现一个共轭复数峰(实部相同,虚部相反)。
直接绘制复数的问题
当你执行plt.plot(xf02, yf02)时,matplotlib默认只提取复数的实部进行绘制。由于±50Hz处的复数实部相同、虚部相反,直接画实部会导致正负频率的信号相互干扰,再加上计算过程中的微小数值误差,最终呈现出杂乱无章的异常图形。取绝对值的意义
abs(yf02)计算的是复数的模,也就是对应频率分量的振幅强度。对于你的正弦信号,±50Hz处的模是相等的,所以绘制后会看到两个对称的尖锐峰,这正是正弦信号频域的典型特征(正常结果)。
额外补充
- 如果需要观察相位信息,可以用
np.angle(yf02)绘制相位谱 - 针对实值信号,也可以用
np.fft.rfft()直接计算正频率部分的傅里叶变换,结果更简洁,无需处理负频率的共轭对称部分
你的测试代码
异常版本(直接绘制复数)
import numpy as np import matplotlib.pyplot as plt # x轴 x02 = np.arange(0, 1, 0.001) # start, stop, step y02 = np.sin(50.0 * 2.0 * np.pi * x02) # 绘制时域正弦信号 plt.figure() plt.plot(x02, y02, color ='b') plt.grid() plt.title('Sinus in time domain') plt.show() # 傅里叶变换 yf02 = np.fft.fft(y02) xf02 = np.fft.fftfreq(len(y02), 0.001) # 绘制频域结果(直接用复数) plt.figure() plt.plot(xf02, yf02, color ='b') plt.grid() plt.title('Sinus in frequency domain') plt.show()
正常版本(取绝对值)
import numpy as np import matplotlib.pyplot as plt # x轴 x02 = np.arange(0, 1, 0.001) # start, stop, step y02 = np.sin(50.0 * 2.0 * np.pi * x02) # 绘制时域正弦信号 plt.figure() plt.plot(x02, y02, color ='b') plt.grid() plt.title('Sinus in time domain') plt.show() # 傅里叶变换 yf02 = np.fft.fft(y02) xf02 = np.fft.fftfreq(len(y02), 0.001) # 绘制频域结果(取绝对值) plt.figure() plt.plot(xf02, abs(yf02), color ='b') plt.grid() plt.title('Sinus in frequency domain') plt.show()
内容的提问来源于stack exchange,提问作者Apinorr
相关产品推荐
相关产品推荐

