WARNING
🧪 Beta公测版本提示:教程主体已完成,正在优化细节,欢迎大家提Issue反馈问题或建议。
频域分析 — demo.py 代码详解
运行方式
bash
cd docs/control/classical/frequency/code
python demo.pyCPU、NumPy 即可。一张图 bode.png:上幅频(dB)、下相频(度),横轴对数 scipy.signal.bode。
代码逐段详解
第1步:复数 与向量化
python
KGAIN = 8.0 # 直流增益>1,幅频才会穿过 0 dB
def G_jw(omega):
"""向量化:omega 可以是数组。开环再乘 K,否则 |G(0)|=1,穿越频率退化。"""
s = 1j * omega
return KGAIN * (WN ** 2) / (s ** 2 + 2.0 * ZETA * WN * s + WN ** 2)1j:Python 的虚数单位。j单独不是虚数,必须写成数字后缀1j。omega可以是数组:NumPy 把1j * omega变成复数数组,除法逐点做。一次算出整条 Bode,不必for。- 分母
在 时一般不为 (极点不在虚轴上),所以能除。
第2步:dB 与辐角
python
def mag_db(g):
return 20.0 * np.log10(np.abs(g))
def phase_deg(g):
return np.angle(g, deg=True)np.abs:复数模,不是绝对值函数在实数上的特例写法,对复数同样适用。 np.log10:常用对数。来自功率: 再取 等于 。 np.angle(..., deg=True):辐角,单位度。默认是弧度。二阶系统相位从走到 。
第3步:网格上估 与相位裕度
python
w = np.logspace(-1, 2, 400)
...
crossed = np.where((mag[:-1] > 0.0) & (mag[1:] <= 0.0))[0]
idx = int(crossed[0]) if crossed.size else int(np.argmin(np.abs(mag)))
wc = float(w[idx])
pm = float(ph[idx] + 180.0)np.logspace(-1, 2, 400):到 ,对数均匀 400 点。Bode 横轴就是这样标的。 - 不要用
argmin(|mag|):直流增益接近时,整段低频都靠近 ,会把 误标在网格左端。应找「从正 dB 跨到负 dB」的第一个点。 PM \approx \phi(\omega_c)+180^\circ:相位是负的,加上得到「离 还剩多少」。网格近似,打印时会看到一个粗值。
semilogx:只对 sharex=True 让上下两图对齐同一 which='both' 让主次网格都淡淡画出来。
源码位置
clone 后打开(相对仓库根目录):
docs/control/classical/frequency/code/demo.py