Python信号处理实战:5分钟搞定FFT频谱分析(附完整代码) Python信号处理实战5分钟搞定FFT频谱分析附完整代码在工程和科研领域快速准确地分析信号频谱是常见需求。传统工具如MATLAB虽然强大但Python凭借其开源生态和简洁语法正成为越来越多工程师的首选。本文将带你用Python的SciPy库在5分钟内完成从信号生成到频谱分析的全流程特别针对从MATLAB转向Python的开发者解决实际应用中的幅值计算和频谱显示问题。1. 环境准备与基础概念FFT快速傅里叶变换是信号处理的基石它能将时域信号转换为频域表示。Python中实现FFT主要依赖两个库import numpy as np # 数值计算核心库 from scipy.fftpack import fft, fftshift # FFT计算工具 import matplotlib.pyplot as plt # 绘图库采样定理是信号处理的基本准则采样频率必须至少是信号最高频率的两倍。例如要分析40Hz的信号采样频率至少需要80Hz。实际应用中通常会选择更高的采样率如120Hz以提高精度。常见参数说明N1024采样点数影响频率分辨率sample_freq120采样频率(Hz)signal_len信号总时长(秒)2. 信号生成与FFT计算我们先构造一个包含多个频率成分的测试信号# 生成时域信号含直流分量和三个正弦波 t np.arange(0, N*sample_interval, sample_interval) signal 5 2*np.sin(2*np.pi*20*t) 3*np.sin(2*np.pi*30*t) 4*np.sin(2*np.pi*40*t)执行FFT计算只需一行代码但幅值处理需要特别注意fft_data fft(signal) # 执行FFT变换 # 幅值校正关键步骤 fft_amp0 np.abs(fft_data)/N * 2 # 双边谱幅值 fft_amp0[0] * 0.5 # 直流分量特殊处理 fft_amp1 fft_amp0[:N//2] # 单边谱幅值校正原理非直流分量幅值需要乘以2/N直流分量(0Hz)只需除以N单边谱取前半部分频谱奈奎斯特频率以下3. 频谱可视化技巧完整的频谱分析需要四种视图对比plt.figure(figsize(12,8)) # 原信号时域图 plt.subplot(221) plt.plot(t, signal) plt.title(Original Signal) plt.xlabel(Time (s)) # 双边谱 plt.subplot(222) plt.plot(freq0, fft_amp0) plt.title(Two-sided Spectrum) plt.ylim(0, 6) # 单边谱 plt.subplot(223) plt.plot(freq1, fft_amp1) plt.title(Single-sided Spectrum) plt.ylim(0, 6) # 零频居中谱 plt.subplot(224) plt.plot(freq0_shift, fftshift(fft_amp0)) plt.title(Centered Spectrum) plt.ylim(0, 6) plt.tight_layout() plt.show()视图对比说明视图类型特点适用场景双边谱显示正负频率理论分析单边谱仅显示正频率工程应用零频居中零频在中间特殊分析4. 实战问题解决方案频谱泄露是常见问题当信号长度不是信号周期的整数倍时会发生。我们的示例中30Hz分量信号长度(1024/120≈8.53s)正好是其周期(1/30≈0.033s)的整数倍 → 幅值准确20Hz和40Hz分量非整数倍关系 → 频谱泄露峰变宽解决方案增加采样点数N提高频率分辨率使用窗函数如汉宁窗减少泄露window np.hanning(N) # 生成汉宁窗 fft_data fft(signal * window) # 加窗后FFT频率轴计算是另一个易错点# 双边谱频率轴 freq0 sample_freq * np.arange(N) / N # 单边谱频率轴 freq1 sample_freq * np.arange(N//2) / N # 零频居中频率轴 freq0_shift sample_freq * (np.arange(N) - N/2) / N5. 完整代码优化版以下是整合所有技巧的完整实现def analyze_spectrum(signal, sample_freq): N len(signal) sample_interval 1/sample_freq # 加窗处理 window np.hanning(N) fft_data fft(signal * window) # 幅值校正 fft_amp 2 * np.abs(fft_data) / np.sum(window) fft_amp[0] * 0.5 # 频率轴计算 freq sample_freq * np.arange(N//2) / N # 绘图 plt.figure() plt.plot(freq, fft_amp[:N//2]) plt.xlabel(Frequency (Hz)) plt.ylabel(Amplitude) plt.grid() return fft_amp, freq这个优化版本自动处理窗函数补偿返回幅值和频率数组供进一步分析简化了可视化流程实际项目中我会将采样参数设置为全局变量方便不同信号对比分析。对于实时处理系统可以考虑使用重叠分段FFT来提高时间分辨率。