Numpy系列(八):实战解析FFT在信号处理中的核心应用
📅 2026/7/15 2:05:05
👁️ 阅读次数
📝 编程学习
1. 从声音到频谱:FFT如何揭开信号的神秘面纱
假设你正在用麦克风录制一段吉他弹奏。麦克风捕捉到的声音波形看起来就像一团杂乱无章的上下波动曲线——这就是典型的时域信号。但人类的耳朵真正感知的却是不同音高的组合,这时候就需要傅里叶变换来解密了。
Numpy的fft.fft()函数就像个神奇的翻译官,它能将时域信号转换为频域表示。我曾在处理一段混杂着50Hz电路噪声的音频时,通过下面这段代码快速定位到了问题频率:
import numpy as np import matplotlib.pyplot as plt # 模拟含噪声的音频信号(440Hz正弦波+50Hz噪声) sample_rate = 44100 # 采样率 duration = 1.0 # 持续时间 t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False) signal = 0.5 * np.sin(2 * np.pi * 440 * t) + 0.2 * np.sin(2 * np.pi * 50 * t) # 执行FFT fft_result = np.fft.fft(signal) frequencies = np.fft.fftfreq(len(fft_result), 1/sample_rate) # 绘制频谱图 plt.plot(frequencies[:len(frequencies)//2], np.abs(fft_result[:len(fft_result)//2])) plt.xlabel('频率 (Hz)') plt.ylabel('振幅') plt.show()运行后会看到两个明显的峰:一个在440Hz(我们的主音),另一个在50Hz(讨厌的噪声)。这种可视化正是信号处理工程师的"X光机",能一眼看穿信号的内部结构。
2. 实战音频降噪:从理论到代码的完整流程
去年我参与了一个语音助手的项目,需要滤除环境中的风扇噪声。下面这个真实案例展示了如何用Numpy实现频域滤波:
- 采集样本:先录制一段纯噪声(只有风扇声)
- 分析噪声特征:通过FFT找到噪声的基频和谐波
- 设计滤波器:在频域将这些频率成分清零
def remove_noise(audio, sample_rate, noise_freqs): """ 频域降噪函数 :param audio: 原始音频信号 :param sample_rate: 采样率 :param noise_freqs: 需要滤除的频率列表(Hz) """ fft_data = np.fft.fft(audio) freqs = np.fft.fftfreq(len(fft_data), 1/sample_rate) # 创建滤波器掩码 mask = np.ones(len(fft_data), dtype=bool) for freq in noise_freqs: # 找到目标频率附近的索引 idx = np.where(np.abs(freqs - freq) < 5)[0] # ±5Hz范围 mask[idx] = False # 应用滤波器 filtered_fft = fft_data * mask return np.fft.ifft(filtered_fft).real # 使用示例 noisy_audio = np.load('noisy_recording.npy') # 加载含噪声音频 clean_audio = remove_noise(noisy_audio, 44100, [50, 100, 150]) # 滤除50Hz及其谐波重要提示:实际项目中我们会用更精细的带阻滤波器而非简单置零,这里为演示做了简化。保存处理前后的频谱对比图,能直观展示滤波效果。
3. 机械振动分析:FFT在工业检测中的高阶应用
在汽轮机振动监测项目中,我们通过加速度传感器采集振动信号。健康的设备频谱会有特定的特征峰,而当轴承磨损时,会在特定频率出现新的谐波。
这个案例展示了如何用fft.rfft()(专为实数信号优化的FFT)进行分析:
def analyze_vibration(signal, sample_rate, rpm): """ 旋转机械振动分析 :param signal: 振动传感器信号 :param sample_rate: 采样率(Hz) :param rpm: 设备转速(转/分钟) """ # 计算转频及其谐波 base_freq = rpm / 60 # 转/分钟 → Hz harmonics = [base_freq * i for i in [1, 2, 3, 4]] # 分析前4阶谐波 # 执行实数FFT(更高效) fft_data = np.fft.rfft(signal) freqs = np.fft.rfftfreq(len(signal), 1/sample_rate) # 提取关键频率成分 results = {} for h in harmonics: idx = np.argmin(np.abs(freqs - h)) results[f'{h:.1f}Hz'] = np.abs(fft_data[idx]) / len(signal) * 2 # 计算真实振幅 return results # 示例:检测到异常的三倍频振动 vibration_data = np.load('bearing_signal.npy') analysis = analyze_vibration(vibration_data, 5000, 1800) # 1800rpm设备 print(analysis) # 输出:{'30.0Hz': 0.12, '60.0Hz': 0.05, '90.0Hz': 0.23, '120.0Hz': 0.02}当三倍频(90Hz)振幅显著增加时,往往提示轴承存在不对中故障。这种分析方法已成功应用于风电设备的预测性维护。
4. 图像频域处理:FFT2在视觉增强中的妙用
没想到吧?FFT还能处理图像!我最近用fft2()给博物馆修复了一批老照片。二维FFT将图像分解为不同方向的条纹模式,低频对应大块颜色区域,高频则包含边缘细节。
这个例子展示如何增强图像锐度:
def sharpen_image(image, factor=2.0): """ 频域图像锐化 :param image: 输入图像(灰度) :param factor: 锐化强度 """ # 二维FFT fft_img = np.fft.fft2(image) fft_shifted = np.fft.fftshift(fft_img) # 低频移到中心 # 创建高通滤波器 rows, cols = image.shape crow, ccol = rows//2, cols//2 mask = np.ones((rows, cols)) radius = 30 mask[crow-radius:crow+radius, ccol-radius:ccol+radius] = 0 # 增强高频成分 filtered = fft_shifted * (1 + mask * factor) # 逆变换 fft_ishift = np.fft.ifftshift(filtered) img_back = np.fft.ifft2(fft_ishift) return np.abs(img_back) # 使用示例 from skimage import data, io moon = data.moon() # 加载示例图像 sharp_moon = sharpen_image(moon, 1.5) io.imshow(np.hstack([moon, sharp_moon]))处理前后的对比会显示右侧图像的地表细节更加清晰。同样的原理还可用于去除周期性噪声(如扫描文档的网纹),只需在频域抹除对应的频率点即可。
编程学习
技术分享
实战经验