numpy.fft.fft 默认对输入一维数组沿最后一轴(axis=-1)计算离散傅里叶变换(dft),返回等长复数数组,零频分量位于索引0处,不归一化、不补零、不预处理。

fft 函数默认做的是什么变换?
numpy.fft.fft 对输入的一维数组做离散傅里叶变换(DFT),返回复数数组,长度与输入相同。它不自动归一化,也不对输入做任何预处理(比如去均值、加窗),输出的零频分量(DC)在索引 0 处,正频率从 1 到 n//2,负频率从 n//2+1 开始(对偶索引)。如果你直接画出 abs(fft(x)),会看到镜像对称——这是实信号 DFT 的共轭对称性导致的,不是 bug。
- 实信号的 FFT 结果满足
fft[k] == conj(fft[n-k])(模长对称,相位相反) - 如果你只关心幅度谱,通常取前半部分(含 DC 和 Nyquist 点)就够了:
np.abs(fft_result[:len(fft_result)//2 + 1]) - 不要误以为
fft默认返回“物理频率轴”——它只返回系数,频率坐标得自己算:freqs = np.fft.fftfreq(n, d=dt)
为什么 fftshift 后图形才看起来“正常”?
numpy.fft.fft 输出的顺序是 [0, 1, 2, ..., n/2, -n/2+1, ..., -1](对偶排列),而人眼习惯把零频放在中间。所以直接绘图时,正负频率被劈开在两端,看着别扭。
- 调用
np.fft.fftshift可以把负频率块移到左边、正频率移到右边,零频居中 - 它只是重排数组顺序,不改变数值本身,也不影响逆变换
- 注意:必须对频率轴和 FFT 结果同时用
fftshift,否则横纵坐标对不上freqs = np.fft.fftfreq(n, dt) X = np.fft.fft(x) freqs_shifted = np.fft.fftshift(freqs) X_shifted = np.fft.fftshift(X)
- 如果你后续要用
ifft,记得先ifftshift回去(ifftshift和fftshift对偶长数组效果一样,但对奇数长度更安全)
real vs complex 输入对 fft 结果有什么影响?
NumPy 的 fft 自动适配输入类型:实数输入返回复数结果,复数输入也返回复数结果,但内存和计算路径略有差异。
- 实数输入会触发底层优化(如用 RFFT),速度略快,且结果具备共轭对称性
- 但如果你手动传入
np.complex64或np.complex128,它就走通用复数路径,不启用实数优化 - 更关键的是:若原始信号本是实数,但你无意中加了极小虚部(比如
x + 1e-15j),就会失去对称性,幅度谱不再镜像,还可能引入数值噪声 - 检查方式很简单:
np.allclose(X[1:n//2+1], np.conj(X[-1:-n//2-1:-1]))—— 若为 False,说明输入被污染或用了非实数 dtype
采样率和点数没设对,fft 频率分辨率就全错了
FFT 本身不“知道”你的采样率;fftfreq 里的 dt(采样间隔)和 n(点数)共同决定频率分辨率 df = 1/(n*dt) 和最大可观测频率 fs/2。
- 常见错误:用
fs = 1000Hz 采样,但传给fftfreq的dt = 1/fs写成1000或0.001漏掉单位换算 - 点数
n必须是实际参与 FFT 的长度,不是原始信号长度。如果做了截断或补零,n就得用补零后的新长度 - 补零(zero-padding)不会提高真实分辨率(那是由采样时长决定的),但会让频谱看起来更“平滑”,便于观察峰值位置
- 真实分辨率只取决于总采样时间
T = n * dt,即df = 1/T。想提高分辨率,只能延长采集时间,不能靠多补零
FFT 的核心是快速算法,但真正用准它,得盯住采样参数、数据类型、频谱排列这三处。最容易漏的是 dt 单位错和忘记 fftshift 配对,一画图就发现频谱“歪了”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











