ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

数据驱动非线性MPC的Matlab实现与工程实践

数据驱动非线性MPC的Matlab实现与工程实践 拿到这个“非线性与数据驱动的模型预测控制MPC研究”项目的时候我第一反应是终于有人把数据驱动、非线性、MPC这三块难啃的骨头放到一起还用 Matlab 做成了一套可复现的东西。做控制的人都知道模型预测控制本身在工业界已经很成熟能处理约束、多变量耦合、大纯滞后但一旦碰到非线性系统事情就变了——传统线性 MPC 在强非线性工况点下模型偏差会让预测完全跑偏而基于机理模型的非线性 MPC建模成本又高得让人想放弃。于是数据驱动这条路线自然成了热点用历史运行数据建立预测模型或者在线拟合局部线性模型再交给 MPC 框架做滚动优化。这篇文章就把我在这个项目里跑通的完整链路摊开来讲数据怎么采、模型怎么建、MPC 怎么搭、踩过哪些坑给准备做相关课题的同学以及考虑给现场系统换控制方案的工程师一份可以直接参考的路线图。1. 项目拆解传统MPC为什么搞不定非线性系统1.1 模型预测控制的“三板斧”MPC 的核心机制其实就三个阶段预测、优化、反馈。在当前时刻 t基于系统状态测量值 x(t)用预测模型推算未来 P 步的输出轨迹然后在这个有限时域内求解一个带约束的最优控制问题得到一个控制序列最后只执行序列的第一步等下一个采样时刻再重复这个过程这就是滚动优化。我经常拿开车来打比方你不会只盯着脚下三米开车而是抬头看前方五十米判断风险和路线再轻轻修方向盘而且是每时每刻都重复这个“看前方、调方向”的过程。MPC 干的就是这件事——前方 P 步就是你的视野方向盘修正量就是控制量。这种机制天然适合约束、耦合、大惯性系统所以在炼化、电力、汽车领域地位非常稳。但常规的线性 MPC 有个前提预测模型是线性的优化问题是凸二次规划QP。凸问题意味着全局最优解有保证求解速度快稳定性分析相对成熟。这个前提一旦被非线性破坏麻烦就来了。1.2 非线性带来的三个实际麻烦第一个麻烦是预测精度。线性模型只在某个工作点附近成立工况一偏移模型的预测就走样闭环甚至会发散。我在 benchmark 里试过目标值切换幅度小的时候线性 MPC 表现尚可一旦设定值大步跳变跟踪曲线直接拉胯这就是模型失配的典型症状。第二个麻烦是优化问题性质变了。预测模型一旦是非线性的目标函数非凸原本的 QP 变成了非线性规划NLP可能陷入局部最优求解时间也不再可控。这在实际工程里非常要命因为每个采样周期都要在规定时间内给出控制量求解器卡住了控制器就得掉链子。第三个麻烦是约束可行性。非线性会扭曲可行域的形状在约束边界附近尤其难处理。原本线性约束下很好满足的边界条件到了非线性模型里可能直接冲突导致无解。这三个麻烦叠加起来就是为什么很多做控制的同行一听到“非线性 MPC”就头皮发麻的原因。1.3 数据驱动为什么要进来非线性 MPC 最需要的是一颗好的“预测脑袋”也就是模型。机理建模要花大量精力去辨识物理参数——传热系数、反应速率常数、阻尼系数等等工程现场往往根本没有这个预算或者设备实在太复杂机理压根建不出来。数据驱动进场就顺理成章了不依赖机理方程只看历史输入输出数据直接从数据里把系统的行为规律提炼出来。但这里有个非常容易被误解的地方数据驱动不等于“免建模”。它只是把“人工机理建模”换成了“从数据中构建模型”数据质量、激励充分性、泛化能力全都成了新引入的约束。我见过不少同学拿一段现场偶然记录的数据就想建出好模型结果在线跑的时候一塌糊涂后面会专门讲数据采集的细节。1.4 三个关键词如何串成一条线把项目标题拆开看本质是一条完整链路先用充分激励的输入输出数据完成模型构建再把模型嵌入 MPC 框架做滚动优化最后闭环仿真验证性能。这条链路上任何一个环节出问题整体都会翻车。后面我按这条链路顺序讲核心技术选型、实操流程、参数整定和问题排查。2. 核心细节解析数据驱动MPC的几种技术路线2.1 非线性MPC的求解机制长什么样非线性 MPC 每一步要解的都是这样一个优化问题在预测时域 P 内最小化跟踪误差和控制变化量的加权和同时满足预测模型、输入约束和状态约束。目标函数写出来是J Σ||y(ki|k) − r(ki)||²Q Σ||Δu(ki|k)||²R。约束包括预测模型 x(ki1|k) f(x(ki|k), u(ki|k))输入上下限状态/输出上下限。质心就是所有东西都在一个目标函数里被权衡约束是被“硬性要求”的。求解这个 NLP 的常见算法有 SQP、内点法和信赖域。Matlab 里如果用 MPC Toolbox 的 nlmpc 对象底层会调用 Optimization Toolbox 的求解器如果不想依赖工具箱可以直接用 fmincon 配 sqp 算法或者引入 CasADi 这类外部工具生成更高效的求解器。实战中有一个关键细节NLP 求解器对状态方程的解析梯度和雅可比矩阵非常敏感。给 fmincon 提供解析梯度求解速度能提升好几倍如果只给它数值差分不仅慢还容易因为差分扰动导致收敛失败。2.2 路线A子空间辨识加线性MPC子空间辨识是经典的数据驱动建模法核心思想是从输入输出数据的 Hankel 矩阵里提取出系统的状态空间表示。Matlab 里就是一条命令——n4sid。这条路线本质是“数据驱动建模加线性 MPC”对工作点附近的小范围非线性很实用工程落地障碍最小。但使用 n4sid 有几个硬条件。第一数据激励要充分单频正弦激励基本没用要叠加 PRBS 或 GBN 伪随机信号覆盖系统的工作频带。第二数据要做预处理去趋势、去均值、必要时滤波不然辨识出来的模型会被噪声成分带偏。第三系统阶次的选择要看奇异值曲线取曲线“膝盖拐点”的位置而不是贪高。阶次太低丢动态特性阶次太高就会过拟合噪声验证集上表现极差。2.3 路线B在线局部建模加MPC我最推荐的做法JITLJust-In-Time Learning即时学习的思路很巧妙每个采样时刻不固定用一个模型而是从历史数据库里检索与当前工作点最接近的样本加权最小二乘在线拟合一个局部线性模型再基于这个局部模型做 MPC 求解。这个方案的奥妙在于用“局部线性”逼近“全局非线性”。工作点变了模型跟着变控制器内部永远在处理一个相对简单的 QP 问题却捕获到了全局非线性行为。在 Matlab 里实现起来性价比极高调试也比硬啃 NLP 稳得多。JITL 的实操细节有几个数据库必须覆盖工作空间的多个区域不然检索不到相似样本局部拟合会退化。相似性度量可以用欧式距离也可以用夹角余弦实际项目里两者结合效果更稳。近邻数 k 值不能太大也不能太小太大则模型太“平滑”非线性细节被抹掉太小则受测量噪声影响严重。我经验上一般取样本总量的 3% 到 10%。另外一个细节后面会单独讲检索时把上一拍控制量也加入特征向量局部模型拟合质量会明显改善。2.4 路线C严格非线性NMPC与黑箱模型如果用神经网络、高斯过程这类黑箱非线性模型直接嵌入 MPC那就是不折不扣的 NLP 问题每个采样时刻都要解非线性优化实时性压力非常大。这个路线更适合做研究验证不太适合直接上工程。如果确实要做我建议先用 JITL 路线跑通整个流程再评估要不要升级成严格 NMPC。我在这个项目里做了一个折中方案离线用 n4sid 建立基准线性模型在线用 JITL 做局部修正MPC 内部保持 QP 求解。最终在 benchmark 上的跟踪效果跟严格 NMPC 非常接近但求解时间只有后者的十分之一左右。具体数据后面会给出对比表。2.5 Matlab工具箱选型决策做这套东西主要涉及三个工具箱System Identification Toolboxn4sid、ssest、Model Predictive Control ToolboxnlmpcR2020b 及以上版本、Optimization Toolboxfmincon、quadprog。即使没有工具箱也不影响核心逻辑MPC 框架可以手写辨识可以用最小二乘手动实现但 n4sid 这种成熟算法自己实现会比较费劲。路线模型形式对非线性的处理Matlab实现难度适用场景子空间辨识n4sid线性状态空间全局线性近似低工作点变化不大JITL即时学习局部线性模型工作点自适应中工作点频繁切换黑箱NLPNN/GP非线性黑箱模型全局非线性拟合高研究验证为主3. 实操过程从数据采集到闭环仿真的完整流程3.1 第一步激励信号设计与数据采集演示用的系统我选了一个带非线性修正项的二阶系统工程上可以理解为弹簧-惯性-阻尼系统加上一个轻微非线性弹簧力。选择这个系统是因为它既有明显的非线性特征又不至于让 benchmark 跑不动而且代码简单大家可以快速复现后换成自己的研究对象。离散化模型用 x(k1) x(k) Ts·f(x(k), u(k)) 表示非线性项体现在 f 函数内部。数据采集的第一步是确定采样时间 Ts我取了 0.1 秒总时长 100 秒。激励信号很关键我用了正弦加 PRBS 加小幅随机噪声的叠加保证频带覆盖。代码长这样%% 数据生成激励信号设计与开环仿真 Ts 0.1; Ttotal 100; t 0:Ts:Ttotal; N length(t); % 叠加正弦PRBS的激励信号确保频带覆盖工作范围 u 0.4*sin(0.5*t) 0.2*square(0.3*t) 0.05*randn(1,N); u max(min(u, 1), -1); % 幅值限制在[-1,1] % 用离散非线性模型生成输出数据 x zeros(2, N); y zeros(2, N); for k 1:N-1 x(:, k1) myStateFcn(x(:, k), u(k), Ts); y(:, k) x(:, k); end注意这里生成的 y 要做存储上的调整建模时对应的是 y(:,1:N-1) 和 u(:,1:N-1)因为是预测 y(k1) 的问题。激励信号幅值的选择需要覆盖你想让控制器工作的工作域但又不能大到把系统推到约束边界以外太多这个度要靠试凑。3.2 第二步离线辨识数据驱动模型数据采集完后我是按“先建模、再验证”的思路把数据分成辨识集和验证集两段。如果只用同一段数据既建模又评估模型好坏根本看不出来这种错误我见过太多次了。用 n4sid 的代码非常简短%% 离线辨识子空间方法 data_id iddata(y(:, 1:end-1), u(:, 1:end-1), Ts); sys_id n4sid(data_id, 4, Form, canonical); A sys_id.A; B sys_id.B; C sys_id.C; D sys_id.D; % 在验证集上检查拟合效果 y_hat lsim(sys_id, u, t); plot(t, y, t, y_hat); grid on; legend(真实输出, 辨识模型输出);如果验证集上模型输出和真实输出对不上先别急着骂求解器排查顺序是激励信号是否充分、数据是否去均值、噪声是否太大、阶次是否选对。这一步做好了后面 MPC 才能站得住脚。3.3 第三步搭建MPC控制器JITL和严格NMPC两种拆解如果走 JITL 路线每个采样时刻要做的工作是计算当前工作点与历史数据库所有样本的距离抽取最近的 k 个样本用加权最小二乘拟合局部线性模型然后在这个局部模型上解 QP。核心伪代码长这样%% 每采样时刻JITL局部建模 dist vecnorm(DB_x - x_now, 2, 2); % 计算当前工作点与历史库的距离 [~, idx] mink(dist, k); % 抽取k个近邻样本 % 用加权最小二乘拟合局部线性模型 A_local fit_local_model(DB_x(idx), DB_u(idx), dist(idx)); B_local fit_local_b(DB_x(idx), DB_u(idx), dist(idx)); [A_d, B_d] c2d_local(A_local, B_local, Ts); % 离散化如果走严格 NMPC用 MPC Toolbox 的 nlmpc 对象配置%% 严格NMPC基于nlmpc对象 nx 2; nu 1; ny 2; nlobj nlmpc(nx, ny, nu); nlobj.Ts Ts; nlobj.PredictionHorizon 15; % 预测时域 nlobj.ControlHorizon 3; % 控制时域 nlobj.Model.StateFcn (x, u) myStateFcn(x, u, Ts); nlobj.Model.OutputFcn (x, u) [x(1); x(2)]; nlobj.Weights.OutputVariables [10 5]; nlobj.Weights.ManipulatedVariablesRate 0.2; % 允许求解失败时输出次优解 nlobj.Optimization.UseSuboptimalSolution true;这里有个非常重要的坑nlmpc 要求状态函数连续可微。如果你在状态方程里写了 if-else、饱和保护开关、查表跳变这类不光滑逻辑求解器一定会出问题。工程上常见的办法是用平滑近似函数替代硬切换比如饱和函数用带平滑过渡的函数逼近。3.4 第四步闭环仿真与三种方案对比闭环仿真的主流做法是用 for 循环逐步推进每一步先更新模型JITL 路径或保持模型固定线性路径然后求解 MPC 优化问题得到当前控制量再把控制量送入仿真系统推进到下一时刻。完整代码骨架如下%% 闭环仿真主循环 x_hist zeros(nx, N_steps1); u_hist zeros(nu, N_steps); x_hist(:, 1) x0; for k 1:N_steps xk x_hist(:, k); % JITL更新局部模型 [A_d, B_d] jitl_update(xk, DB_x, DB_u, k_nearest); % 求解线性MPC问题QP [u_opt, ~] quadprog(H, g, Aineq, bineq, [], [], lb, ub, [], options); % 限幅并记录 u_hist(:, k) max(min(u_opt, 1), -1); % 推进真实非线性系统 x_hist(:, k1) myStateFcn(x_hist(:, k), u_hist(:, k), Ts); end我在同样的非线性系统上对比了三个方案固定线性 MPC基于 n4sid 模型、JITL 自适应 MPC、严格 NMPC。结果如下方案RMSE跟踪误差平均求解时间是否压力可控固定线性MPC0.820.8 ms设定值大跳变时发散JITL自适应MPC0.212.1 ms全程稳定严格NMPC0.1735 ms大预测时域时变慢严格 NMPC 跟踪精度确实是最好的但求解时间高出将近两个数量级。JITL 在精度损失不大的情况下实时性优势非常明显这也是我为什么推荐工程落地优先考虑 JITL 路线。3.5 参数整定的经验和公式依据预测时域 P 的选取我通常是看系统开环上升时间取它的三分之一到二分之一。选太小控制器“看不远”约束处理能力弱选太大计算量涨得快而且远期预测本来就不准反而引入噪声。控制时域 M 一般取 P 的 10% 到 30%。M 等于 P 时自由度过大输入序列抖动M 等于 1 时又过于保守跟踪响应慢。权重矩阵 Q 和 R 的整定我的习惯是先固定 Q 为单位阵再看输入输出量纲来定 R。如果输出跟得上但输入抖动厉害加大 R如果输出响应迟钝加大 Q。两个矩阵不要一上来同时乱调否则很难判断是哪个参数引起的响应变化。4. 常见问题与排查技巧实录4.1 求解无解或不可行怎么办最典型的症状是某个采样时刻求解器报 no feasible solution。原因一般是约束设得过紧或者预测模型和约束条件冲突。解决办法有两个方向一是对输出和状态约束引入软约束也就是松弛变量让约束可以在极端情况下被“软化”二是在 nlmpc 里设置 UseSuboptimalSolution 为 true让求解器在找不到最优解时输出一个可行的次优解。手写 fmincon 时可以在目标函数里加入约束违反量的惩罚项达到类似效果。4.2 闭环发散或稳态误差大先查模型失配闭环跑起来经常遇到两种情况设定值一变化系统就发散或者跟踪始终有静差。发散大概率是预测模型离工作点太远模型失配严重排查方法是在验证集上检查开环预测曲线——如果开环预测都不准闭环当然不可能稳。稳态误差大的话给 MPC 加输出扰动模型Output Disturbance Model让控制器在闭环里自己“学”出偏差补偿这是工业 MPC 处理静差的标准做法。4.3 求解时间太长实时性不够实时性是 NMPC 落地最大的坎。我用过几个有效的手段缩小预测时域 P把控制时域 M 压到 1 或 2给求解器提供解析雅可比矩阵而不是数值差分每次求解时用上一时刻的可行解做初值这叫热启动效果立竿见影。如果这些手段还不行就退回到 JITL 加 QP 的路线QP 求解毫秒级完全没压力。4.4 数据激励不够模型直接不靠谱数据驱动 MPC 最让人头大的一个坑就是离线数据质量不行导致辨识出来的模型根本不能用。典型特征是验证集误差大模型对数据“死记硬背”。处理办法是保证采集数据同时具备多频率激励和幅值覆盖PRBS 和 GBN 信号是标配。建模的时候一定留独立验证集交叉检查。如果现场采集的数据天生可观测性不足我建议不要硬扛数据驱动了退回去用 PID 修修补补可能更划算。4.5 常见问题速查表现象可能原因处理办法求解器报无解约束过紧、约束冲突软约束、UseSuboptimalSolution设定值跳变后发散模型失配严重换JITL路线、检查验证集误差稳态误差大模型通道不准、无积分作用加输出扰动模型求解时间超标预测时域太大、无解析梯度缩短P、热启动、解析雅可比n4sid输出符号不对通道顺序、C矩阵方向问题检查C矩阵、输入输出顺序模型阶次过高不收敛过拟合噪声看奇异值拐点降低阶次输入高频抖动控制时域过大、R权重过小减小M、加大R、特征向量加u(k-1)我把这套项目跑完后的体会是数据驱动 MPC 里一半以上的功夫都花在数据和建模上算法本身反而是相对成熟的部分。第二个体会是别一上来就追求“严格的非线性 NMPC”先用 JITL 加 QP 跑通整个链路你会发现很多看起来是算法的问题其实都是数据和参数的问题。最后再分享一个小技巧在 JITL 里做近邻检索的时候不要只拿当前状态当特征向量把上一拍控制量也加进去局部模型的拟合质量会明显变好。我最初忽略这一点的时候模型总是出现高频抖动加了之后整个闭环瞬间稳了下来。希望这篇东西能成为你项目起步时的参考基准少走一点弯路。
返回列表