WARNING
🧪 Beta公测版本提示:教程主体已完成,正在优化细节,欢迎大家提Issue反馈问题或建议。
控制论导论 — demo.py 代码详解
运行方式
bash
cd docs/control/overview/code
python demo.pyCPU、NumPy 即可。一张图 overview_loop.png:左是质量-弹簧的开环 vs 比例闭环,右是二阶系统四个阻尼比 scipy.signal,植物用半隐式欧拉往前走。
代码逐段详解
第1步:植物参数
python
M, C, KSPRING = 1.0, 0.4, 2.0
DT = 0.01
T_END = 8.0
R = 1.0
KP = 8.0
WN = 2.0KSPRING:弹簧刚度。后面 PID 增益用KP,避免和弹簧挤同一个K。R:参考位置。开环稳态力必须是R * KSPRING才能抵弹簧,否则质量会被拉回。 WN:右图二阶系统的自然频率,四个 共用,只改阻尼。
np.random.seed(42) 写了,但本脚本无随机数,轨迹完全确定。
第2步:mass_spring — 开环力 vs
python
def mass_spring(open_loop=True):
n = int(T_END / DT)
x, v = 0.0, 0.0
xs, ts = [], []
for i in range(n):
if open_loop:
u = R * KSPRING
else:
u = KP * (R - x)
a = (u - C * v - KSPRING * x) / M
v = v + DT * a
x = x + DT * v
xs.append(x)
ts.append(i * DT)
return np.array(ts), np.array(xs)- 先更新
v再更新x:半隐式欧拉,比两处都用旧速度更稳一点。 - 开环
u = R * KSPRING:稳态对,暂态全交给自己晃。 - 闭环只乘比例:没有积分,有弹簧时末端往往仍差一点——这是导论故意留的缺口,PID 章用
啃掉它。
语法:n = int(T_END / DT) 把秒数变成步数;xs.append(x) 先用 Python 列表,最后 np.array 一次转,避免循环里反复扩数组。
第3步:second_order_step — 标准二阶
改写成
python
a = wn ** 2 * (R - y) - 2.0 * zeta * wn * vzeta < 0:阻尼项变成加油,能量往上长,曲线发散。右图把它画出来,是为了让「右半平面极点」在时域里看得见。wn ** 2:Python 的幂是**,不是^(^是按位异或)。
第4步:画图与打印
python
zetas = [(1.4, '过阻尼 ζ=1.4'), (0.5, '欠阻尼 ζ=0.5'),
(0.0, '无阻尼 ζ=0'), (-0.15, '负阻尼 ζ=-0.15')]元组列表:第一个元素给积分,第二个给图例。y.max() 是 NumPy 数组的峰值,欠阻尼会大于
图存到章节 images/overview_loop.png:路径由 __file__ 往上拼,从哪启动脚本都写到对的地方。
源码位置
clone 后打开(相对仓库根目录):
docs/control/overview/code/demo.py