You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用scipy.fftpack计算FFT绘图出现恒定线的原因与解决方法

解决FFT绘图中出现水平线和垂直线的问题

我来帮你拆解这个FFT绘图的问题,你遇到的水平线和垂直线其实都是FFT处理和绘图时的常见小坑,咱们用你说的12Hz正弦波例子一步步说清楚:

一、为什么会出现这些线条?

1. 垂直线的原因

scipy的fftfreq函数返回的频率数组排序很特殊:前半段是正频率(从0到采样频率的一半,也就是奈奎斯特频率),后半段突然跳转到负频率(从接近-奈奎斯特频率到-最小频率间隔)。如果你直接用plt.plot()连接所有频率点,最后一个正频率点和第一个负频率点之间会因为频率值的巨大突变,画出一条横跨整个x轴的垂直线。

2. 水平线的原因

你看到的恒定水平线,大概率是这几个原因之一:

  • 没有计算FFT的幅值:FFT返回的是复数结果,如果你直接绘制实部或虚部,正弦波的FFT在非峰值频率处的实部/虚部接近0,看起来就像一条水平线;
  • 频谱泄漏:如果采样时长不是信号周期的整数倍,非峰值频率处会出现小的幅值,视觉上像一条低幅值的水平线;
  • 未归一化:FFT的幅值默认是原始信号幅值的N/2倍(N是采样点数),如果没归一化,可能会让轴范围被峰值拉得很大,导致接近0的点看起来像一条水平线。

二、解决方案:画出干净的频谱

咱们用完整的代码示例来实现无干扰的FFT频谱图:

1. 生成标准测试信号

先创建一个符合奈奎斯特准则的12Hz正弦波:

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

# 信号参数
f_signal = 12  # 目标信号频率12Hz
fs = 100       # 采样频率100Hz(满足奈奎斯特:fs > 2*f_signal)
duration = 1   # 采样时长1秒
n_samples = fs * duration  # 总采样点数

# 生成时间轴和正弦波
t = np.linspace(0, duration, n_samples, endpoint=False)
signal = np.sin(2 * np.pi * f_signal * t)

2. 正确计算FFT幅值并归一化

FFT的复数结果需要取绝对值得到幅值,同时归一化到原始信号的幅值范围:

# 计算FFT
fft_vals = scipy.fftpack.fft(signal)
# 计算归一化后的幅值(除以采样点数的一半,还原原始信号幅值)
fft_amp = np.abs(fft_vals) / (n_samples / 2)
# 获取频率轴
freqs = scipy.fftpack.fftfreq(n_samples, 1/fs)

3. 只保留正频率部分

为了避免频率突变导致的垂直线,我们只筛选正频率(包括0频率)的部分:

# 筛选正频率的索引
positive_freq_idx = freqs >= 0
freqs_pos = freqs[positive_freq_idx]
fft_amp_pos = fft_amp[positive_freq_idx]

4. 绘制干净的频谱图

用stem图(适合离散频谱)或者plot图绘制,就能得到没有多余线条的结果:

plt.figure(figsize=(10, 6))
# stem图更清晰展示离散频谱的峰值
plt.stem(freqs_pos, fft_amp_pos, basefmt=" ", use_line_collection=True)
plt.xlabel("Frequency (Hz)")
plt.ylabel("Amplitude")
plt.title("FFT Spectrum of 12Hz Sine Wave")
plt.xlim(0, fs/2)  # 限制x轴到奈奎斯特频率
plt.grid(True)
plt.show()

这样画出来的图,只会在12Hz处有一个清晰的峰值,不会出现之前的水平线和垂直线啦。

内容的提问来源于stack exchange,提问作者lrsppp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:40:09