信号系统课没讲透的零极点:用Python+Matplotlib手把手教你画图分析滤波器(附代码)
信号系统课没讲透的零极点用PythonMatplotlib手把手教你画图分析滤波器附代码第一次接触零极点分析时你是否也被那些抽象的复平面坐标和传递函数搞得晕头转向作为电子工程系的学生我曾经花了整整两周时间才搞明白极点在右半平面为什么会导致系统不稳定。直到某天深夜当我用Python画出第一个巴特沃斯滤波器的零极点图时那些枯燥的理论突然变得鲜活起来——原来极点的位置真的决定了滤波器的类型本文将带你用代码重现这个顿悟时刻。不同于教科书上的理论推导我们会直接从实践入手通过Python的SciPy和Matplotlib库从编写传递函数开始一步步计算并绘制零极点图再关联到幅频/相频特性曲线。你将会看到当我们在复平面上拖动零极点位置时滤波器的特性如何实时变化。这种可视化的学习方式比死记硬背极点在左是低通要直观得多。1. 环境准备与基础概念在开始编程之前我们需要先搭建好Python环境。推荐使用Anaconda发行版它已经集成了我们所需的大部分科学计算库。打开终端或Anaconda Prompt执行以下命令安装必要的库conda install numpy scipy matplotlib零极点分析的核心是传递函数通常表示为H(s)或H(z)。对于连续时间系统传递函数是有理分式$$ H(s) \frac{N(s)}{D(s)} \frac{b_ms^m ... b_1s b_0}{a_ns^n ... a_1s a_0} $$其中零点使N(s)0的s值分子根极点使D(s)0的s值分母根离散时间系统中我们用z变换代替拉普拉斯变换但概念类似。理解这两个定义后我们就能用Python找出任意传递函数的零极点。提示在信号处理中极点的实部决定了系统的稳定性。所有极点实部为负左半平面时系统稳定这与电路理论中极点频率的概念密切相关。2. 构建传递函数与计算零极点让我们从一个简单的二阶低通滤波器开始。SciPy的signal模块提供了创建常用滤波器和分析零极点的工具。以下代码展示了如何构建巴特沃斯滤波器并提取其零极点import numpy as np import scipy.signal as signal import matplotlib.pyplot as plt # 设计一个二阶巴特沃斯低通滤波器 b, a signal.butter(2, 0.1, lowpass) # 计算零极点 zeros signal.tf2zpk(b, a)[0] poles signal.tf2zpk(b, a)[1] print(零点位置:, zeros) print(极点位置:, poles)运行后会输出类似这样的结果零点位置: [-1.0.j -1.0.j] 极点位置: [0.84080.1735j 0.8408-0.1735j]这个输出告诉我们有两个零点都在z-1处离散系统两个共轭极点位于单位圆内这是低通滤波器的特征滤波器类型与零极点位置的对应关系滤波器类型极点位置特征零点位置特征低通集中在低频区域通常在高频区域高通集中在高频区域通常在低频区域带通在通带中心频率附近通常在低频和高频区域带阻在阻带两侧在阻带中心频率附近3. 绘制零极点图与频率响应理解了零极点的计算后我们可以用Matplotlib将它们可视化。零极点图能直观展示系统的稳定性与滤波特性def plot_pzmap(zeros, poles): plt.figure(figsize(8, 6)) # 绘制单位圆 theta np.linspace(0, 2*np.pi, 100) plt.plot(np.cos(theta), np.sin(theta), k--, alpha0.5) # 绘制零极点 plt.scatter(np.real(zeros), np.imag(zeros), markero, facecolorsnone, edgecolorsb, s100) plt.scatter(np.real(poles), np.imag(poles), markerx, colorr, s100) plt.axhline(0, colork, linestyle--, alpha0.5) plt.axvline(0, colork, linestyle--, alpha0.5) plt.grid() plt.xlabel(Real) plt.ylabel(Imaginary) plt.title(Pole-Zero Plot) plt.axis(equal) plt.show() plot_pzmap(zeros, poles)这段代码会生成一个标准的零极点图其中蓝色圆圈表示零点红色叉号表示极点黑色虚线圆表示单位圆离散系统或虚轴连续系统为了更全面地理解滤波器特性我们还需要绘制频率响应曲线def plot_freq_response(b, a): w, h signal.freqz(b, a) plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(w, 20 * np.log10(abs(h))) plt.title(Magnitude Response) plt.ylabel(Amplitude [dB]) plt.xlabel(Frequency [rad/sample]) plt.grid() plt.subplot(1, 2, 2) plt.plot(w, np.angle(h)) plt.title(Phase Response) plt.ylabel(Phase [rad]) plt.xlabel(Frequency [rad/sample]) plt.grid() plt.tight_layout() plt.show() plot_freq_response(b, a)通过对比零极点图和频率响应你会发现极点靠近单位圆的区域对应频率响应的峰值零点靠近单位圆的区域对应频率响应的谷值极点的角度决定了峰值出现的频率位置4. 交互式零极点调整实验理论学习固然重要但没有什么比自己动手尝试更能加深理解。下面这段代码创建了一个交互式界面让你可以实时拖动零极点位置观察滤波器特性的变化from ipywidgets import interact, FloatSlider def interactive_pzmap(real_pole0.5, imag_pole0.5, real_zero-0.5, imag_zero0): poles [complex(real_pole, imag_pole), complex(real_pole, -imag_pole)] zeros [complex(real_zero, imag_zero), complex(real_zero, -imag_zero)] # 转换为传递函数系数 b np.poly(zeros) a np.poly(poles) plt.figure(figsize(12, 5)) # 零极点图 plt.subplot(1, 2, 1) plot_pzmap(zeros, poles) # 频率响应 plt.subplot(1, 2, 2) w, h signal.freqz(b, a) plt.plot(w, 20 * np.log10(abs(h))) plt.title(Frequency Response) plt.ylabel(Amplitude [dB]) plt.xlabel(Frequency [rad/sample]) plt.grid() plt.ylim(-40, 10) plt.tight_layout() plt.show() interact(interactive_pzmap, real_poleFloatSlider(min-1, max1, step0.05, value0.5), imag_poleFloatSlider(min0, max1, step0.05, value0.5), real_zeroFloatSlider(min-1, max1, step0.05, value-0.5), imag_zeroFloatSlider(min0, max1, step0.05, value0))通过这个交互实验你可以验证以下规律将极点向右移动增大实部系统会逐渐变得不稳定将零点移动到极点附近会抵消极点的影响形成零极点对消极点和零点在单位圆上的角度决定了频率响应的峰值和谷值位置5. 实际应用案例与常见问题掌握了基本原理后让我们看几个实际应用中的例子。第一个案例是设计一个带阻滤波器陷波器用于消除特定频率的干扰# 设计50Hz陷波器假设采样率1000Hz fs 1000 f0 50 # 要消除的频率 w0 2 * np.pi * f0 / fs # 转换为数字频率 # 创建陷波器 b, a signal.iirnotch(w0, 30, fs) # 绘制响应 plot_pzmap(*signal.tf2zpk(b, a)) plot_freq_response(b, a)这个例子展示了如何利用零极点分析设计特定用途的滤波器。陷波器的特点是在目标频率处放置零点完全抑制在附近放置极点增加选择性常见问题与解决方案数值不稳定现象频率响应曲线出现异常波动原因极点太靠近单位圆或零点极点非常接近解决使用signal.zpk2tf时添加analogFalse参数绘图不清晰# 提高频率响应的分辨率 w, h signal.freqz(b, a, worN8000)连续系统与离散系统的转换# 连续到离散的转换 dt 0.01 # 采样间隔 b_discrete, a_discrete signal.bilinear(b_continuous, a_continuous, fs1/dt)在完成这些实验后我建议你尝试设计一个完整的音频均衡器包含低通、高通和三个带通滤波器。通过调整每个滤波器的零极点位置你可以实现不同频段的增益控制。这个过程中你会发现零极点分析不仅是理论工具更是实际工程设计的指南针。