别再死记硬背公式了!用Python+NumPy手把手带你‘画’出傅里叶变换(附代码)

张开发
2026/4/17 5:54:14 15 分钟阅读

分享文章

别再死记硬背公式了!用Python+NumPy手把手带你‘画’出傅里叶变换(附代码)
用PythonNumPy‘画’出傅里叶变换从视觉直觉理解信号分解的艺术当你第一次听说任何复杂波形都能分解成正弦波叠加时是否觉得这像魔法我在初学信号处理时盯着那堆积分公式看了三天依然云里雾里直到用Python画出第一个方波的傅里叶级数逼近才真正理解这个变换的奥妙。本文将带你用代码搭建一座从数学公式到视觉理解的桥梁——不需要死记硬背只需跟着动手实现你就能在屏幕上亲眼见证信号分解的魔法。1. 准备工作搭建Python信号实验室1.1 核心工具包配置确保你的Python环境已安装以下科学计算三件套pip install numpy matplotlib scipy1.2 基础波形生成器我们先创建几个常用波形生成函数后续将用它们作为原材料import numpy as np import matplotlib.pyplot as plt def sine_wave(freq, duration1, sample_rate44100): 生成正弦波 t np.linspace(0, duration, int(sample_rate * duration)) return np.sin(2 * np.pi * freq * t) def square_wave(freq, duration1, harmonics10): 合成方波通过傅里叶级数 t np.linspace(0, duration, 44100) signal np.zeros_like(t) for n in range(1, harmonics*2, 2): # 只取奇次谐波 signal (4/np.pi) * (1/n) * np.sin(2 * np.pi * n * freq * t) return signal提示方波的傅里叶级数展开只包含基频奇数倍的谐波振幅随谐波次数递减——这个特性我们稍后会在可视化中清晰看到。2. 解构方波眼见为实的谐波叠加2.1 单谐波演示让我们从最简单的基波开始逐步增加谐波观察波形变化# 生成1kHz基波和三次谐波 fundamental sine_wave(1000, duration0.01) harmonic3 (4/np.pi)*(1/3)*sine_wave(3000, duration0.01) plt.figure(figsize(10,6)) plt.plot(fundamental[:400], label基波 (1kHz)) plt.plot((fundamental harmonic3)[:400], label基波三次谐波) plt.legend(); plt.title(方波构建过程); plt.show()运行这段代码你会看到蓝色曲线是纯净的1kHz正弦波橙色曲线已经开始呈现方波的平顶特征2.2 动态谐波叠加实验更直观的方式是制作动画展示谐波累积效果以下代码需要Jupyter Notebook环境from IPython.display import HTML from matplotlib.animation import FuncAnimation fig, ax plt.subplots(figsize(10,6)) line, ax.plot([], [], lw2) ax.set_xlim(0, 400); ax.set_ylim(-1.5, 1.5) def init(): line.set_data([], []) return (line,) def animate(n): t np.linspace(0, 0.01, 44100) y np.zeros_like(t) for i in range(1, 2*n1, 2): y (4/np.pi) * (1/i) * np.sin(2*np.pi*i*1000*t) line.set_data(range(400), y[:400]) ax.set_title(f前{n}个奇次谐波叠加) return (line,) anim FuncAnimation(fig, animate, frames10, init_funcinit, interval800) HTML(anim.to_jshtml())你会观察到随着谐波数量增加波形如何逐步逼近理想方波。这个实验揭示了两个关键认知高频成分决定细节高阶谐波主要影响波形的陡峭边沿吉布斯现象即使在无限谐波情况下跳变处仍存在约9%的过冲3. 频率域视角NumPy实现FFT分析3.1 快速傅里叶变换实践NumPy的fft模块让我们能轻松分析信号频谱def plot_spectrum(signal, sample_rate44100): n len(signal) yf np.fft.fft(signal)[:n//2] xf np.fft.fftfreq(n, 1/sample_rate)[:n//2] plt.figure(figsize(10,4)) plt.plot(xf, 2/n * np.abs(yf)) plt.xlabel(Frequency (Hz)); plt.ylabel(Amplitude) plt.grid() # 分析1kHz方波 square square_wave(1000, harmonics15) plot_spectrum(square)3.2 频谱解读技巧运行上述代码后注意观察频谱图中的几个特征谱线只出现在1kHz、3kHz、5kHz等奇次频率位置振幅遵循1/n的衰减规律频谱泄露现象可通过加窗函数改善下表对比了理想方波与实际计算的频谱特性特性理想方波15次谐波近似谐波次数无限有限边沿陡度瞬时有限斜率频谱泄露无明显计算复杂度不可计算O(n)4. 实战应用音频滤波与信号处理4.1 简易低通滤波器实现理解频谱后我们可以设计滤波器来改变信号特征def low_pass_filter(signal, cutoff, sample_rate): 时域卷积实现理想低通滤波 n len(signal) freq np.fft.fftfreq(n, 1/sample_rate) fft_signal np.fft.fft(signal) fft_signal[np.abs(freq) cutoff] 0 return np.fft.ifft(fft_signal).real # 应用5kHz低通滤波 filtered low_pass_filter(square_wave(1000), 5000, 44100) plt.plot(filtered[:1000]); plt.title(5kHz低通滤波后的方波)观察滤波后的波形你会发现高频谐波被抑制后波形边沿变得圆滑信号开始类似正弦波因为只剩下基频和少量低频谐波4.2 音乐和弦分析案例傅里叶变换在音频分析中尤为强大。试试分析钢琴和弦from scipy.io import wavfile # 生成C大三和弦 (C4-E4-G4) chord (sine_wave(261.63) sine_wave(329.63) sine_wave(392.00)) * 0.3 plot_spectrum(chord)频谱图中清晰可见三个主峰对应和弦的组成音高这种分析能力正是现代音频识别软件的基础。5. 进阶探索从理解到创新当你掌握了这些基础工具后可以尝试更有挑战性的实验合成复杂波形如模拟乐器音色实现实时频谱可视化构建简单的音频压缩算法研究短时傅里叶变换(STFT)用于时频分析我在一个音乐可视化项目中曾用傅里叶变换实现了这样的效果当播放贝多芬交响乐时程序能实时分离不同乐器组的频率范围并驱动LED灯阵显示对应的频谱图案——这正是傅里叶变换魔力的最佳展示。

更多文章