增量式状态空间MPC的Matlab实现与公式详解
MPC模型预测控制这几年在工业过程控制、自动驾驶、机器人运动控制里几乎成了标配。但很多入门的朋友跟我一样一开始接触的都是最朴素的状态空间MPC直接以控制输入 u(k) 为决策变量代价函数里对 u 做惩罚约束也直接加在 u 上。等项目真落地的时候发现一个问题模型有误差或者存在外部常值扰动时静差消不掉控制器输出在稳态时总差那么一点。后来我认真啃了采用输入增量Δu的MPC公式发现状态空间模型的推导方式还不止一种不同公式实现出来的效果、代码复杂度、数值稳定性差别都不小。今天这篇就以Matlab代码实现为主线把“用输入增量构造状态空间MPC”的几种典型公式掰开揉碎把我的推导思路、仿真代码和踩坑记录一并分享出来。适合已经会基础MPC推导、想搞清楚增量式实现细节的朋友也适合正在做MatlabSimulink控制器开发、打算自己手写MPC求解器的工程师参考。1. 为什么MPC要引入输入增量从基本原理讲起1.1 标准状态空间MPC的基本形式先把标准离散状态空间模型写在前面后面所有增量式公式都是从这个模型变过去的。设被控对象为线性时不变离散系统x(k1) A x(k) B u(k) y(k) C x(k) D u(k)其中 x∈R^nu∈R^my∈R^p。MPC的核心思想是在当前时刻 k利用该模型预测未来 N_p 步的输出或者状态构造一个带约束的优化问题求出未来 N_c 步的最优控制序列然后只把第一步控制量送到被控对象下一时刻滚动优化。标准MPC通常直接以 u(k), u(k1), ..., u(kN_c-1) 为优化变量目标函数写成J Σ_{i1}^{N_p} || ŷ(ki) - r(ki) ||Q^2 Σ{i0}^{N_c-1} || u(ki) ||_R^2约束包括输入幅值约束、输入变化率约束、输出约束等。这种做法在理想模型下没问题仿真效果很漂亮。但是只要被控对象有未建模动态、模型参数失配或者常值扰动输出就会存在稳态误差。原因是标准MPC没有把积分作用显式放进控制器结构里而对无自衡对象或者有扰动的系统没有积分环节就相当于比例控制静差是必然的。1.2 输入增量式MPC的核心动机消除稳态误差和抗扰动把控制增量 Δu(k)u(k)-u(k-1) 作为优化变量本质上是在控制器内部引入了一个离散积分器。可以这样理解MPC每步解出来的不是绝对位置的控制量而是控制量的“变化量”控制器输出的实际控制量通过累加得到u(k) u(k-1) Δu(k)这样一来即便模型有常值误差只要输出偏离设定值优化问题就会持续产生非零的 Δu(k)累计之后改变 u(k)直到误差被校正。有了这个离散积分环节系统的类型数增加对阶跃扰动和阶跃给定都能实现无静差跟踪。这跟经典控制里在PID中加积分项、在LQR前面加积分器原理是相通的。只不过MPC通过把 Δu 放到优化变量里把积分作用自然地嵌入到了预测模型中不需要额外设计误差积分状态。另外把 Δu 作为优化变量还有一个工程上的好处可以直接对控制增量施加约束。比如执行机构是伺服电机给定转速变化率不能超过某个值或者执行器是液压阀阀位开度变化速度有限制。这时只需要在优化问题里写 u_min ≤ u ≤ u_max、Δu_min ≤ Δu ≤ Δu_max 即可。如果还是以绝对 u 为变量变化率约束就得写成相邻两个 u 的差值形式虽然也能写但在某些控制器平台上比如Q3P、FORCES等不如直接用增量更方便。1.3 输入增量方案下的两种处理思路同样是用 Δu 作为优化变量状态空间模型的写法至少有两条路扩维状态法把上一时刻的控制输入 u(k-1) 作为新增状态构成新状态向量 z(k) [x(k); u(k-1)]于是原模型转变成以 Δu 为输入的标准状态空间模型。全增量法状态和输入一起取增量即 Δx(k)x(k)-x(k-1)Δu(k)u(k)-u(k-1)再选择合适的新状态通常是 [Δx(k); y(k)] 或 [Δx(k); e(k)]构造增广模型。两条路最终都能得到形如z(k1) Ã z(k) B̃ Δu(k) y(k) C̃ z(k)的标准状态空间方程因此可以统一套用常规的MPC预测矩阵推导只是在状态维度、矩阵构造细节上有差异。我自己的体会是扩维状态法直观好理解适合新手全增量法在输出跟踪和抗扰动设计上更顺手尤其是对输出方程里直接含输入项 D 的情况处理起来更规整。下面两部分分别把这两种公式的推导过程完整走一遍并给出对应的Matlab矩阵装配代码。2. 状态空间扩维法把输入增量变成标准状态空间2.1 扩维建模的原理推导假设被控对象模型为不带直接传输项 D 的简化形式这一步是为了减少干扰实际中 D 非零时后文也会给出处理方法x(k1) A x(k) B u(k) y(k) C x(k)定义增广状态 z(k) [x(k); u(k-1)]维度为 nm。因为当前时刻 u(k) u(k-1) Δu(k)所以x(k1) A x(k) B [u(k-1) Δu(k)] A x(k) B u(k-1) B Δu(k) u(k) u(k-1) Δu(k)写成矩阵形式[ x(k1) ] [ A B ] [ x(k) ] [ B ][ u(k) ] [ 0 I ] [ u(k-1) ] [ I ] Δu(k)即z(k1) Ã z(k) B̃ Δu(k)其中Ã [ A, B ; 0, I_m ] B̃ [ B ; I_m ]输出方程y(k) C x(k) [ C, 0 ] z(k)如果原输出方程中有直接传输项即 y(k)C x(k)D u(k)代入 u(k)u(k-1)Δu(k) 得y(k) [ C, D ] z(k) D Δu(k)注意此时输出方程多了一项 D Δu(k)。虽然也可以通过增广输出向量把 D Δu(k) 并进状态但通常MPC预测时输出表达式中会出现“当前时刻输入增量”对应的矩阵推导预测方程时需要单独处理略麻烦。这也是很多人推荐先忽略 D 或者通过模型变换消掉 D 的原因。2.2 扩维后预测模型的矩阵形式一旦写出标准状态空间模型 z(k1)Ã z(k)B̃ Δu(k)接下来的预测推导就和普通MPC完全一致了。设预测时域为 N_p控制时域为 N_c并令 N_c ≤ N_p并假设在 N_c 之后控制增量保持为0。定义从 k 时刻起未来控制增量向量为ΔU [ Δu(k); Δu(k1); ...; Δu(kN_c-1) ] ∈ R^{m N_c}预测状态序列为Z [ z(k1); z(k2); ...; z(kN_p) ]则Z Φ z(k) Ψ ΔU其中 Φ 是块列矩阵Ψ 是块下三角矩阵具体形式跟普通MPC一样Φ [ Ã; Ã^2; ...; Ã^{N_p} ]Ψ [ B̃, 0, 0, ...Ã B̃, B̃, 0, ...Ã^2 B̃, Ã B̃, B̃, ......Ã^{N_p-1} B̃, ..., Ã^{N_p-N_c} B̃ ]然后预测输出 Y [ ŷ(k1); ...; ŷ(kN_p) ] C_z Z其中 C_z blkdiag(C̃, C̃, ..., C̃)。这里 C̃ 根据扩维状态法输出矩阵而定若原始输出为 C x则 C̃ [ C, 0 ]。在Matlab中推荐用循环或者 cell 数组构造 Φ 和 Ψ不要手动展开大矩阵否则维度一变就错。后面代码部分我会给出实用函数。2.3 约束处理与代价函数设计采用输入增量后优化变量是 ΔU需要把原约束统一转成关于 ΔU 的不等式。典型约束有控制增量约束Δu_min ≤ Δu(ki) ≤ Δu_max这直接是 ΔU 的上下界处理最简单。控制幅值约束u_min ≤ u(ki) ≤ u_max。由于 u(ki) u(k-1) cumsum(Δu(k) ... Δu(ki))需要把历史累计关系写成矩阵例如定义 T_u 为下三角块元素全为 I_m 的矩阵则 U repmat(u(k-1), N_p,1) T_u ΔU_new其中 ΔU_new 扩展到 N_p 维N_c之后置0也可以见同构扩展。上下限约束写成 -T_u ΔU ≤ -u_min repmat(u(k-1),...) T_u ΔU ≤ u_max - repmat(u(k-1),...)输出约束y_min ≤ ŷ(ki) ≤ y_max直接基于 Y C_z Φ z(k) C_z Ψ ΔU 写出线性不等式本质上也是 ΔU 的线性约束。代价函数中可以包含输出跟踪误差、输入增量惩罚、控制幅值惩罚等。如果以 ΔU 为变量目标函数标准形式为J (Y - R)^T Q_y (Y - R) ΔU^T R_du ΔU U^T R_u U其中 R 是参考轨迹向量。由于 U 也是 ΔU 的线性函数最后能转化为一个标准的凸二次规划QP问题。解决QP之后取 ΔU 的第一个分量 Δu(k)实际控制量 u(k)u(k-1)Δu(k) 输出给被控对象。这里有个容易忽视的细节代价函数里的输入增量惩罚矩阵 R_du 和输入幅值惩罚矩阵 R_u 并不是一回事。在一些代码实现中只惩罚增量不惩罚幅值这样控制器可能输出一个很大的偏置量只惩罚幅值、不惩罚增量又可能出现剧烈抖动的增量信号。通常的做法是两者都保留但幅值惩罚项要放很小的权重或者根本不加入目标函数而只通过约束限制幅值具体看工程需求。3. MATLAB代码实现增量式MPC控制器搭建全流程3.1 仿真场景和对象模型为了对比不同公式我选了一个经典的二阶开环不稳定对象加上输入输出模型形式如下离散化后A [1.1 0.3; 0 0.8]; B [0.1; 0.2]; C [1 0]; D 0;采样周期 T_s0.1s。这个对象开环极点一个在单位圆外1.1用普通比例控制很难稳定很适合拿MPC演示。仿真中设置设定值 r1在 t5s 加入幅值0.1的常值扰动考察增量式MPC的静差消除能力。为什么不直接用更简单的稳定对象因为在稳定对象上普通MPC和增量式MPC的静差差别可能不明显尤其模型精确时基本看不出区别但换到不稳定对象上模型失配和扰动的效果一下子就被放大了更适合暴露问题。3.2 预测模型构建与Horizon设置用一个增广函数把原始 A,B,C 转换成扩维模型function [At, Bt, Ct] augmentInputModel(A, B, C, m) % 扩维状态法z [x; u_prev]输入为 du n size(A,1); At [A, B; zeros(m, n), eye(m)]; Bt [B; eye(m)]; Ct [C, zeros(size(C,1), m)]; end如果原始模型带 D则增广输出为 Ct [C, D]但同时要注意输出预测时额外加一项 Ddu。为了代码整洁下面的示例先假设 D0实际工程如果 D 不为零要么对模型做预处理要么在预测函数里单独加 Ddu 项我会在后面补一段说明。然后构造预测矩阵 Ψ 和 Φ。一个简单但清晰的循环写法function [Phi, Psi] buildPredictionMatrices(At, Bt, Ct, Np, Nc) n size(At,1); p size(Ct,1); m size(Bt,2); Phi zeros(p*Np, n); Psi zeros(p*Np, m*Nc); % 构造 Phi Pk At; for i 1:Np Phi((i-1)*p1 : i*p, :) Ct * Pk; Pk At * Pk; end % 构造 Psi H zeros(n, m*Nc); H(:, 1:m) Bt; for i 1:Np row_start (i-1)*p 1; row_end i*p; for j 1:min(i, Nc) col_start (j-1)*m 1; col_end j*m; if i 1 j 1 Psi(row_start:row_end, col_start:col_end) Ct*Bt; else % 计算 At^(i-j) * Bt A_pow At; for q 1:(i-j) A_pow At * A_pow; end Psi(row_start:row_end, col_start:col_end) Ct * A_pow * Bt; end end end end这个写法里对每项都重新算 At 的幂效率不高但胜在直观控制工程里时域不会太长Np 一般不超过20效率可以接受。追求效率的话可以提前把 At^0,...,At^{Np-1} 存进 cell 数组再调用。3.3 二次规划求解与闭环仿真代码增量式MPC的核心在每个采样周期求解一个QP。Matlab环境里最省事的是用旧版quadprog接口新版也可以用optimoptions指定求解器。先搭出 QP 的标准形式min 0.5 * x * H * x f * x s.t. A_ineq * x ≤ b_ineq A_eq * x b_eq lb ≤ x ≤ ub其中 x 就是 ΔU。代价函数采用J (Y - R)^T Q_y (Y - R) ΔU^T R_du ΔU注意这里为了简洁暂时不加控制幅值惩罚项只把幅值约束写进不等式里。展开Y Phi * z Psi * du_vector所以J (Psidu - (R - Phiz)) * Qy * (Psidu - (R - Phiz)) du * Rdu * du du * (PsiQyPsi Rdu) * du - 2*(R-Phiz)QyPsidu const常数项不影响最优解故可令H_qp 2 * (Psi * Qy * Psi Rdu) f_qp -2 * Psi * Qy * (R - Phi * z)约束方面假设只有幅值约束 u_min ≤ u ≤ u_max 和增量约束 du_min ≤ du ≤ du_max。注意 du 向量长度 Nc*m但实际预测时 Np 可能比 Nc 长增量在 Nc 之后默认0所以在构建约束矩阵时要把 Np 内的控制序列用 Nc 个增量表示u_k_i u_prev [T_u_cum] * du其中 T_u_cum 是一个 (Npm) x (Ncm) 的矩阵第 i 块的累加逻辑是如果 i ≤ Nc则第 i 块取前 i 个 du 块之和如果 i Nc则取 Nc 个 du 块之和。Matlab里用 kron 和 tril 构造很方便T_cum zeros(Np*m, Nc*m); for i 1:Np jmax min(i, Nc); for j 1:jmax T_cum((i-1)*m1:i*m, (j-1)*m1:j*m) eye(m); end end % 但注意这里每行块累积和还需要乘以单位阵这个循环更清楚更紧凑的写法是T_cum zeros(Np*m, Nc*m); B_eye repmat({eye(m)}, Np, Nc); for i1:Np for j1:min(i,Nc) T_cum((i-1)*m1:i*m,(j-1)*m1:j*m)eye(m); end end不过还是循环直观。然后幅值约束U_full repmat(u_prev, Np,1) T_cum * du u_min_full ≤ U_full ≤ u_max_full即T_cum * du ≤ u_max_full - repmat(u_prev, Np,1) -T_cum * du ≤ -u_min_full repmat(u_prev, Np,1)增量约束直接落在 du 的上下界。把这些凑成 A_ineq, b_ineq, lb, ub。完整仿真主程序如下仅核心部分% 参数设置 Np 10; Nc 3; Qy 10 * eye(Np); % 每个输出均有权重或针对单输出就标量乘单位阵 Rdu 0.5 * eye(Nc); u_min -2; u_max 2; du_min -0.5; du_max 0.5; u_prev 0; x zeros(2,1); z [x; u_prev]; Tsim 30; Nsim Tsim / Ts; % 预分配存储 y_hist zeros(Nsim,1); u_hist zeros(Nsim,1); options optimoptions(quadprog,Display,off); for k 1:Nsim % 测量或者从对象仿真获取当前状态 x % 参考轨迹 r_k 1; R repmat(r_k, Np, 1); % 当前增广状态 z [x; u_prev]; % 预测矩阵 [Phi, Psi] buildPredictionMatrices(At, Bt, Ct, Np, Nc); % QP 目标 H_qp 2 * (Psi * Qy * Psi Rdu); f_qp -2 * Psi * Qy * (R - Phi * z); % 约束 T_cum zeros(Np, Nc); for i1:Np for j1:min(i,Nc) T_cum(i,j) 1; % 单输入情况下 m1直接标量 end end U_full repmat(u_prev,Np,1) T_cum * du; % 这里 du 是符号实际作为变量 A_ineq [T_cum; -T_cum]; b_ineq [repmat(u_max,Np,1) - repmat(u_prev,Np,1); ... -repmat(u_min,Np,1) repmat(u_prev,Np,1)]; lb repmat(du_min, Nc, 1); ub repmat(du_max, Nc, 1); % 求解 du_opt quadprog(H_qp, f_qp, A_ineq, b_ineq, [], [], lb, ub, [], options); du_k du_opt(1); u_k u_prev du_k; % 仿真对象 x_next A * x B * u_k; y_k C * x_next; % 注意输出取 x(k1) 或者 x(k)噪声均可这里简化为下一拍输出 % 或者按 yCx 当前状态按需处理 % 更新 x x_next; u_prev u_k; y_hist(k) y_k; u_hist(k) u_k; end上面代码为了示意做了一些简化比如输出取的是下一拍状态但整体闭环逻辑完整。实际部署时建议把预测矩阵的构建移到循环外因为模型是定常的Phi 和 Psi 可以提前算好循环里只更新 z 和参考轨迹这样仿真速度能快不少。3.4 结果可视化分析仿真结束后画出输出曲线和控制曲线。增量式MPC在 t5s 常值扰动加入后输出经过短暂波动能重新回到设定值这说明积分作用确实生效了。对比普通MPC以 u 为变量的代码两者在初始响应阶段差别不大但扰动阶段普通MPC的输出会固定在某个偏差处怎么调 Q、R 都压不掉那点误差原因就是没有积分环节。另外我还测试了不同的 Rdu 对系统动态的影响。Rdu 越大控制增量被约束得越保守系统响应变慢但控制量变化更平滑Rdu 过小时控制器对误差反应过于激进可能出现振荡。直观上Rdu 就类比对控制量的“阻尼系数”调参时可以先从 Rdu1 开始再往两个方向扫。4. 不同状态空间MPC公式的对比与选型4.1 增量式输出MPC与增量式状态MPC的差异全增量法用的是另一种扩维方式将状态增量 Δx(k) 和输出 y(k) 组成新状态。推导如下定义 Δx(k)x(k)-x(k-1)则Δx(k1) x(k1)-x(k) A Δx(k) B Δu(k)同时y(k1) C x(k1) C A x(k) C B u(k)要做到用 Δx 和 y 表示 y(k1)需要对 x(k) 做变换。常见技巧是引入输出方程y(k)C x(k)于是 x(k) 可以由当前状态得到。但更标准的做法是定义新状态 z [Δx(k); y(k)]并利用以下关系y(k1) y(k) C Δx(k1) y(k) C (A Δx(k) B Δu(k)) C A Δx(k) y(k) C B Δu(k)不对上述推导有问题因为 y(k)C x(k)Δx(k1)x(k1)-x(k)则 y(k1)C x(k1)C x(k)C Δx(k1)C x(k)C A Δx(k)C B Δu(k)。而 C x(k) 不等于 y(k)C Δx(k)? 实际上 x(k)x(k-1)Δx(k)所以 C x(k)C x(k-1)C Δx(k)y(k-1)C Δx(k)这里多出来 y(k-1)。因此标准做法中需要把状态扩成 [Δx(k); y(k)] 的时候推导利用 x(k)Δx(k)x(k-1)且 Δx(k1)A Δx(k)B Δu(k)。然后y(k1)C A x(k)C B u(k) 这个表达式里含绝对状态和绝对输入不好直接转化。王鹏教材里采用的是对状态方程先取增量再取输出为 y(k1)C A x(k)C B u(k)最后巧妙利用 y(k)C x(k) 以及 x(k)Δx(k)x(k-1) 得到y(k1)-y(k)C A Δx(k)C B Δu(k) 吗我们验证y(k1)C x(k1)C(A x(k)B u(k)) y(k)C x(k) 因此 y(k1)-y(k)C(A-I)x(k)C B u(k)。包含绝对量不简洁。实际上需用扩大状态的等式取 z1(k)Δx(k)z2(k)y(k) 则 Δx(k1)A Δx(k)B Δu(k) 同时 y(k1)y(k)C Δx(k1)? 不对因为 y(k1)-y(k)C x(k1)-C x(k)C(x(k1)-x(k))C Δx(k1)。 这里注意 C Δx(k1)C(x(k1)-x(k)) y(k1)-y(k)。所以 y(k1)y(k)C Δx(k1)。而 Δx(k1)A Δx(k)B Δu(k)。因此y(k1)y(k)C(A Δx(k)B Δu(k)) C A Δx(k) y(k) C B Δu(k)。推导成立。需要利用 y(k)C x(k) 吗不需要只用到 y(k) 作为积分器状态。所以全增量模型为[ Δx(k1) ] [ A 0 ] [ Δx(k) ] [ B ] [ y(k1) ] [ C A I ] [ y(k) ] [ C B ] Δu(k)输出为 y(k) (其实 y(k1) 是状态第二分量)。注意这里 y(k) 是“上一时刻输出”的积分模型内蕴含积分环节状态维度为 np比扩维状态法的 nm 可能不同。这个方法在输出跟踪问题中很直接新增的状态就是被控输出本身你可以直接在代价函数里惩罚 y(ki)-r而不需要额外从预测输出向量中提取。它本质上把输出积分状态显式建进了模型而不是靠外部累加 u。这跟输入增量扩维法状态里放 u_prev是不同的思想一个把执行机构位置当作状态一个把输出误差的积分当作状态。两者都有积分作用但数值特性、状态可观测性和对应的观测器设计差别很大。4.2 观测器设计对公式选择的影响实际系统状态往往不能全测需要设计状态观测器。这时增量式MPC的状态构成会直接影响观测器设计。扩维状态法里包含 u(k-1)这个信号是控制器已知的完全可以当作已知输入处理所以观测器只需观测原始 x。若把 z 整体交给观测器其中 u_prev 已经是精确已知值等于增加了一个虚拟的“无噪声状态”观测器设计简便。全增量法的状态包含 Δx 和 y。其中 y 通常是传感器直接测到的输出可作为已知量注入观测器Δx 则需要估计。这时候状态方程里出现了 y(k) 到下一状态 y(k1) 的传递观测器矩阵不再是标准形式需要仔细配置。如果状态维度低、系统阶次小两者都能用但换成高阶系统我建议优先考虑扩维法工程实现上更容易处理。4.3 计算量与数值稳定性分析从矩阵维度看扩维法增广状态维度是 nm全增量法增广状态维度是 np。一般 m 和 p 都远小于 n所以计算量差异不大。但要注意如果输出数量 p 很大比如有多路输出全增量法状态维度会明显增加QP 的预测矩阵 Ψ 会变胖求解变慢。而扩维法状态维度取决于输入数量 m跟输出数无关。因此多输出系统用扩维法更有优势。数值稳定性方面扩维法把 u_prev 作为状态状态矩阵中会出现单位阵块特征值稳定全增量法中由于新增输出积分状态系统矩阵会有位于单位圆上的特征根离散积分器。MPC 预测时这个积分状态可能因为模型失配导致缓慢漂移尤其是存在测量噪声时输出积分状态可能累计噪声造成控制量漂移。解决方法是给积分状态设置抗饱和机制或者在Q中降低对积分状态初值的敏感度。这些细节教科书里很少提但工程上非常关键。5. 调参与踩坑记录增量式MPC常见问题速查为了让你少走弯路我把调参和写代码时撞过的坑整理成速查表现象可能原因排查与解决方法初始时刻控制量跳变过大状态扩维时 u_prev 初值设定不合理把 u_prev 初始化为当前稳态工作点附近的控制量而不是0系统稳定但是有静差模型里没有真正引入积分作用检查是否以 Δu 为决策变量代价函数里是否把 Δu 作为变量而非 u控制量高频抖动Rdu 过小或者约束中 Δu 上限过松增大 Rdu或调小 du_max必要时加入输出变化率惩罚扰动后恢复太慢预测时域太短/输出权重过低增大 Np或者提高 Qy但注意别引起振荡状态不可观导致控制发散全增量法未处理积分状态优先用扩维法或给积分状态加观测器修正带 D 项的模型预测输出公式错输出预测时漏了 D*du 项检查输出表达式修正预测矩阵或者在QP中加补偿项quadprog报错“Hessian must be positive definite”H_qp 中 Psi’QyPsi 可能半正定加上 Rdu 后仍奇异比如 Rdu 有0确保 Rdu 为正定或加最小正则化如 1e-6*eye5.1 控制器初始化和冷启动问题增量式MPC启动时u_prev 怎么设很关键。如果对象本来就运行在一个稳态u_prev 应该用当前实际控制量而不是默认0。我一开始用0结果第一步 Δu 需要从0跳变到稳态控制量附近如果稳恒控制量比较大直接触发 u 幅值约束导致初始响应出现奇怪的非线性。正确做法是启动控制器前先记录一次执行机构反馈值作为 u_prev 初始值。5.2 预测时域与控制时域的配合增量式MPC对Horizon的敏感程度高于普通MPC。Nc 太小时控制自由度不足积分作用发挥不出来Nc 太大QP求解变慢且过大的 Nc 可能造成过度调节。我的经验是 Nc 选在系统主导时间常数对应采样步数的10%~20%Np 选 Nc 的3~5倍。比如采样周期0.1s系统时间常数约1s那么 Np 取15~20Nc 取3~5。这个组合鲁棒性比较好。5.3 权重矩阵调节技巧Qy 决定输出跟踪能力Rdu 决定执行机构活动强度。一个直观思路先把 Rdu 设为0看系统最快动态下的控制量是否可接受然后逐渐增大 Rdu直到控制量变化幅度降到一个顺眼的水平。实际运行中若稳态时有轻微噪声可以在输出误差项基础上加入一个对输出变化率的惩罚抑制噪声传到控制端效果比单纯调大 Rdu 更细腻。5.4 增广状态导致的可观性与数值问题扩维法状态矩阵中出现了单位阵块模型本身是可控的但也可能存在数值病态。比如 A 中某些元素数量级差异很大计算预测矩阵时会产生大数吃小数。建议在构造预测矩阵前先对模型做离散化尺度归一化或者用平衡模型balreal预处理。全增量法的积分状态在数值上容易累积误差连续长时间运行时要考虑定期重置积分状态或增加状态估计修正。5.5 MATLAB实现中的典型Bug我写代码时遇到过几个经典bug用 kron(eye(Np), C) 构造输出块对角矩阵时C 的维度搞错导致 Phi 维度不匹配。在约束矩阵 T_cum 中把 Np 和 Nc 搞混累积矩阵成了 Nc 行程序还能跑但实际控制序列不对且难以察觉。把 quadprog 的 H_qp 少乘了2目标函数等效问题不大但最优解受约束影响时会有偏差。仿真时输出取 x(k) 还是 x(k1) 不一致导致延迟一拍控制器误以为模型有滞后。忘了在每次循环里更新 u_prev导致控制器输出的不是累计值而是纯增量这会让系统变成纯积分控制极易发散。针对最后一个坑我后来会把“更新 u_prev”这行代码放在仿真函数的前面并用 assert 检查 u 的连续性。6. 后续扩展思路非线性系统、自适应MPC等6.1 从线性MPC到线性时变MPC增量式状态空间公式很容易扩展到线性时变系统LTV-MPC只需要在每个采样时刻更新 A(k), B(k) 并重新构造预测矩阵。比如对非线性系统在工作点线性化得到 A_lin(k), B_lin(k)然后用同样的增量公式生成扩维模型。此时预测矩阵 Ψ 的构造依赖各步的时序模型不能再用不变矩阵Matlab里可以逐步组装但计算量明显上升。我建议用 MATLAB function 块或者生成 C 代码后部署到实时仿真器里。6.2 与无模型方法结合的实现方向增量式MPC中的 Δu 思想也可以迁移到无模型自适应控制、数据驱动预测控制中。例如不再显式建模 A,B而是通过历史数据估计预测矩阵或者直接学习增量模型 f(Δu, Δx)本质上仍然是利用“增量”作为决策变量来减少模型误差带来的静差。我最近在尝试用神经网络拟合被控对象的增量动态再把预测控制问题套进去思路类似但计算负担更重适合离线训练加在线快速推理。最后再分享一个我个人的小习惯做MPC仿真时把不同公式的控制器封装成统一的接口输入 A,B,C,D、时域参数、权重、约束输出控制量。这样后续换模型、换控制器只需要替换底层预测模型函数不用改动主循环。我最初为了比较扩维法和全增量法写了两套完整循环结果调参时要改两处对比起来非常痛苦。后来重构成接口形式工作量减少了一半也更容易定位差异到底是公式本身还是代码实现造成的。这个项目做完我最大的体会是MPC公式看似复杂但核心就是“怎么把积分作用装进预测模型”。输入增量法给出的答案很优雅把控制增量当成决策变量状态空间自然扩维。只要吃透了扩维这一步后面所有推导和代码都是水到渠成。希望这篇分享能帮你跨过这个坎早日造出自己顺手的状态空间增量MPC控制器。