从旋转的i到信号频谱:用Python动画可视化欧拉公式与三大变换

张开发
2026/5/23 14:06:43 15 分钟阅读
从旋转的i到信号频谱:用Python动画可视化欧拉公式与三大变换
从旋转的i到信号频谱用Python动画可视化欧拉公式与三大变换数学公式背后的几何直觉往往比符号本身更有启发性。记得第一次看到欧拉公式e^(iπ) 1 0时那种震撼感至今难忘——看似无关的自然对数底、虚数单位、圆周率竟能如此优雅地统一。但真正理解这个数学最美公式的奥秘是在用Python让复平面上的点动起来的那一刻。本文将带你用Matplotlib和Manim库通过动画拆解三大信号变换的视觉本质。不同于教科书上的公式推导我们会用代码实现以下视觉化效果复平面上旋转的e^(ix)如何生成正弦波傅里叶变换如何通过旋转箭头提取频率成分拉普拉斯变换怎样用衰减螺旋拓展复平面Z变换的单位圆与离散信号的关系1. 动态欧拉公式旋转的数学之美打开Jupyter Notebook我们先从最基础的动画开始——让复数e^(ix)在复平面上跳起圆舞曲。运行这段代码你会看到一个红点沿单位圆匀速运动import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation fig, ax plt.subplots(figsize(6,6)) ax.set_xlim(-1.5,1.5); ax.set_ylim(-1.5,1.5) ax.grid(); ax.set_aspect(equal) circle plt.Circle((0,0), 1, fillFalse, colorblue) point, ax.plot([], [], ro) def init(): ax.add_patch(circle) return point, def update(frame): x np.cos(frame); y np.sin(frame) point.set_data([x], [y]) return point, ani FuncAnimation(fig, update, framesnp.linspace(0,2*np.pi,128), init_funcinit, blitTrue) plt.show()这个动画揭示了三个关键几何事实实部投影生成余弦波xcosθ虚部投影生成正弦波ysinθ旋转速度对应角频率ω提示尝试修改frames参数为np.linspace(0,4*np.pi,256)观察双倍转速下的波形变化当我们将多个不同频率的旋转向量叠加时就得到了傅里叶级数的几何解释。下表对比了数学表达式与对应的几何意义数学表达几何解释Python实现关键e^(iωt)角速度为ω的旋转向量np.exp(1jomegat)Re{e^(iωt)}实轴投影轨迹x np.cos(omega*t)Im{e^(iωt)}虚轴投影轨迹y np.sin(omega*t)Σaₙe^(iωₙt)多个旋转向量合成np.sum(amplitudes * np.exp(1jomegast))2. 傅里叶变换旋转箭头的频率提取术理解傅里叶变换最直观的方式是观察它对时域信号的旋转扫描过程。我们创建一个包含5Hz和20Hz成分的合成信号t np.linspace(0, 1, 1000) signal 0.5*np.sin(2*np.pi*5*t) 0.3*np.cos(2*np.pi*20*t)通过下面这个动画可以看到傅里叶变换如何通过旋转的探测箭头提取频率成分def create_ft_animation(): fig, (ax1, ax2) plt.subplots(1, 2, figsize(12,5)) # 时域信号绘制 line, ax1.plot(t, signal) probe, ax1.plot([], [], ro) # 频域结果绘制 freq np.fft.fftfreq(len(t), t[1]-t[0]) fft_vals np.fft.fft(signal) magnitude np.abs(fft_vals) ax2.stem(freq, magnitude) def update(frame): # 更新探测点位置 probe.set_data([frame], [signal[int(frame*len(t))]]) # 计算当前旋转向量 test_freq 5 # 测试频率 rotating np.exp(-2j*np.pi*test_freq*t[:int(frame*len(t))]) weighted signal[:int(frame*len(t))] * rotating integral np.sum(weighted) return probe, ani FuncAnimation(fig, update, framesnp.linspace(0,1,100), interval50, blitTrue) plt.show()这个动画展示了傅里叶变换的核心机制旋转匹配当测试频率与信号成分匹配时旋转向量会与信号同步积分放大匹配频率的积分值会持续增大共振效应频率检测最终频谱图中的峰值对应信号的实际频率成分3. 拉普拉斯变换复平面上的衰减螺旋傅里叶变换的局限在于处理增长信号时会遇到积分发散问题。拉普拉斯变换通过引入衰减因子e^(-σt)解决了这一难题。让我们用三维动画展示这个拓展过程from mpl_toolkits.mplot3d import Axes3D sigma 0.5 # 衰减系数 omega 2*np.pi*1 # 角频率 fig plt.figure(figsize(10,6)) ax fig.add_subplot(111, projection3d) t np.linspace(0, 5, 500) # 计算螺旋线坐标 x np.exp(-sigma*t) * np.cos(omega*t) y np.exp(-sigma*t) * np.sin(omega*t) z t ax.plot(x, y, z, b-, linewidth2) ax.set_xlabel(Real); ax.set_ylabel(Imag); ax.set_zlabel(Time) # 添加投影线 for i in range(0, len(t), 50): ax.plot([x[i],x[i]], [y[i],y[i]], [0,z[i]], r--, alpha0.3) ax.plot([0,x[i]], [0,y[i]], [z[i],z[i]], g--, alpha0.3) plt.tight_layout() plt.show()这个可视化说明了衰减效应螺旋线半径随时间指数衰减受σ控制频率保持旋转速度仍由ω决定复平面拓展σ-ω平面构成完整的复频域关键参数对变换的影响参数组合变换类型几何表现适用场景σ0傅里叶变换纯旋转无衰减稳态信号σ0拉普拉斯变换收缩螺旋衰减信号σ0拉普拉斯变换扩张螺旋增长信号4. Z变换离散世界的单位圆舞蹈在离散时间领域Z变换扮演着类似拉普拉斯变换的角色。其收敛域与单位圆的关系可以通过以下交互可视化理解def plot_z_transform(): # 创建零极点图 fig, ax plt.subplots(figsize(6,6)) unit_circle plt.Circle((0,0), 1, fillFalse, colorblue) ax.add_patch(unit_circle) ax.set_xlim(-1.5,1.5); ax.set_ylim(-1.5,1.5) ax.grid(True) # 示例系统零点在0.5极点在0.8∠±π/4 zeros [0.5 0j] poles [0.8*np.exp(1j*np.pi/4), 0.8*np.exp(-1j*np.pi/4)] # 绘制零极点 ax.plot(np.real(zeros), np.imag(zeros), o, markersize10, colorr) ax.plot(np.real(poles), np.imag(poles), x, markersize10, colorb) # 频率响应可视化 angles np.linspace(0, 2*np.pi, 100) resp [] for angle in angles: z np.exp(1j*angle) num np.prod([(z - zero) for zero in zeros]) den np.prod([(z - pole) for pole in poles]) resp.append(np.abs(num/den)) ax_r ax.twinx() ax_r.plot(np.cos(angles), np.sin(angles), g-, alpha0.3) ax_r.plot(np.cos(angles), resp, m-, linewidth2) plt.show()这个可视化揭示了Z变换的三大要点单位圆意义对应离散时间傅里叶变换DTFT零极点影响极点靠近单位圆时会产生共振峰稳定性条件所有极点必须在单位圆内离散变换对比表变换类型变量替换可视化特征典型应用DTFTz e^(jω)单位圆上的取值频谱分析Z变换z re^(jω)整个复平面系统分析DFTz_k e^(j2πk/N)单位圆上等距采样数字计算5. 综合应用音频频谱分析实战让我们将这些变换应用于实际音频处理。以下代码演示如何分析录音信号的时频特性import scipy.io.wavfile as wav # 读取音频文件 sample_rate, data wav.read(audio_sample.wav) duration len(data)/sample_rate time np.arange(0, duration, 1/sample_rate) # 绘制时域波形 plt.figure(figsize(12,4)) plt.subplot(121) plt.plot(time, data) plt.title(Time Domain) # 计算并绘制频谱 plt.subplot(122) n len(data) freq np.fft.rfftfreq(n, d1/sample_rate) fft np.abs(np.fft.rfft(data)) plt.plot(freq, fft) plt.xlim(0, 5000) # 聚焦可听范围 plt.title(Frequency Domain) plt.tight_layout()进阶分析时可以结合短时傅里叶变换STFT观察频谱随时间变化from scipy.signal import spectrogram f, t, Sxx spectrogram(data, fssample_rate, nperseg1024) plt.pcolormesh(t, f, 10*np.log10(Sxx), shadinggouraud) plt.ylabel(Frequency [Hz]); plt.xlabel(Time [sec]) plt.colorbar(labelIntensity [dB])在完成这些可视化后有几个实用技巧值得分享使用%matplotlib notebook获得交互式图形Manim库适合制作高质量教学动画但学习曲线较陡对于复杂动画考虑使用Blender的Python API实时音频处理可尝试PyAudio库

更多文章