np.fft.fft()输出复数是因为傅里叶变换将实信号分解为复指数函数组合,复系数的模为幅值、辐角为相位;频率对应k*fs/N,需用fftfreq生成坐标并fftshift调整顺序,幅值需除以N归一化。

np.fft.fft() 输出结果为什么是复数?怎么看频率和幅值
因为傅里叶变换本质就是把实信号分解成一系列复指数函数的线性组合,np.fft.fft() 返回的就是这些复系数——实部对应余弦分量,虚部对应正弦分量。你不能直接画 fft_result,得取模:np.abs(fft_result) 才是各频率点的幅值大小。
注意:输出数组索引 k 对应的物理频率是 k * fs / N(fs 是采样率,N 是点数),但默认顺序是“直流分量→正频率→负频率”(即 fftshift 前的排列)。想让频率轴从负到正对称,必须用 np.fft.fftshift() 配合 np.fft.fftfreq()。
- 不做
fftshift就直接画图,中间突起的峰值看起来像在高频,其实是直流或低频成分被挤到了开头 -
fftfreq(N, 1/fs)才给出正确频率坐标,别手算np.arange(N) * fs / N——它没处理负频部分 - 幅值要除以
N才接近真实幅度(能量守恒),尤其做定量分析时不能漏
输入长度不是 2 的幂,np.fft.fft() 还准不准
准,完全准。NumPy 的 fft 底层用的是 FFTW 或自研混合算法,支持任意长度,不强制要求 2 的幂。只是当长度含小质因子(如 2、3、5)时更快;纯大质数(比如 1009)会回落到 O(N²) 的 DFT,明显变慢。
- 日常信号长度选 1000、2048、4000 都没问题,别为“凑 2 的幂”截断或补零——除非你明确需要分辨率或对齐
- 补零(
np.pad(signal, (0, 1000)))只提高频域采样密度(插值效果),不提升真实频率分辨率;真要分辨两个靠得很近的频率,得加长原始采集时间(增加N) - 如果信号本身很短又必须快,可考虑
scipy.fft.next_fast_len()找最近的高效长度,再补零计算
实信号用 np.fft.fft() 还是 np.fft.rfft()
优先用 np.fft.rfft()。它专为实输入优化:输出长度约 N//2+1,自动剔除冗余负频部分,省内存、少一半计算量,且返回的是“真正可用”的正频率复数数组。
-
rfft输出不含负频,对应频率用np.fft.rfftfreq(N, 1/fs),别混用fftfreq - 想从
rfft结果还原实信号,必须用np.fft.irfft(),用ifft()会出错(维度不匹配) - 如果你后续要画单边谱、算功率谱密度(PSD),
rfft+rfftfreq是最自然的组合,不用手动切片或fftshift
为什么频谱图里 50Hz 工频干扰特别尖,但自己生成的正弦波反而不尖
因为真实采集的信号含噪声、非理想截断、直流偏移,导致频谱泄漏;而你用 np.sin(2*np.pi*50*t) 生成的完美周期信号,若采样点数刚好整除周期,就落在 FFT 的频点上,能量集中——但这在现实中几乎不会发生。
- 加窗(如
np.hanning(len(signal)))能压低旁瓣,减少泄漏,但会轻微展宽主瓣;常用汉宁窗,别用矩形窗(默认) - 确保信号均值为 0,否则直流分量巨大,掩盖其他特征;预处理先减去
np.mean(signal) - 采样率
fs和记录时长T共同决定频率分辨率1/T;哪怕fs很高,若只录了 0.1 秒,50Hz 和 51Hz 在频谱上也分不开
实际中,频谱“尖”不尖,往往比公式更早暴露数据质量或参数设置问题。









