ARTICLE · 1017897
离散系统的数字校正:PID 下载进单片机中就震荡?问题可能出在一个约等号上
上一期我们把离散系统的"稳、准、快"全挂到了一个圆上——会看了。但看懂不等于会修。
这一期是第三部分,也是整个数字控制最实用的一段:怎么把控制器真正写进代码,怎么把一个不听话的系统调到又快又稳,以及——那个听起来像吹牛的"几拍到位",到底靠不靠谱。

1. PID 写成代码,难的不是公式,是三个「约等号」
连续 PID 谁都会背:

最麻烦的是中间那个积分号。单片机里没有"积分"这回事,只有"把过去的误差加起来"。
积分就是攒面积。那问题就只剩一个:这一格的面积,按哪个高度算?

用上一拍的误差当高度 —— 前向欧拉 用这一拍的误差当高度 —— 后向欧拉 两拍取平均(梯形)—— 双线性变换,也叫 Tustin
就这么朴素。所谓"离散化方法",一句话就是你打算怎么数格子。
对应到公式上,无非是把 (s) 换成三个不同的东西:

这一节记住:离散化不是什么高深操作,就是选一种数格子的方式。
2. 换个约等号,稳定的系统真会算成不稳定
数格子的方式听起来无伤大雅,但它决定了一件大事:连续世界里的"稳定区",被搬到 z 平面之后落在哪儿。

前向欧拉 
整个左半平面被摊成半个 z 平面,一大片落在单位圆外。也就是说,连续算着好好的系统,离散完可能直接发散。 后向欧拉 
左半平面被挤进一个半径为 0.5 的小圆,怎么都在圆内?听起来很安全?其实是它把本该发散的东西也算成了稳定——等于骗自己。 双线性 
左半平面 ↔ 单位圆内,边界对边界,不多不少。
真的会炸吗?会
拿个具体例子跑一遍。对象

PID 取

微分项带一个时间常数

的低通。三种写法,只改采样周期:
(表里是闭环极点的最大模长,超过 1 就发散)

看那个临界点:0.10 秒,正好是(2Tf)。
这不是巧合。前向欧拉把连续极点

搬到了

只要 (T>2Tf),这个点就跑到 (-1) 的左边去了——滤波器自己先不稳定了,跟你的 PID 参数一点关系都没有。
所以记住一个数:用前向欧拉采样时,采样周期必须小于微分滤波时间常数的两倍。
顺带补一刀:微分项一定要带低通
如果你用的是"教科书版"的理想微分项(Kd s),双线性变换会在 (z=-1) 给你留一个极点。上一期说过,负实轴上的极点意味着一拍高一拍低的振铃。
这不是精细调优的问题,是能不能用的问题。工程上微分项永远写成

3. 位置式还是增量式?真正要防的是「积分冲过头」
把三个约等号代进去,就得到两种写法。
位置式——直接算出这一拍该输出多少:

增量式——只算这一拍比上一拍多给多少:


增量式的好处很实在:不用存那个越滚越大的累加和;手动/自动切换的时候不会跳;执行器本身就是积分型的(步进电机、阀门开度)时,直接送增量最自然。
写成代码也就几行:
/* 增量式 PID,每个采样周期调用一次 */floatpid_step(floatref, float meas){static float e1 = 0.0f, e2 = 0.0f, u = 0.0f;float e = ref - meas;float du = Kp * (e - e1)+ Ki * T * e+ Kd / T * (e - 2.0f * e1 + e2);u += du;if (u > U_MAX) u = U_MAX; /* 先限幅 */if (u < U_MIN) u = U_MIN; /* 再输出,积分就飞不起来 */e2 = e1; e1 = e;return u;}
但真正的分水岭不在"位置式还是增量式",而在执行器饱和的那一刻你干了什么。
电机已经满功率了,误差还在,位置式的积分项照样闷头累加。等系统终于追上来,那个攒了一肚子的积分还得慢慢吐出去——于是冲过头。
同一套参数,三种写法:

增量式天生不容易冲过头,但抗饱和才是解药——两者不是二选一。
4. 数字校正:给系统配一副眼镜
PID 只是校正器里最出名的那一个。更一般的说法是:在回路里串一个 D(z),把闭环极点挪到你想要的地方。
常用的就两副"眼镜"。
超前校正:买速度
在对象的慢极点旁边放一个零点把它"按住",再放一个更靠近圆心的极点,根轨迹就被拽进来了。

同一个对象

调节时间砍到六分之一,超调几乎没了。代价写在最后一列:控制量峰值大了 5.6 倍。你的电机、驱动器扛不扛得住,这才是能不能这么调的真正边界。
滞后校正:买精度
滞后校正不管速度,专治"总差一口气"。做法是在 (z=1) 附近塞一对挨得很近的零极点,把低频增益抬上去。

一个 0 型系统,纯比例控制时稳态误差 0.50,加上


动态几乎没动,误差掉到原来的五分之一。
超前花的是功率,滞后花的是时间。天下没有白调的参数。
5. 无差拍:真能「几拍到位」吗?
前面都是"设计一个 D(z),然后看看效果"。无差拍控制把这个顺序反了过来:
先写下你想要的闭环,再反解控制器。
想要 (N) 拍到位?那就令闭环传递函数直接等于

输入延迟 (N) 拍原样输出,这不就是"(N) 拍精确到位"吗?然后反解:

听起来像作弊,但它真的成立:

两拍,输出精确等于 1,一点误差都没有。
然后看下面那一栏。
控制量第一下冲到 32.6,而这个系统稳定下来只需要 3.0 ——11 倍。而且它一正一负地甩:+32.6、−26.7、+22.9……执行器要是有限幅(哪个没有呢),这套设计当场失效。
还有两个更要命的

第一,采样点之间它在疯狂来回。控制器每隔 (T) 看一眼,每次看到的都是漂亮的 1.000。但被控对象经历的是一条 ±34% 上下翻滚的曲线。控制器很满意,机器很难受。
第二,模型错一点点就崩。无差拍是拿 (1/G(z)) 硬凑出来的,等于把控制器和对象完全绑死。对象的增益实际上偏了 30%——这在工程里根本不算大误差——结果就是超调 30%,说好的 2 拍变成了 8 拍。
所以:无差拍是一把尺子,量出"最快能多快";它不是一个可以直接上机器的目标。实际工程里常用的是"阻尼无差拍"——故意把 (\Phi(z)) 设计得没那么激进,用几拍的速度换一大截鲁棒性。
6. 总结?
还是六个词:
数格子、看落点、防饱和、买速度、买精度、留余量。
数格子:三种离散化就是三种数面积的方式; 看落点:前向欧拉会把稳定算成发散,双线性才是一一对应; 防饱和:执行器一顶到头,积分就得停手; 买速度:超前校正把极点拽向圆心,付的是控制量; 买精度:滞后校正抬低频增益,付的是响应时间; 留余量:无差拍的极限性能,是用鲁棒性换来的。
到这里,离散控制的三块拼图——建模、分析、校正——就齐了。你已经能把一个连续系统搬进单片机,判断它稳不稳,再把它调到想要的样子。