2、线性MPC理论:线性状态空间模型、预测方程推导、代价函数设计、约束处理
好,咱们进入正题。线性MPC,说白了就是模型预测控制里最基础、最成熟的那一套。你想想看,很多工业场景下,系统本身虽然不是严格线性的,但在工作点附近用线性模型去近似,效果已经足够好了。我个人习惯,做项目第一步就是先把模型线性化,省得后面自找麻烦。
2.1 线性状态空间模型
咱们先从最熟悉的离散时间状态空间模型说起。为什么用离散的?因为控制器是数字的,采样周期固定,天然就是离散的。
标准形式长这样:
x(k+1) = A x(k) + B u(k)
y(k) = C x(k) + D u(k)
这里:
- x(k) 是状态向量,维度 n×1。比如电机的位置、速度。
- u(k) 是控制输入,维度 m×1。比如电压、电流。
- y(k) 是系统输出,维度 p×1。比如你关心的角度。
- A 是系统矩阵,n×n。描述状态怎么自演化。
- B 是输入矩阵,n×m。描述控制量怎么影响状态。
- C 是输出矩阵,p×n。描述哪些状态被观测到。
- D 是前馈矩阵,p×m。大多数情况下是零矩阵。
我在项目中遇到过一个问题:有人直接把连续系统模型拿过来用,采样周期一长,预测全乱套了。记住,这里的A和B必须是离散化之后的。常用的方法有零阶保持器法(ZOH),或者直接用欧拉法近似:
A_d = I + A_c * Ts
B_d = B_c * Ts
嗯,这里要注意,欧拉法只在采样周期足够小时才准。如果Ts大了,建议用c2d函数做精确离散化。
2.2 预测方程推导
有了模型,下一步就是预测未来。说白了,就是根据当前状态x(k),和未来一系列控制输入u(k), u(k+1), ...,算出未来的状态x(k+1), x(k+2), ...。
咱们定义预测时域为N。那么从k时刻开始,未来N步的状态可以写成:
x(k+1) = A x(k) + B u(k)
x(k+2) = A x(k+1) + B u(k+1) = A^2 x(k) + A B u(k) + B u(k+1)
x(k+3) = A^3 x(k) + A^2 B u(k) + A B u(k+1) + B u(k+2)
...
x(k+N) = A^N x(k) + A^(N-1) B u(k) + ... + B u(k+N-1)
写成紧凑的矩阵形式,就是所谓的预测方程:
X = F x(k) + G U
其中:
- X = [x(k+1); x(k+2); ...; x(k+N)],维度 Nn×1
- U = [u(k); u(k+1); ...; u(k+N-1)],维度 Nm×1
- F = [A; A^2; ...; A^N],维度 Nn×n
- G 是一个下三角块矩阵,维度 Nn×Nm
这个G矩阵长什么样?我写个伪代码你感受一下:
G = [B, 0, 0, ..., 0;
A B, B, 0, ..., 0;
A^2 B, A B, B, ..., 0;
...
A^(N-1) B, A^(N-2) B, ..., B]
为什么是下三角?因为未来的控制输入不能影响过去的状态。这个因果关系一定要搞清楚。
2.3 代价函数设计
预测做好了,接下来就是「怎么才算好」。代价函数,就是量化控制性能的尺子。
标准的二次型代价函数长这样:
J = sum_{i=1}^{N} [ x(k+i)^T Q x(k+i) + u(k+i-1)^T R u(k+i-1) ]
这里:
- Q 是状态权重矩阵,半正定。越大,系统越「着急」让状态回到零。
- R 是输入权重矩阵,正定。越大,控制动作越「温柔」。
你想想看,如果Q很大R很小,控制器会拼命用大电压去调节,响应快但可能震荡。反过来,R很大Q很小,系统就慢吞吞的,像个老爷车。
在实际项目中,我一般这样调参:
- 先把R固定,比如设为单位矩阵。
- Q用对角线矩阵,先设成单位阵,然后根据物理量纲调整。比如位置误差权重给10,速度误差权重给1。
- 跑仿真,看响应。如果震荡,增大R;如果太慢,增大Q。
把预测方程代入代价函数,可以写成关于U的二次型:
J = U^T H U + 2 x(k)^T f U + constant
其中:
- H = G^T Q_bar G + R_bar
- f = G^T Q_bar F
- Q_bar和R_bar是块对角矩阵,由Q和R重复N次组成。
这个形式,就是标准的二次规划(QP)问题。后面求解就交给求解器了。
2.4 约束处理
线性MPC最大的优势之一,就是能显式处理约束。没有约束的MPC,其实和LQR差不多。有了约束,才是真正的MPC。
常见的约束有三类:
| 约束类型 | 数学表达 | 物理含义 |
|---|---|---|
| 输入约束 | u_min ≤ u(k) ≤ u_max | 电机最大电压、阀门最大开度 |
| 输出约束 | y_min ≤ y(k) ≤ y_max | 位置不能超限、温度不能过高 |
| 状态约束 | x_min ≤ x(k) ≤ x_max | 速度限制、角度限制 |
把这些约束写成关于U的线性不等式:
A_ineq U ≤ b_ineq
举个例子,输入约束:
u_min ≤ u(k) ≤ u_max
u_min ≤ u(k+1) ≤ u_max
...
u_min ≤ u(k+N-1) ≤ u_max
写成矩阵形式就是:
[ I; -I ] U ≤ [ u_max * ones(N,1); -u_min * ones(N,1) ]
输出约束稍微复杂一点,因为输出是状态的线性组合:
y(k+i) = C x(k+i) = C ( A^i x(k) + ... )
最终也能写成关于U的线性不等式。
2.5 完整的MPC优化问题
把上面所有东西拼起来,线性MPC在每个采样时刻要解决的优化问题就是:
min_U U^T H U + 2 x(k)^T f U
s.t. A_ineq U ≤ b_ineq
这是一个标准的凸二次规划问题。求解之后,取U的第一个元素u(k)作为实际控制量施加到系统上。下一时刻,重新测量状态,再求解一次。这就是滚动时域控制的核心思想。
嗯,说到这里,我想起刚入行时的一个误区:以为MPC是一次性算完所有控制量然后一股脑全用上。其实不是的,每次只取第一步,剩下的都扔掉。为什么?因为模型有误差,预测不准,必须不断用新测量值修正。
核心要点回顾:
- 线性状态空间模型是基础,记得离散化
- 预测方程把未来状态写成当前状态和未来控制输入的线性组合
- 代价函数用Q和R调性能,二次型形式方便求解
- 约束写成线性不等式,加入QP问题中
- 滚动时域:只取第一步,不断重复
下一章,咱们会聊怎么实际求解这个QP问题,以及代码实现上的细节。到时候我会分享一些我在嵌入式平台上跑MPC的实战经验,包括怎么选求解器、怎么处理计算延时等等。敬请期待。