ARTICLE DETAIL

资讯详情

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

CFDL-MFAC无模型自适应控制原理与Matlab/Simulink仿真实现

CFDL-MFAC无模型自适应控制原理与Matlab/Simulink仿真实现 做控制仿真的工程师看到“无模型自适应控制”这几个字第一反应往往是两个极端要么觉得它太玄不建立机理模型怎么谈控制要么把它当成一个黑箱控制器仿真跑通就完事。我这次把基于紧格式动态线性化CFDL的 MFAC 无模型自适应控制完整做了一遍从控制律推导到伪偏导数在线估计再到 Matlab 脚本和 Simulink 闭环仿真一次性跑通过程中踩了几个典型的坑。这篇就围绕 CFDL-MFAC 这套方法把“为什么能无模型”“伪偏导数到底在估什么”“代码怎么写才不踩坑”三件事讲透。1. “无模型”到底是什么CFDL-MFAC 的控制对象观1.1 传统建模链路在哪里栽了跟头传统思路做控制路径通常是先对被控对象做机理建模把物理规律写成微分方程或差分方程然后辨识参数最后基于模型设计控制器。问题也出在这一步现实里很多对象的机理并不清晰可能是黑箱也可能只有输入输出数据。更麻烦的是系统参数可能在运行中漂移比如温度变化、负载切换、机械磨损都会让一套好不容易辨识出来的模型失效。自适应控制解决了一部分问题但它的核心假设仍然是对象结构已知、只有若干参数未知适应算法本质上是去辨识那一组“真参数”。如果模型结构选错了辨识出来的参数再准也没有意义。MFAC 换了一个视角它不追求把系统的全局模型“认出来”而是在每个工作点附近用一个带时变参数的等价数据模型去描述系统的输入输出关系。这个时变参数不需要知道机理含义只要求它能反映当前工作点附近的增量关系然后在线更新。1.2 紧格式动态线性化一段一段地把系统描出来CFDL 是 MFAC 里最简明的动态线性化形式英文全称是 compact form dynamic linearization。它针对单输入单输出非线性离散系统给出一个非常紧凑的等式y(k1) - y(k) φ(k) · [u(k) - u(k-1)]这个式子把相邻两个时刻的输出变化直接和相邻两个时刻的输入变化联系起来。等号右边的 φ(k) 就是伪偏导数它是时变的、有界的、每个采样时刻都不同的一个标量。注意这个等式不是对原系统做的全局近似它只在当前时刻附近的局部成立所以叫“紧格式”。为什么可以这么写本质上是在用“斜率”替代“曲线”。就好比你在山路开车GPS 不需要给你整座山的三维模型它只要知道当前这一小段路的坡度就能判断车速该怎么调。CFDL 里的 φ(k) 就相当于每一小段的坡度系统工作点一变这个坡度也跟着变控制律就按新的坡度重新算。对系统本身的要求也不高通常需要系统输出相对输入满足广义 Lipschitz 条件说白了就是输入变化不能无限大否则输出会失控这在实际工程里是自然成立的。模型也不要求线性、不要求时不变、不要求最小相位适用范围比传统线性模型宽得多。1.3 伪偏导数到底是偏导数吗名字里带“导数”但它不是机理模型里对某个物理量求偏导的结果而是一个跟系统状态、输入、输出都有关的时变系数所以叫“伪”。对单输入单输出对象来说φ(k) 可以理解为输入增量到输出增量之间的局部增益方向也由它的符号体现。有一点很重要φ(k) 的符号并不一定永远保持正。如果一个系统在某个工作点附近是正的局部增益φ 就是正的如果系统进入反向特性区域比如某些非线性阀、磁滞机构、或者非最小相位环节φ 就可能变号。这个现象后面会直接关系到伪偏导数估计器的重置机制做仿真时很容易忽略但忽略的后果往往是控制量发散。2. 控制律与伪偏导数估计一次推导全部理顺2.1 控制器要最小化的那个目标有了紧格式动态线性化模型控制器设计就变成了一个在线求解优化问题。控制目标很直观让下一步输出尽量贴近期望值同时不要因为控制量变化太猛而破坏局部线性化假设。准则函数一般写成J(u(k)) [ y*(k1) - y(k1) ]² λ · [ u(k) - u(k-1) ]²第一项代表跟踪误差第二项是控制增量的惩罚。λ 是控制增量权重它不只是数学上的正则化实际作用非常明确当伪偏导数估计值 φ_hat(k) 很小、甚至接近零时如果 λ 也是零控制量会瞬间飙到非常大系统直接失去稳定性。λ 把这种情况“压住”保证控制律在数值上一稳到底。同时这一步预测用的模型就是把 CFDL 等式做一个时间平移y(k1) y(k) φ_hat(k) · [ u(k) - u(k-1) ]代入准则函数时预测误差就用 y*(k1) 减去 y(k) 和 φ_hat(k)Δu(k) 两项。2.2 一步求导得到控制律把 J 对 Δu(k) 求偏导并令其等于零。过程虽然简单但值得自己推一遍推完才知道每个参数在什么位置起作用dJ/dΔu(k) -2φ_hat(k) [ e(k) - φ_hat(k)Δu(k) ] 2λΔu(k) 0整理后得到Δu(k) φ_hat(k) · e(k) / ( λ φ_hat(k)² )再乘一个步长因子 ρ得到最终的控制器形式u(k) u(k-1) ρ · φ_hat(k) · e(k) / ( λ φ_hat(k)² )这里 e(k) y*(k1) - y(k)注意用的是当前输出和下一步期望之间的误差信息。由于在仿真中参考信号通常预先给定y*(k1) 就是 k 时刻已知的未来值所以这个控制律在离散时间实现里没有任何超前仍然是一个因果可实现的控制器。2.3 PPD 估计器的递推式控制律里出现了伪偏导数估计值 φ_hat(k)它不能靠机理模型给出来必须用输入输出数据在线估计。估计器的目标同样是一个准则函数J(φ) [ Δy(k) - φ · Δu(k-1) ]² μ · [ φ - φ_hat(k-1) ]²第一项是拟合误差也就是用 φ 去解释“上一步输入增量造成了这一步输出增量”这个事实。第二项是惩罚 φ 相对于上一时刻估计值变化得过于剧烈μ 控制这个惩罚强度。对 φ 求导并令其为零再引入步长因子 η 方便调节收敛速度就得到递推估计式φ_hat(k) φ_hat(k-1) η · Δu(k-1) · [ Δy(k) - φ_hat(k-1)·Δu(k-1) ] / ( μ Δu(k-1)² )这个式子看着复杂拆开看就简单如果上一部的输入增量 Δu(k-1) 很小那么分母很小、修正增益很大但实际用处不大如果 Δu 很大整个修正项被分母稀释不至于一步跳太远。μ 在这里就是防止分母为零和抑制估计值突变的正则项。3. 伪偏导数在线估计里的三个“保命”细节3.1 符号判断与重置机制伪偏导数在线估计最容易翻车的地方不是递推公式写错而是忘了重置机制。工程里你不可能保证系统永远单调如果对象本身存在反向特性或者运行点跨过了极值区φ 的真实方向会发生改变。此时如果不干预估计器会在错误的方向上一直修正控制律也可能在错误方向上加大输出最终发散。标准做法是用一个很简单但非常有效的规则如果 φ_hat(k) 的绝对值小于某个很小的阈值 ε或者它的符号和初始值 φ0 的符号不一致就把 φ_hat(k) 重置回 φ0 或其他设定值。这个机制不是理论上的花架子我仿真时专门试过关闭重置结果大约在几百步之后控制量就冲到了十万量级数据曲线完全没法看。开了重置之后即使系统参数中途切换控制器也能在几十步内重新找回正确的方向。3.2 估计器中的 μ、η 到底在控制什么很多人调参数时容易把 η 和 μ 混在一起。实际上它们的作用完全不同η 影响修正步长η 越大估计值对新数据的反应越快但噪声也越容易被放大μ 是正则项控制的是“估计值不要跑太远”μ 越大φ_hat 的变化越平滑但跟踪真实非线性动态的速度也越慢。在仿真里如果发现 φ_hat 反复被重置绝大多数原因是 η 太大或 μ 太小导致估计值在真实值附近来回震荡然后频繁触发符号判断。反过来如果跟踪效果始终不好而且 φ_hat 长时间纹丝不动大概率是 μ 设置过大估计器对数据变化已经反应迟钝了。我一般先把 η、μ 都设为 1 跑通再根据 φ_hat 曲线的波动情况去调整。3.3 噪声环境下更新死区仿真用的对象模型如果只有纯 deterministics 输出更新死区可有可无但如果你加上了测量噪声伪偏导数估计器会很敏感。原因是估计式分母里只有 Δu(k-1)²没有考虑输出噪声。输入增量很小的时候噪声造成的输出波动会被当成有效系统动态去更新 φ_hat结果就是 φ_hat 在噪声里乱跳控制量跟着抖动。工程上的做法是加一个死区条件只有 |Δu(k-1)| 大于某个阈值时才执行 PPD 更新。阈值不能太大否则低频段也有更新延迟也不能太小否则死区形同虚设。通常取输入量程的千分之一到百分之一之间先跑一次仿真看数据分布再定。这个细节虽然不写在经典算法的基本式子里但做真正的仿真验证时非常实用。4. Matlab 脚本仿真CFDL-MFAC 全程可运行代码4.1 被控对象怎么选仿真研究里被控对象的选择直接影响你能否看出 MFAC 的优势。如果选一个线性定常对象那么最普通 PID 也能控制得很好CFDL-MFAC 反而显得多余。我建议选带典型非线性的对象经典选择是y(k1) a · y(k) / ( 1 y(k)² ) b · u(k)³第一项会产生饱和型非线性输出越大增益越小第二项是三次方输入非线性输入符号不同时增益方向完全不同。这样的对象既不为难仿真代码又能明显体现 MFAC 的局部线性化思路。中途还把 a、b 两个参数切换一次模拟对象特性漂移检验控制器的自适应能力。4.2 完整仿真代码下面这段代码可以在 Matlab 里直接运行目标就是完整跑一遍 CFDL-MFAC 的跟踪控制并把输出 y、控制量 u、伪偏导数估计值 φ_hat 三条曲线都画出来。clear; clc; close all; % 控制器参数 rho 0.5; % 控制律步长因子 lambda 0.8; % 控制增量惩罚因子 eta 1.0; % PPD估计算法步长因子 mu 1.0; % PPD估计惩罚因子 phi0 1.0; % PPD初值与重置值 % 被控对象参数中途切换一次 a 1.0; b 1.0; N 2000; % 参考信号三段不同电平 yr zeros(1, N); yr(1:500) 0.5; yr(501:1200) -0.3; yr(1201:N) 0.6; y zeros(1, N1); u zeros(1, N); e zeros(1, N); phiSeq zeros(1, N); phi_hat phi0; u_prev 0; u_prev2 0; for k 1:N % 在第900步切换对象参数检验自适应能力 if k 900 a 0.8; b 1.3; end e(k) yr(k) - y(k); % 伪偏导数在线估计 if k 2 dy y(k) - y(k-1); du u(k-1) - u_prev2; if abs(du) 1e-5 phi_hat phi_hat eta * du * (dy - phi_hat * du) / (mu du^2); end % 符号判断与重置 if abs(phi_hat) 1e-5 || sign(phi_hat) ~ sign(phi0) phi_hat phi0; end end % CFDL-MFAC 控制律 u(k) u_prev rho * phi_hat * e(k) / (lambda phi_hat^2); % 被控对象 y(k1) a * y(k) / (1 y(k)^2) b * u(k)^3; phiSeq(k) phi_hat; u_prev2 u_prev; u_prev u(k); end % 绘图 figure; subplot(3,1,1); plot(1:N, yr, --, 1:N, y(1:N), -, LineWidth, 1.2); legend(yref, y, Location, best); title(输出跟踪); grid on; subplot(3,1,2); plot(1:N, u, LineWidth, 1); title(控制输入 u); grid on; subplot(3,1,3); plot(1:N, phiSeq, LineWidth, 1); title(伪偏导数估计值 phi); grid on;4.3 代码里几个容易踩的索引细节这段代码看起来简单但索引细节稍不注意就会让结果出错。第一个是u_prev2的处理它对应 u(k-2)在 k1 时不存在我直接用初始化零来代替相当于零初值控制量。第二个是 PPD 估计更新用的是du u(k-1) - u_prev2也就是上上拍与上一拍之间的控制增量千万不要写成当前 k 时刻的增量否则控制律和估计器之间会出现一个拍的对齐误差跟踪曲线看上去也能凑合但伪偏导数估计值会一直滞后。第三个细节是绘图时用的y(1:N)而y数组长度是 N1最后一位是仿真结束后计算出来的 y(N1)不在参考信号序列里画图时要用前 N 个点。这类问题在 Matlab 仿真里极其常见一旦画出来的曲线头部或尾部对不齐先检查数组长度和采样时刻对齐。5. 把 CFDL-MFAC 搬进 Simulink 闭环仿真5.1 Simulink 模型的结构设计Matlab 脚本适合快速验证算法但要做系统性的仿真演示Simulink 的闭环结构更直观特别是需要展示信号流、模块连接、在线估计过程时。搭建方式并不复杂核心结构是参考信号 → 误差计算 → CFDL-MFAC 控制器模块 → 被控对象模块 → 反馈回到误差计算注意控制器的采样和执行必须和被控对象在同一个离散时间步上。我建议用固定步长求解器步长设为 0.01 秒控制周期和被控对象采样周期保持一致。这样 CFDL-MFAC 里的每一步 k都对应一个仿真采样点。如果被控对象是连续系统需要在控制器输出之后加一个零阶保持器把离散控制量变成连续信号再送入对象反馈输出侧再加一个采样保持把连续输出量化到离散时刻。很多仿真报告里省略了这个接口直接用连续对象模块和离散控制器模块相连Simulink 会自动插入采样跨越但很容易因为采样周期不匹配产生隐晦的时序问题。5.2 被控对象的离散 S-Function 写法为了让闭环时序完全可控我把被控对象写成离散 S-Function采样周期设为 0.01 秒。S-Function 文件如下function [sys,x0,str,ts] cfdl_plant_sfun(t,x,u,flag) switch flag case 0 sizes simsizes; sizes.NumContStates 0; sizes.NumDiscStates 1; sizes.NumOutputs 1; sizes.NumInputs 1; sizes.DirFeedthrough 0; sizes.NumSampleTimes 1; sys simsizes(sizes); x0 0; % 初始输出 y(0) str []; ts [0.01 0]; % 固定离散采样周期 case 2 % 离散状态更新y(k1) y(k)/(1y(k)^2) u(k)^3 sys x(1) / (1 x(1)^2) u(1)^3; case 3 % 输出当前离散状态 y(k) sys x(1); case {1,4,9} sys []; otherwise error([unhandled flag , num2str(flag)]); end注意DirFeedthrough被设为 0这意味着输出只依赖离散状态 x(1)不直接依赖输入 u。这一点对避免代数环很重要。如果你把被控对象写成 y(k1) f(y(k), u(k)) 且输出也直接用输入 u 计算Simulink 会在仿真初始化阶段检测到代数环求解器需要反复迭代才能解出结果不熟练的话很容易卡在配置阶段。5.3 控制器 MATLAB Function 块的写法控制器也可以写成单独的 MATLAB Function 块内部用 persistent 变量保存上一拍的输入输出和伪偏导数估计值。代码如下function uout cfdl_controller(yref, y) persistent phi_hat y_delay u_delay u_delay2 if isempty(phi_hat) phi_hat 1.0; y_delay 0.0; u_delay 0.0; u_delay2 0.0; end rho 0.5; lambda 0.8; eta 1.0; mu 1.0; phi0 1.0; % 计算当前输出增量与前一步控制增量 dy y - y_delay; du u_delay - u_delay2; % 伪偏导数在线估计 if abs(du) 1e-5 phi_hat phi_hat eta * du * (dy - phi_hat * du) / (mu du^2); end % 符号判断与重置 if abs(phi_hat) 1e-5 || sign(phi_hat) ~ sign(phi0) phi_hat phi0; end % 控制律 e yref - y; uout u_delay rho * phi_hat * e / (lambda phi_hat^2); % 更新持久变量 y_delay y; u_delay2 u_delay; u_delay uout; end这段代码和脚本版本的核心逻辑完全一样但要注意 Simulink 中的一个细节persistent 变量在仿真结束或模型修改后不会自动清除。如果你改完参数重新运行一次仿真发现伪偏导数初值已经不是 1控制曲线和第一次对不上那就是上一轮仿真的持久状态残留了。可以在模型初始化回调里加一行clear cfdl_controller或者在运行脚本最前面写一个 clear 函数养成习惯后能省不少排查时间。5.4 仿真步长与代数环的注意点Simulink 配置里有一个地方很容易踩坑把求解器选成了变步长而控制器和被控对象都是离散模块变步长求解器会在某些时刻插入额外的内部步长导致 CFDL-MFAC 的“第 k 步”和实际仿真时间步对不上。更稳妥的做法是在 Solver 配置里选择固定步长步长设为 0.01离散求解器类型选“discrete”这样每一拍就是一个明确的离散控制周期。另一个容易遇到的问题就是代数环。控制器的 MATLAB Function 是直接馈通模块因为它的输出 uout 会直接影响被控对象的输入而被控对象由于DirFeedthrough0输出是离散状态而不是输入的即时函数所以整个闭环不会形成瞬时依赖。如果你自己建对象模型时图省事用了一个纯 Gain 或 Fen 模块直接连接控制器输出和反馈回路Simulink 可能提示检测到代数环。不要慌把那条直通路径换成离散状态模块或者加一个 Unit Delay就能断掉代数环。6. 仿真结果怎么读跟踪曲线、控制量和 PPD 序列6.1 先说跟踪效果跑完上面的程序输出跟踪曲线的典型结果是这样参考信号在 0.5、-0.3、0.6 三个电平之间跳变输出 y 在前 40~60 拍之内就能跟上第一个电平不会出现明显超调当参考信号在 500 拍跳到 -0.3 时输出会有短暂回落过程但很快又进入稳态。系统的非线性项 y/(1y²) 让输出在接近 ±1 时会出现增益压缩所以如果参考电平选得过大比如 1.5跟踪速度会明显变慢这是对象自身特性决定的不是控制器失效。中途 900 拍切换对象参数 a、b 之后输出会出现一个小幅的瞬态偏差偏差大小通常比参考信号跳变时的偏差小很多因为工作点没变伪偏导数估计值也不需要做大幅调整。这说明 CFDL-MFAC 对参数漂移的处理能力明显强于固定参数控制器。如果你在 Simulink 里跑的模型也是这个对象得到的曲线形状应该和脚本版本几乎一致。6.2 再看伪偏导数估计曲线伪偏导数序列 φ_hat 的变化比跟踪曲线更值得看。它从初始的 1.0 开始经过大约几十拍的修正收敛到 0.2~0.5 附近这个数值大致就是对象在工作点附近的局部增益水平。注意它不会完全稳定成一条直线因为对象是非线性的工作点变化时真实局部增益也在变化所以 φ_hat 会跟着上下缓慢浮动。如果你看到 φ_hat 曲线出现密度很高的尖峰而且尖峰附近控制量也剧烈抖动不要急着调控制器参数先去查估计器更新条件。很多时候是因为dy和du的时间对齐错了或者离散仿真步长不一致导致估计器拿到的是错拍的数据。这类问题在脚本里不太会出现但在 Simulink 里因为采样模块的时序细节很容易被错误配置诱发。6.3 参数切换下的自适应行为对象参数切换的那一刻跟踪曲线不会立刻崩溃但伪偏导数估计值会有一个明显的调整过程。由于 a 从 1.0 变成 0.8、b 从 1.0 变成 1.3对象局部增益发生了改变原来收敛好的 φ_hat 不再准确估计器会利用切换后的输入输出数据重新修正。调整速度取决于 η 和 μ 的组合。如果你把 η 调成 2、μ 调成 0.1φ_hat 收敛会更快但曲线也会更毛糙反过来 η 调成 0.5、μ 调成 2φ_hat 平滑但参数切换后跟踪恢复时间会拉长。所以看结果时重点不是单看某一组参数下曲线好不好看而是理解 φ_hat 动态调整的过程。这也是伪偏导数在线估计研究的核心观察点估计器是否能在不依赖机理模型的前提下用输入输出数据把系统的局部动态“跟上”。7. 调参顺序和常见问题7.1 参数角色的对照做 CFDL-MFAC 仿真时参数不算多但每个参数的作用必须定位准确否则调参就是瞎猜。我把它们的角色整理成一张表参数所属环节主要作用取值太大取值太小ρ控制律调节跟踪速度超调、振荡响应过慢λ控制律抑制控制增量指令变化钝、响应慢控制量跳动剧烈ηPPD 估计调节估计收敛速度估计值波动大估计响应迟钝μPPD 估计对估计值变化加正则惩罚估计被过分平滑估计值易受噪声干扰φ0PPD 估计初值、重置基准影响初期收敛方向与速度同上这里特别注意 ρ 和 λ 是一对需要配合的参数。ρ 大、λ 小系统动作快但容易过冲ρ 小、λ 大系统稳但跟踪磨蹭。可以先固定一个调另一个不要两个同时猛调。7.2 常见的三种调参陷阱第一种陷阱是控制量过早饱和。CFDL-MFAC 控制律不含任何积分限幅处理如果对象本身存在执行机构限幅你必须在 Simulink 模型里加 Saturation 模块否则控制器输出的计算值会远超实际执行值而反馈回来的输出依然只反映了限幅后的控制效果伪偏导数估计器会被误导。这种“控制计算值 vs 实际执行值”的区分在仿真里很容易漏掉。第二种陷阱是伪偏导数频繁重置。如果你在仿真日志里统计 reset 次数发现它一直不为零说明估计器在正常跟踪阶段也触发了符号判断。这时候不要通过调大 phi0 来掩盖问题而要检查系统工作点附近是不是真的存在反向增益。如果系统正常单调那就是 μ、η 没配好让估计值在符号边界来回试探。第三种陷阱是死区设置过小。脚本里我用的是abs(du) 1e-5这是为了对付纯数值环境下的零增量情况。如果实际对象有测量噪声1e-5 这个阈值等于没有死区必须按输入量程比例放大。你可以先用一个开环数据流看一下 du 的取值范围再决定死区阈值而不是随手写一个固定值。7.3 我个人推荐的调参顺序先把对象在平衡点附近的增益方向确认清楚把 φ0 的符号设成与真实局部增益一致这一步做错后面再好的参数都挽救不回来。然后把 λ 设为 1、ρ 设为 0.5、η 和 μ 都设为 1先跑通整个闭环确认输出不发散、控制量在合理范围。第三步看跟踪速度如果太慢以 0.1 为步长逐步增加 ρ如果出现振荡回退 ρ增加 λ。最后一步再精调 PPD 估计器。观察 φ_hat 曲线如果波动过大把 μ 往 2 到 5 的方向调或者把 η 降到 0.5 以下如果 φ_hat 几乎不动、控制性能始终上不去把 μ 减小到 0.1 到 0.5 试试。调参中最忌讳的是同时改多个参数。每改一个参数都维持其他参数不变运行一次仿真记录跟踪最大误差、控制量变化幅度、伪偏导数重置次数三个指标。这三个指标能帮你定位问题是出在控制律环节还是估计环节。控制律环节的问题通常表现为跟踪误差大但 φ_hat 平滑估计环节的问题通常表现为 φ_hat 乱跳而跟踪误差反而不见好转。我个人做完这套仿真后最大的体会是CFDL-MFAC 的门槛其实不在算法本身而在你是否愿意把伪偏导数估计序列当成一个正式输出量去检查。很多人只盯着 y 的跟踪曲线看到跟踪得不错就以为万事大吉结果控制量和 φ_hat 早就乱成一片。做研究性质的仿真建议把 u 和 φ_hat 连同 y 一起画出来三张图放在一起看才能真正判断一套参数是好是坏。后续如果再加上时变时延、外部扰动和执行机构饱和这套框架还有不少可以继续深挖的空间。
返回列表