简介这份《Dr.CAN【自动控制原理】课程笔记13期全》面向自动控制理论初学者及需要补齐基础的高年级本科生、研究生尤其适合正在学习传递函数、稳定性分析与控制器设计却苦于边看视频边记笔记效率不高的读者。内容以课程截屏配合GoodNotes手写整理系统覆盖开环与闭环系统、反馈控制、传递函数、极点与稳定性、根轨迹绘制、终值定理与稳态误差、比例积分控制器以及分离点、大汇合点等知识点可作为课程同步复习与查漏补缺的参考。压缩包共1个PDF文件大小约12.27MB单文件便于在平板或电脑上翻阅标注。已有851人学习下载说明其在自动控制入门群体中有一定参考价值。笔记保留了课程讲解的推导脉络与图示适合用来快速回顾概念、对照例题理解根轨迹和PID调节思路也为后续学习卡尔曼滤波、MPC与最优控制打基础。1. 从开环到闭环反馈到底买到了什么很多人学自动控制原理第一反应是“这不就是调 PID 吗”真正卡住的地方其实更靠前同一个被控对象开环跑起来勉强能用接上反馈之后整个系统的脾气就变了。开环的加热器不管室外多冷都按固定功率输出闭环的加热器盯着温度计自己加油门或者松油门——这套 13 期课程笔记把这条分界线放在最前面用期望值、实际值、误差这三个量的关系把传递函数、极点、根轨迹一层层接上去。它真正讲的不是“会不会画图”而是让稳定性、稳态误差这些词变成能自己推一遍的东西。作为一份课程资源它的价值就在这条主线上先让你相信“极点位置决定命运”再告诉你控制器参数怎么把极点搬到想去的地方。2. 传递函数与零极点为什么一个分式就能描述整个系统2.1 拉普拉斯变换把微分方程降成代数方程时域里描述一个线性系统绕不开微分方程。二阶系统的形式是y 3y 2y u求解要靠特征根、特解、初始条件稍微复杂一点就没法手算。拉普拉斯变换做的事情只有一件把微分算子d/dt换成乘一个复变量s把卷积换成乘法把微分方程换成一个关于s的多项式方程。定义是F(s) ∫₀^∞ f(t)e^{-st}dt其中s σ jω。这个复变量的实部σ管衰减或发散虚部ω管振荡频率两个维度合起来正好是一张复平面。所有后续关于稳定性的讨论本质上都是在这张平面上看点的位置。import sympy as sp t, s sp.symbols(t s) # 一个指数衰减振荡信号e^{-2t} * sin(5t) f sp.exp(-2*t) * sp.sin(5*t) F sp.laplace_transform(f, t, s, nocondsTrue) print(sp.simplify(F)) # 5/((s 2)**2 25) # 反过来看极点分母为 0 的 s den sp.denom(sp.simplify(F)) print(sp.solve(den, s)) # [-2 5*I, -2 - 5*I]这段代码做了两件事先对时域信号做变换再从变换结果的分母里解出极点。e^{-2t}里的-2变成了极点的实部sin(5t)里的5变成了极点的虚部两者拼起来就是s -2 ± 5j。参数nocondsTrue是让 sympy 只返回变换结果、不附加收敛域条件实际手算时收敛域决定了这个变换在哪个σ范围内成立而极点位置恰好就在收敛域的边界上——这一点是理解“极点决定稳定性”的关键伏笔。2.2 极点决定模态零点决定权重拿到传递函数G(s) N(s)/D(s)之后把分母因式分解得到若干个极点p₁, p₂, …, pₙ把分子因式分解得到若干个零点z₁, z₂, …, zₘ。极点告诉你系统里存在哪些“基本运动模式”零点告诉你这些模式各自占多大比重。做一个部分分式展开就清楚了Y(s) N(s) / [(s-p₁)(s-p₂)…(s-pₙ)] A₁/(s-p₁) A₂/(s-p₂) … Aₙ/(s-pₙ)反变换回时域y(t) A₁e^{p₁t} A₂e^{p₂t} …。每个极点pᵢ贡献一个指数项系数Aᵢ由留数决定而留数的计算里必然出现分子N(pᵢ)——也就是零点。零点本身不产生新的运动模式但它能把某个模式的系数压到接近零甚至完全抵消。import numpy as np from scipy import signal # G(s) (s 3) / ((s 1)(s 2)) num [1, 3] den np.poly([-1, -2]) # 展开成 s^2 3s 2 sys signal.TransferFunction(num, den) t np.linspace(0, 6, 300) _, y signal.step(sys, Tt) # 部分分式系数A1 lim_{s--1} (s1)Y(s)/s for p in [-1, -2]: A np.polyval(num, p) / (p * np.polyval(np.polyder(den), p)) print(f极点 {p} 对应系数 A {A:.3f})np.poly([-1, -2])把极点列表展开成多项式系数np.polyder求导是为了算留数公式里的分母。跑出来的两个系数一大一小说明-1那个模态在响应里占主导-2那个模态衰减快、几乎看不见。零点-3在这里的作用是调整这两个系数的比例但改变不了“响应由-1主导”这个事实。这就是为什么调控制器时工程师盯着极点看零点只作为辅助手段。2.3 二阶系统的三个参数ωn、ζ 和极点坐标的换算工程上最常打交道的是一对共轭复极点。把它们写成标准形式s² 2ζωₙs ωₙ² 0 s -ζωₙ ± jωₙ√(1-ζ²)ωₙ是自然频率等于极点到原点的距离ζ是阻尼比等于极点实部绝对值除以这个距离。极点越靠近虚轴ζ越小超调越大极点越往左ζ越接近 1响应越平缓但越慢。这个换算关系是后面所有设计的坐标系。给定一组性能指标比如“超调不超过 10%、调节时间不超过 2 秒”可以直接翻译成复平面上的一个区域ζ ≥ 0.59给出一个扇形ζωₙ ≥ 2给出一条竖直线两条边界一交控制器要做的就是把闭环极点塞进这块区域里。这套语言比“调大一点、再调大一点”精确得多也是这份笔记反复强调“先画极点再动手”的原因。3. 稳定性为什么极点落在左半平面就一定会收敛3.1 e^{σt} 是稳定性判据的全部物理来源复极点写成s σ jω代回指数项e^{st} e^{(σjω)t} e^{σt} · (cos ωt j sin ωt)括号里是等幅振荡幅度恒为 1只负责来回摆真正决定“越摆越大还是越摆越小”的是外面的e^{σt}。σ 0时它是指数衰减振荡被压下去系统最终停在某个值上σ 0时它恒等于 1振荡幅度不增不减σ 0时它指数增长几秒钟之内就能把系统推到饱和。所以“极点必须在左半平面”没什么玄学成分它只是e^{σt}这个函数在σ取负值时的单调性。判断稳定性不需要解时域响应只需要看所有极点的实部符号——这就是这套笔记开篇就把单摆和平衡车摆在一起对照的原因。单摆在无阻尼、无摩擦的假设下极点是一对纯虚数±j√(g/L)。给它一个初始位移它会永远摆下去幅度不变也永远回不到原点。主观上它“看起来稳”数学上它只是临界稳定不是渐近稳定。平衡车正好相反倒立位置本身是一个右半平面极点不给控制它一定倒所以必须靠反馈把这对极点拉到左边去。两者的区别不在“有没有反馈”而在“极点在哪边”。3.2 劳斯判据不解高次方程也能数清右半平面有几个根四阶以上的特征方程手算求根基本不现实劳斯判据就是为这个场景准备的。它不给出根的具体位置只回答一个问题右半平面有几个根。构造方法是从最高次项开始把系数按奇偶列排成两行然后逐行做交叉相乘再相除s³ | 1 2 s² | 1 8 s¹ | b₁ b₂ s⁰ | c₁其中b₁ (1×2 - 1×8)/1 -6b₂ 0c₁ 8。首列是1, 1, -6, 8符号变化两次说明有两个根在右半平面系统不稳定。def routh_table(coeffs): coeffs 从最高次到常数项返回劳斯表的每一行 n len(coeffs) - 1 first coeffs[0::2] [0] second coeffs[1::2] [0] rows [first, second] for i in range(2, n 1): prev1, prev2 rows[i-1], rows[i-2] if abs(prev1[0]) 1e-12: prev1[0] 1e-9 # 首列为 0 时用极小量替代 new [(prev1[0]*prev2[j1] - prev2[0]*prev1[j1]) / prev1[0] for j in range(len(first) - 1)] [0] rows.append(new) return rows def count_right_half(coeffs): first_col [r[0] for r in routh_table(coeffs)] return sum(1 for a, b in zip(first_col, first_col[1:]) if a * b 0) print(count_right_half([1, 6, 11, 6])) # 0三阶全稳定 print(count_right_half([1, 1, 2, 8])) # 2两个右半平面根函数里first和second分别取奇数位和偶数位系数后面补零是为了让两行等长方便逐列做交叉相乘。if abs(prev1[0]) 1e-12这一段处理的是首列出现零的情况——真实系统里这种情况对应“有纯虚根”或者“有对称于原点的根”工程上通常用ε代替零再取极限代码里用极小量近似结论一致但数值上要注意别让它参与后面的除法时溢出。劳斯判据的局限也很明显它只回答“有没有右半平面根”不回答“离虚轴多远”。两个都稳定的系统一个极点离虚轴 0.01一个离虚轴 5实际表现天差地别。稳定性是二值的稳定裕度是连续的后者要靠根轨迹或者奈奎斯特图来补。3.3 相对稳定性极点离虚轴的距离就是衰减速度极点实部σ的绝对值直接就是包络线e^{σt}的时间常数倒数。σ -1意味着每过 1 秒幅度衰减到 37%σ -5意味着 0.2 秒就衰减到 37%。把极点从-1挪到-5响应快五倍听起来很美好但代价是控制器要输出的能量、系统带宽、对噪声的敏感度都会同步上去。这套笔记在讲稳定性时特意留了一句“越左越快但不是越左越好”这句话是整门课的分水岭。前面所有内容都在教“怎么判断稳不稳”从这里开始转向“稳到什么程度才合适”。第 6 章会把这个取舍展开先记住一个结论稳定裕度不是越大越好它和执行器的物理极限是一对矛盾。4. 终值定理与稳态误差为什么有的系统永远追不上目标4.1 终值定理的三个前提缺一个结论就是错的终值定理的形式很简洁lim_{t→∞} f(t) lim_{s→0} sF(s)。但它有一个容易被跳过的前提——sF(s)的所有极点必须位于左半平面允许在原点处有一个一阶极点。条件不满足时等式右边算出来的数字和时域的真实极限没有关系。最经典的反例是f(t) sin(t)。它的拉普拉斯变换是F(s) 1/(s²1)乘上s得到s/(s²1)令s→0得 0。按公式的结论sin(t)最终会趋于 0——显然荒谬它一直在-1和1之间振荡根本没有极限。问题出在sF(s)的极点是±j落在虚轴上不满足“全部在左半平面”的前提。import numpy as np # 时域直接验证sin(t) 在很大的 t 上依然在振荡 for T in [10, 1000, 10**6]: print(T, np.sin(T)) # 换一个满足条件的例子e^{-2t}F(s) 1/(s2) # sF(s) s/(s2)s-0 得 0与时域极限一致输出里sin(10**6)依然是[-1, 1]区间内的某个值不会收敛。这段代码的意义在于提醒终值定理是一个“有条件的捷径”用之前必须先检查sF(s)的极点分布。这套笔记里提到“无阻尼系统理论上终值应该回到 0、实际却一直在振”踩的就是这个坑——把定理当成了无条件成立的恒等式。4.2 系统型别决定了能跟踪哪一类输入把开环传递函数写成G(s) K·N(s) / [s^ν · D(s)]其中s^ν表示原点处的极点个数ν就叫系统型别。型别决定了系统对阶跃、斜坡、抛物线这三类输入的稳态误差型别阶跃输入斜坡输入抛物线输入0 型1/(1Kp)∞∞I 型01/Kv∞II 型001/Ka三个误差常数分别是Kp lim_{s→0} G(s)、Kv lim_{s→0} sG(s)、Ka lim_{s→0} s²G(s)。这张表的读法是每提高一个型别系统就能多跟踪一类输入而不产生稳态误差但代价是闭环特征方程的阶次升高稳定性变差。这条规律解释了一个常见困惑为什么纯比例控制的一阶系统跟踪阶跃输入总是差一点。设对象是K/(Ts1)比例增益Kp闭环传递函数是KKp/(Ts1KKp)阶跃稳态值是KKp/(1KKp)误差是1/(1KKp)。增大Kp只能把误差压小永远压不到零——因为开环是 0 型分母里没有s。4.3 积分环节的本质把型别提高一级在控制器里加一个1/s开环传递函数的分母就多了一个s型别从 0 型升到 I 型阶跃稳态误差立刻变成零。这就是积分控制的全部数学原理没有更神秘的东西。但型别升高是有代价的。原来的一阶闭环特征方程是Ts 1 KKp 0加积分之后变成Ts² (1KKp)s KKi 0从一阶变二阶。二阶系统就有共轭极点的可能Ki给大了会振荡给小了收敛慢。import numpy as np from scipy import signal # 被控对象 G 2/(s1) G signal.TransferFunction([2], [1, 1]) # 纯比例Kp 5闭环 10/(s11) sys_p signal.TransferFunction([10], [1, 11]) # PIKp 5, Ki 10开环 (10s20)/(s(s1)) # 闭环特征方程s^2 11s 20 0 sys_pi signal.TransferFunction([10, 20], [1, 11, 20]) t np.linspace(0, 5, 500) _, yp signal.step(sys_p, Tt) _, ypi signal.step(sys_pi, Tt) print(纯比例稳态值:, yp[-1]) # 0.909误差约 9% print(PI 稳态值:, ypi[-1]) # 1.0误差为 0signal.TransferFunction([10, 20], [1, 11, 20])里的分子10s20对应K·(Kp·s Ki)分母是闭环特征多项式。打印出来的两个稳态值直观展示了型别的差别纯比例永远差 9%加了积分之后精确到 1.0。但注意s²11s20的两个根是-2.5和-8.5都在左半平面所以这个 PI 参数是安全的如果Ki加到 100特征方程变成s²11s200根就跑到-5.5 ± 13j超调会非常明显。5. 根轨迹的常见问题分离点、渐近线和 K 值为什么总算错5.1 根轨迹的数学本质是把特征方程翻译成两个几何条件闭环特征方程是1 K·G(s)H(s) 0整理一下得到G(s)H(s) -1/K。右边是一个负实数所以左边必须满足两个条件相角条件∠G(s)H(s) (2k1)·180° 模值条件|G(s)H(s)| 1/K相角条件里没有K它只跟s的位置有关所以根轨迹的形状完全由开环零极点决定模值条件用来在已知形状上标定每个点对应的K。这个分离是根轨迹能手工画出来的根本原因——先靠相角条件画出曲线再靠模值条件标刻度。K从 0 变到无穷闭环极点就从开环极点出发最终落到开环零点或者无穷远处。n个开环极点对应n条分支其中m条终止于零点剩下的n-m条沿着渐近线跑向无穷。5.2 绘制规则的几何解释几条最常用的规则背后都是相角条件的直接推论实轴上的某一段属于根轨迹当且仅当这段右侧的实数零极点总数为奇数。原因是实轴上任意一点往左看共轭零极点对的相角互相抵消只有右侧的实数点会贡献180°的整数倍奇数个才能凑出(2k1)·180°。渐近线的角度是θ (2k1)·180°/(n-m)重心是σ (Σpᵢ - Σzⱼ)/(n-m)。n-m是分支数差决定了渐近线把复平面分成几个扇区重心是所有零极点的“质心”渐近线从这个点放射出去。分离点是根轨迹从实轴分叉进复平面的位置满足dK/ds 0等价于Σ 1/(s - pᵢ) Σ 1/(s - zⱼ)import numpy as np # G(s)H(s) 1/(s(s2)(s4))三个开环极点无零点 # 分离点方程1/s 1/(s2) 1/(s4) 0 # 通分后3s^2 12s 8 0 roots np.roots([3, 12, 8]) print(roots) # [-3.155, -0.845] # 实轴段判断右侧实数零极点个数为奇数的区间 # 0 到 -2右侧有 1 个极点0- 属于根轨迹 # -2 到 -4右侧 2 个 - 不属于 # -4 到 -∞右侧 3 个 - 属于算出来的两个根里-0.845落在0到-2这一段是合法的分离点-3.155落在-2到-4之间这一段不属于根轨迹必须舍掉。这一步是手算最容易翻车的地方dK/ds 0只是分离点的必要条件不是充分条件解出来的根必须回到实轴段上验证。5.3 用等阻尼线反推 K从性能指标到参数值给定阻尼比ζ复平面上的等阻尼线是一条从原点出发、与负实轴夹角为θ arccos(ζ)的射线。根轨迹和这条射线的交点就是满足该阻尼比的闭环极点交点对应的K由模值条件给出。import numpy as np def angle_condition(sv, poles, zeros): ang sum(np.angle(sv - z) for z in zeros) ang - sum(np.angle(sv - p) for p in poles) return np.degrees(ang) % 360 poles, zeros [0, -2, -4], [] zeta 0.45 # 沿等阻尼线扫描找相角条件等于 180° 的点 for w in np.linspace(0.1, 10, 20000): sv -zeta*w 1j*w*np.sqrt(1 - zeta**2) if abs(angle_condition(sv, poles, zeros) - 180) 0.5: K abs(sv) * abs(sv2) * abs(sv4) # 模值条件 |GH| 1/K print(f交点 s ≈ {sv:.3f}, K ≈ {K:.2f}) breakangle_condition里零点贡献正相角、极点贡献负相角这是∠(s-z) - ∠(s-p)的直接展开。扫描步长20000是为了在交点附近有足够分辨率abs(...) 0.5是容差。模值条件那行把|G(s)H(s)| 1/K反过来用直接算出K |s|·|s2|·|s4|。这套流程在工程上就是“给定 ζ 求 K”比反复试凑快得多也是根轨迹相比直接解特征方程的最大优势——它把一维参数K的变化过程完整地画了出来。5.4 四个高频翻车点分离点算出复数根却硬画在实轴上。现象是手算出来的分离点带虚部画图时却当成实数点标上去。原因是dK/ds 0的解可能是一对共轭复根只有实根才有资格当分离点。解决方式是先看虚部是否为零再把实根代回实轴段判断两个条件都满足才保留。渐近线角度里 n 和 m 用反。现象是画出来的渐近线方向完全不对分支数也对不上。原因是有零点时n-m变小渐近线条数应该等于n-m而不是n。解决方式是在纸上先写清楚“几个极点、几个零点、差几条”再代公式别凭记忆套。K 用开环增益直接代入。现象是模值条件算出来的K和实际控制器参数对不上差一个系数。原因是根轨迹里的K是首一形式下的增益G(s)H(s)必须写成K·Π(s-zᵢ)/Π(s-pⱼ)如果原始传递函数里有10/(s²3s2)这种形式要先化成10/[(s1)(s2)]再确认K到底乘在哪里。解决方式是把传递函数统一化成首一多项式再读K。把根轨迹穿过虚轴时的 K 当成可用上限。现象是参数取到临界值仿真里勉强稳定实测时一有扰动就发散。原因是穿轴点对应的是临界稳定相位裕度为零任何建模误差都会把它推过去。解决方式是在穿轴K的基础上留出 3 到 6 dB 的裕度实际取值不要贴着边界。6. 设计取舍为什么“极点越靠左”是个伪目标把整套内容串起来看自动控制原理给出的其实是一张地图传递函数是坐标极点是位置稳定性是左半平面这个区域根轨迹是参数变化时极点移动的路径PID 是三种搬动极点的工具。地图很完整但真实系统从来不按地图走。最典型的误区是把“极点越靠左越好”当成设计准则。极点往左移响应确实变快但控制器输出的变化率、系统带宽、对传感器噪声的放大倍数会同步上升。一个位置伺服系统如果把带宽从 10 Hz 提到 100 Hz电机电流的噪声会被放大十倍执行器很快就会进入饱和饱和之后模型不再是线性的前面所有基于线性系统的推导全部失效。稳定裕度和物理极限之间的这条线才是设计真正要处理的东西。第二个取舍在 PID 三项之间。比例项负责把极点整体往左推代价是超调和稳态精度之间的矛盾积分项负责提高型别、消掉稳态误差代价是相位滞后和阶次升高微分项负责增加阻尼、压住超调代价是对高频噪声极其敏感实际工程里往往要加一个低通滤波把微分项的高频增益压下去。三项不是“都加上就更好”而是各自对应一类具体问题用错了会互相拆台。手段改变的物理量主要代价适用场景增大 Kp极点左移、响应加快超调、噪声放大、饱和对象惯性大、精度要求一般加入 Ki型别升高、稳态误差归零阶次升高、易振荡需要精确跟踪常值或斜坡加入 Kd阻尼增加、超调下降高频噪声放大对象有明显惯性滞后配置零点改变根轨迹形状需要额外传感器或补偿网络单纯调增益无法满足指标第三个取舍是模型精度和控制器复杂度之间的权衡。根轨迹、劳斯判据、终值定理全都建立在“系统是线性时不变的”这个假设上。真实对象有摩擦、有饱和、有死区、有参数漂移模型越精细控制器越复杂但复杂控制器对模型误差的鲁棒性往往更差。工程上 PID 长期占据主流不是因为它先进而是因为它在模型不准时退化得比较体面——这一点在笔记里那句“先看懂极点再谈算法”里其实已经埋下了。从那以后我每次调参之前都会先在复平面上把开环极点标出来、把目标区域画出来再决定动哪一项而不是打开仿真软件盲扫。这个习惯让我少走了很多弯路极点图不会骗人它只会老老实实告诉你你想要的响应速度和你能接受的稳定裕度之间到底隔着多远本文还有配套的精品资源点击获取