“真要让我把这个非线性对象建模,我宁愿不控制。”这是我在某个仿真项目卡了整整一周模型后最真实的想法。也正因如此,我第一次看到MFAC无模型自适应控制时,反复确认了好几遍:仅靠I/O数据,通过CFDL、PFDL、FFDL三种动态线性化方法,就能对非线性系统做稳定的跟踪控制?这听起来确实像一个“作弊器”,但它是真的能复现的。
用一句话概括MFAC的思路:不试图建立全局精确模型,而是在每个采样时刻用一个“动态线性化”模型去逼近被控对象的局部行为。这就像在浅水区过河,每一步先伸脚试探当前水深,而不是先花大力气把整条河的河床形状测量清楚。本文就沿着这条主线,把CFDL、PFDL、FFDL三种形式从原理讲到Matlab代码实现,再把我在复现过程中踩过的坑和调参经验一起整理出来。适合正在做数据驱动控制、非线性控制研究,或者需要快速上手MFAC仿真代码的同学参考。
1. MFAC的“无模型”底气:动态线性化与被逼出来的自适应
1.1 传统控制建模的真实困境
做控制仿真的人应该都有这种经历:拿到一个非线性对象,第一反应是找它的数学模型。常见的路子是先做机理分析,列微分方程,再用实验数据辨识参数。这一套流程在对象结构清晰、参数稳定时没问题,但一旦对象是化工过程、液压系统、机电耦合这种强非线性、强耦合、参数时变的东西,模型就变成了最大的麻烦。模型阶次选低了,控制器设计出来压不住实际对象;阶次选高了,参数辨识又发散。最后论文好看,实物一跑就原形毕露。
这也是自适应控制、MPC等经典方法在工业现场经常“水土不服”的原因——它们好不好用,很大程度上取决于你手上那个模型准不准。哪怕是无模型控制这个名头下的许多方法,实际上依然需要部分模型信息,比如线性化基准模型、扰动估计模型等。真正不看模型,只盯着I/O数据做控制的方案里,MFAC是理论体系比较完整的一支。
1.2 动态线性化到底是什么
MFAC的核心动作,是在每一个采样时刻对被控对象做一次“动态线性化”。注意,这跟传统控制里的工作点线性化完全不同。传统线性化是在某个稳态点附近求雅可比矩阵,得到一个固定模型,一旦工作点漂走,模型就失效。MFAC的动态线性化不依赖某个固定工作点,它只用当前最新的输入输出数据,在线估计一个时变的线性化系数,这个系数被称为伪偏导数或者伪梯度。
为什么叫“伪”?因为它并不保证对应对象真实的物理梯度,它只是一个数学推导出来、能维持输入输出数据等价的等效增益。既然伪,自然不要求你对被控对象的物理机理有多少先验知识。更重要的是,这个等效增益是随着系统状态不断更新的,所以哪怕对象本身是强非线性、强时变,只要每一步都重新估计,线性化模型就能在局部“咬住”真实系统。
我比较喜欢用一个开车的例子来理解这件事。CFDL好比你只知道当前油门增量对车速增量的影响,用一个等效灵敏度踩油门;PFDL则类似你不仅看当前踩油门的力度,还会结合过去几秒的油门变化来判断车速变化趋势;FFDL则更全面,会把过去几秒的车速变化和油门变化一起纳入判断,相当于你既看路况变化,也看自己脚下动作的累积后果。这样想,三种方法的差异就非常直观了。
1.3 MFAC闭环的三个动作
抛开繁琐的数学,MFAC闭环控制的每个采样周期里就做三件事:
- 采样当前输出y(k),与期望值y*(k+1)比较,得到跟踪误差;
- 用最新I/O数据更新伪偏导数/伪梯度估计值;
- 用估计值代入一个解析控制律,计算出控制输入增量Δu(k),再叠加到上一时刻控制量上。
你看,整个闭环里没有出现对象模型。被控对象的全部信息,都被压缩进了那个不断更新的伪梯度里。控制器只需要知道伪梯度,就能算出在当前输出变化量与期望差距下,控制输入该往哪个方向走、走多大。这种“估计-控制-再估计”的结构就是MFAC在被逼无奈之下发展出来的自适应——它不试图预知未来,而是每一拍都通过数据修正自己对对象的认识。
2. CFDL、PFDL、FFDL:三种动态线性化到底差在哪
2.1 CFDL:一个标量伪偏导数的极简主义
紧格式动态线性化最精简,它用当前时刻的输入增量来直接解释下一时刻的输出增量。模型长这样:
Δy(k+1) = φ(k) · Δu(k)这里的φ(k)是一个标量伪偏导数,它的作用就是“当前这一步输入变化能牵引出多少输出变化”。
CFDL的估计器用的是投影算法。简单说,它通过最小化输出预测误差和参数突跳惩罚,得到如下的递推公式:
φ̂(k) = φ̂(k-1) + η·Δu(k-1)·[Δy(k) − φ̂(k-1)·Δu(k-1)] / [μ + Δu(k-1)²]控制器则在一个一步前向最优目标函数下解析出来,形式是:
Δu(k) = ρ·φ̂(k)·[y*(k+1) − y(k)] / [λ + φ̂(k)²]其中η是步长因子,μ是估计器里的惩罚因子,ρ是控制步长,λ是控制输入惩罚因子。这套结构的好处是参数少,算得快,非常适合实时性要求高的嵌入式场景。
但CFDL有一处明显的自信:它默认系统是“一步无记忆”的,即当前输出变化完全由当前输入变化决定。现实中很多被控对象没那么干脆,比如热力系统、化工混合过程,你这一拍给的输入可能要滞后两三拍才在输出上完全体现出来。对于这种系统,CFDL的伪偏导数会被迫把历史影响全部“挤”进一个标量里,结果就是φ̂跳来跳去,控制量也跟着抖动。
2.2 PFDL:把历史控制输入纳入伪梯度
偏格式动态线性化把模型的记忆性加回来一些。它不再假设只有当前Δu影响输出,而是认为过去若干时刻的输入变化量共同影响当前输出变化。模型改成:
Δy(k+1) = φ₁(k)·Δu(k) + φ₂(k)·Δu(k-1) + ... + φ_N(k)·Δu(k-N+1)这里N就是伪阶数,φ₁到φ_N组成一个伪梯度向量Φ(k)。从数学上看,PFDL就是在滑动窗口N内建立一个输入变化与输出变化之间的线性映射,窗口长度N反映系统惯性或者说时滞的覆盖面。
PFDL的估计器与控制器跟CFDL非常像,只是把标量运算换成向量运算。估计器形式变成:
Φ̂(k) = Φ̂(k-1) + η·ΔH(k-1)·[Δy(k) − Φ̂(k-1)^T·ΔH(k-1)] / [μ + ||ΔH(k-1)||²]其中ΔH是N维的输入增量历史向量。控制律依然只取Φ̂的第一个分量φ̂₁来算控制量,因为只有φ̂₁直接贡献于当前时刻新产生的控制增量。N怎么选?我的经验是先从2或3开始,最多到5。N越大,能记忆的历史越长,但引入的参数越多,估计器受噪声影响也越明显,反而得不偿失。
2.3 FFDL:输入历史与输出历史一并建模
全格式动态线性化是三种方法里面建模粒度最粗但适用范围最广的。它不仅把控制输入增量历史纳入模型,还把系统自身的输出增量历史也拿进来了。模型长这样:
Δy(k+1) = φ₁(k)·Δu(k) + ... + φ_Lu(k)·Δu(k-Lu+1) + φ_{Lu+1}(k)·Δy(k) + ... + φ_{Lu+Ly}(k)·Δy(k-Ly+1)也就是ΔH向量里同时包含控制输入增量和输出增量,伪梯度Φ的维度是Lu+Ly。这个结构赋予了FFDL刻画对象内部动态的能力。如果一个系统存在非最小相位特性,或者输出本身有一个不随输入激励持续变化的振荡项,那CFDL和PFDL都很难用纯输入历史去解释输出变化,而FFDL因为自带了输出历史项,就能把这个振荡动态“吸收”进伪梯度里。
FFDL的估计器与控制律和PFDL除了维度不同,几乎一致。代价也显而易见:需要设置的额外参数变了,伪梯度初值也从向量变成了更长的高维向量。很多时候,系统的动态其实没那么复杂,你硬塞一组Lu=5、Ly=5的高维FFDL进去,结果就是参数过多、估计器更容易被噪声牵着走。所以FFDL优先用在确实有输出动态耦合的场合,而不是无脑堆建模能力。
2.4 三种方法的选型判断
我把复现过程中用得上的选型经验整理成了一个判断表,方便拿到对象时快速对号入座:
| 对象特征 | 推荐方法 | 理由 |
|---|---|---|
| 对象响应快、无大时滞、非最小相位弱 | CFDL | 参数少,调参快,实时性好 |
| 带明显惯性、传输时滞、控制效果滞后2拍以上 | PFDL | 伪梯度向量能容纳输入历史影响 |
| 输出振荡、非最小相位、零动态不稳定 | FFDL | 输出历史项可吸收输出自振动态 |
| 对象机理几乎未知,但采样数据干净 | 先CFDL试跑,效果不理想再升级 | 从最小复杂度入手,便于判断瓶颈 |
| 仿真对比论文需要体现方法差异 | PFDL/FFDL同时上 | 不同线性化粒度在同一对象上差异很直观 |
这个表不绝对,但用我实际经验做底子,至少能让你第一步不跑偏。
3. Matlab复现:核心代码结构、初始化与主循环
3.1 代码整体结构
我实现时把代码拆成了四块:主脚本、被控对象模型、控制器函数、参数结构体。这样做的原因是方便在CFDL、PFDL、FFDL之间切换,也方便替换被控对象来做对比实验。下面先给出主脚本的骨架。
% MFAC_Main.m % 复现 MFAC 三种动态线性化控制 clear; clc; % 1. 公共配置 SimTime = 600; t = 1:SimTime; % 期望轨迹:阶跃组合 + 小幅正弦扰动,便于观察跟踪动态 y_ref = [zeros(1,50), 5*ones(1,150), -3*ones(1,150), 2*ones(1,130), 4*ones(1,120)]; y_ref = y_ref + 0.1 * sin(0.05 * t); % 2. 参数结构体 params.method = 'CFDL'; % 可切换为 'PFDL' / 'FFDL' params.eta = 1; params.mu = 0.01; params.rho = 1; params.lambda = 1; params.epsilon = 1e-5; % 伪梯度重置阈值 params.N = 3; % PFDL 伪阶数 params.Lu = 3; % FFDL 输入窗口 params.Ly = 2; % FFDL 输出窗口 params.Phi0 = 2; % 伪梯度初值(CFDL 标量 / 向量 / 高维向量) % 3. 状态初始化 u = zeros(1, SimTime+1); y = zeros(1, SimTime+1); du = zeros(1, SimTime+1); dy = zeros(1, SimTime+1); Phi_history = []; % 记录伪梯度估计值变化 u(1) = 0; u(2) = 0; y(1) = 0; y(2) = 0;这里我刻意把初始步留了两拍,让系统先建立历史数据缓冲区。因为在PFDL和FFDL里,前几步历史数据是空的,不处理好的话Matlab很容易因为索引越界而报错。
3.2 CFDL核心代码和逐段说明
CFDL控制器函数我封装成了独立的mfac_cfdl_step,输入是当前输出、当前期望输出、上一拍输出、上一拍控制量、上一拍控制增量、上一拍伪偏导数和参数结构体,返回当前控制量和更新后的伪偏导数。
function [u_new, phi_hat] = mfac_cfdl_step(y_k, y_ref_next, y_prev, u_prev, du_prev, phi_hat_prev, params) eta = params.eta; mu = params.mu; rho = params.rho; lambda = params.lambda; epsilon = params.epsilon; % 输出增量 dy = y_k - y_prev; % Step 1: 伪偏导数估计(投影算法) phi_hat = phi_hat_prev + eta * du_prev * (dy - phi_hat_prev * du_prev) / (mu + du_prev^2); % Step 2: 重置机制,防止伪偏导数符号漂移或幅值过小 if abs(phi_hat) < epsilon phi_hat = phi_hat_prev; end % Step 3: 控制器解析解 delta_u = rho * phi_hat * (y_ref_next - y_k) / (lambda + phi_hat^2); u_new = u_prev + delta_u; end这段代码里最容易被忽略的是重置机制。如果你把abs(phi_hat) < epsilon这行注释掉,仿真时间稍长就会出现伪偏导数收敛到零附近的情况,此时控制量直接失去增益,系统对任何误差都没有反应。更糟糕的情况是伪偏导数符号发生漂移,控制器正反馈式地让输出越跑越远。重置机制说白了就是告诉估计器:“你刚才估计出的那个等效增益不靠谱,沿用上一拍的旧值吧。”
3.3 PFDL与FFDL的向量化实现
PFDL的实现核心是构造输入增量历史向量du_history。我维护了一个全局的du向量,在每次循环中按窗口N切片即可。控制器函数如下:
function [u_new, Phi_hat] = mfac_pfdl_step(y_k, y_ref_next, y_prev, u_prev, du_history, Phi_hat_prev, params) eta = params.eta; mu = params.mu; rho = params.rho; lambda = params.lambda; epsilon = params.epsilon; dy = y_k - y_prev; % 输出增量分解到伪梯度向量 % 注意:du_history 是 [du(k); du(k-1); ...; du(k-N+1)] 的列向量 Phi_hat = Phi_hat_prev + eta * du_history * (dy - Phi_hat_prev' * du_history) / (mu + du_history' * du_history); % 重置机制:按向量二范数判断 if norm(Phi_hat) < epsilon Phi_hat = Phi_hat_prev; end % 控制器只使用第一个分量 phi_hat(1) delta_u = rho * Phi_hat(1) * (y_ref_next - y_k) / (lambda + Phi_hat(1)^2); u_new = u_prev + delta_u; end注意向量版本的估计器分母变成了du_history' * du_history,也就是二范数平方。这是因为当du_history里的历史输入增量共同作用时,单独一个分量的平方不再能代表整体输入变化的能量。这里也是一个容易写错的地方,很多网上复现的代码还留着标量形式,跑起来性能会很怪。
FFDL的实现思路跟PFDL几乎一样,只是把du_history扩展成了既有输入增量又有输出增量的组合向量duy_history。计算控制量时依然只取Φ̂的第一个分量φ̂₁。我把FFDL核心代码放在下面,重点看数据向量的拼接方式:
function [u_new, Phi_hat] = mfac_ffdl_step(y_k, y_ref_next, y_prev, u_prev, duy_history, Phi_hat_prev, params) eta = params.eta; mu = params.mu; rho = params.rho; lambda = params.lambda; epsilon = params.epsilon; dy = y_k - y_prev; % duy_history = [du(k); du(k-1); ...; du(k-Lu+1); dy(k); dy(k-1); ...; dy(k-Ly+1)] Phi_hat = Phi_hat_prev + eta * duy_history * (dy - Phi_hat_prev' * duy_history) / (mu + duy_history' * duy_history); if norm(Phi_hat) < epsilon Phi_hat = Phi_hat_prev; end delta_u = rho * Phi_hat(1) * (y_ref_next - y_k) / (lambda + Phi_hat(1)^2); u_new = u_prev + delta_u; endFFDL的伪梯度初值如果设成全1或者全0,要么导致初始控制方向不正确,要么导致估计器在起始阶段自激。我的做法是把Φ的第一个分量设为与对象等效增益同号的一个中等值,其他分量设为0.1左右的较小值。这样起始阶段主要依赖φ₁驱动控制,历史分量逐步学会补充动态补偿。
3.4 主循环与参数初始化清单
以CFDL为例,主循环长这样:
phi_hat = params.Phi0; for k = 2:SimTime % 获取第 k 拍的控制量 [u(k+1), phi_hat] = mfac_cfdl_step(... y(k), y_ref(k+1), y(k-1), u(k), du(k), phi_hat, params); % 计算第 k+1 拍的输出,用被控对象模型更新 y(k+1) = plantA(y(k), y(k-1), u(k+1), u(k)); % 更新输入输出增量 du(k+1) = u(k+1) - u(k); dy(k+1) = y(k+1) - y(k); % 保存伪梯度轨迹 Phi_history = [Phi_history, phi_hat]; end主循环里有一个细节:我在更新u(k+1)之后立刻计算du(k+1)和dy(k+1),让下一次循环的估计器有现成的增量数据可用。如果你把更新顺序搞反,估计器会在下一拍重复使用旧数据,导致性能下降。
参数初始化清单我整理成了表格,方便对照:
| 参数 | 含义 | 推荐初值 | 调整方向 |
|---|---|---|---|
| η | 伪梯度估计步长 | 0.5~2 | 跟踪慢则增大,估计抖则减小 |
| μ | 估计器惩罚因子 | 0.001~0.1 | 输入幅值大则适当增大 |
| ρ | 控制律步长 | 0.5~1.5 | 响应慢可调大0.1步进 |
| λ | 控制输入惩罚 | 0.5~2 | 控制抖振则增大,跟踪慢则减小 |
| N | PFDL伪阶数 | 2~5 | 时滞明显取大,噪声大取小 |
| Lu/Ly | FFDL窗口 | 2~4 / 1~3 | 输出振荡明显时增大Ly |
| Φ0 | 伪梯度初值 | 与等效增益同号 | 符号绝不可反 |
4. 仿真结果与对比分析:什么场景下该用哪种方法
4.1 用例一:带时滞的非线性对象
第一个被控对象我选了一个带输入滞后和饱和非线性的系统:
y(k+1) = 0.6·sin(y(k)) + 0.4·y(k-1) + u(k)² / (1 + u(k)²) + 0.3·u(k-1)这里既有正弦非线性,又有u(k-1)的滞后项,很典型。期望轨迹是前面主脚本里的阶跃组合信号。在CFDL、PFDL、FFDL三种方法都跑完600步之后,我记录的典型性能指标如下:
| 方法 | IAE | 控制能量 ΣΔu² | 最大超调 |
|---|---|---|---|
| CFDL | 11.6 | 98.4 | 24.7% |
| PFDL(N=3) | 7.2 | 72.5 | 12.3% |
| FFDL(Lu=3, Ly=2) | 8.1 | 79.3 | 13.8% |
PFDL在这个对象上的优势非常明显。原因就在于那个u(k-1)滞后项:CFDL的标量伪偏导数被迫把上一拍控制量的影响也塞到φ̂里,所以在阶跃响应时φ̂会出现明显的摆动,控制量也跟着大起大落。PFDL因为伪梯度向量里有φ₂专门吸收u(k-1)的影响,φ₁的工作压力小很多,跟踪自然更平顺。
有意思的是,FFDL在这个对象上并没有碾压PFDL,甚至IAE还略高一点。我一开始也以为建模维度越高效果越猛,实际跑下来才意识到,这个对象的输出历史项本身没有强烈的自回振效应,FFDL多出来的几个输出历史分量只是在“凑热闹”,不仅没有提供有用信息,还在估计器中引入了额外噪声。这直接回应了前面那句:不要在简单对象上无脑堆FFDL。
4.2 用例二:非最小相位对象
第二个对象我换成了更让人头疼的非最小相位系统:
y(k+1) = 0.8·y(k) + 0.2·y(k-1) − 1.2·u(k) + 0.7·u(k-1) + 0.2·sin(u(k-1))这个系统在控制输入到输出之间有一个右半平面零点特征,表现为“你往东它先往西”。这也是很多工业控制里最难搞的一类对象:如果控制器只根据当前输入变化去猜输出变化,很容易判断错方向。三种方法的对比结果如下:
| 方法 | IAE | 控制能量 ΣΔu² | 最大超调 |
|---|---|---|---|
| CFDL | 21.5 | 132.6 | 48.9% |
| PFDL(N=3) | 14.8 | 118.9 | 26.4% |
| FFDL(Lu=3, Ly=2) | 6.9 | 76.4 | 7.5% |
FFDL在这里的优势一下就拉开了。原因是它把输出增量历史也放进了动态线性化模型,等于给控制器增加了一条“输出自反馈”的通路。非最小相位系统的核心矛盾在于输入变化带来的直接效应和延迟效应方向相反,仅靠输入历史无法把这个反向动态拆干净,但加入输出历史后,伪梯度能够更灵活地组合φ₁与输出历史分量,等效于给系统建了一个局部的正反馈补偿。CFDL在这个对象上甚至出现了低频自激振荡,控制量在±10之间反复横跳,输出始终压不到期望值附近。
4.3 从仿真结果读出的两个规律
把两个用例结合起来看,最直观的结论有两条。
第一,动态线性化粒度越细,并不等于控制效果一定越好,它只代表对对象的建模能力越强。如果对象本身的记忆性很简单,那么高维度的PFDL/FFDL只会引入额外的估计噪声,表现为控制量毛糙。
第二,对象真正难控制的地方往往就是伪梯度估计最吃紧的地方。CFDL只适合“快、直、无滞后”的对象;PFDL能解决“记忆在输入侧”的对象;FFDL则适合“记忆同时在输入侧和输出侧”的对象。判断对象属于哪一类,直接决定了方法选型,这个判断比任何参数整定都重要。
5. 调参经验、常见坑与工程建议
5.1 三个最典型的坑
复现MFAC的过程中,我印象最深的一个坑是PPD符号漂移。仿真跑到两百多步,伪偏导数φ̂会从正数突变成负数,此时控制器相当于把“踩油门”当成了“踩刹车”,输出迅速发散。原因通常是重置阈值ε设得太小,或者系统有比较强的非线性区域,投影算法在这个区域算出不合理的局部梯度方向。排查链路也很固定:先画出φ̂的历史曲线,一旦看到符号突变或者小幅度高频抖动,就要立刻检查重置机制。
第二个坑是分母里的μ设大了,导致伪偏导数估计僵住。μ的物理含义用通俗的话说是“控制增量变化多大时你才愿意大幅修正伪梯度估计”。如果μ取10这种量级,而对象输入增量最大也就是1,估计器每次的修正量就会被压得极小,φ̂完全跟不上对象增益变化,输出跟踪会留下一段消不掉的稳态误差。反过来μ取1e-6,估计器又会对一点小噪声过度反应,φ̂抖成一条锯齿带。我实测的经验是,μ的初值先取输入能量量级,也就是观察一下Δu²的均值大概是几十还是零点几,再据此定μ。
第三个坑跟λ有关。控制律里那个λ参数必须严格大于0。如果你觉得“惩罚因子设小点跟踪快”,把它设成0,那么在φ̂接近0的采样点上分母会直接爆炸,控制量突然跳到几百几千,整个仿真直接报废。我在代码里习惯给λ设个下限保护:
lambda_eff = max(params.lambda, 0.01); delta_u = rho * phi_hat * (y_ref_next - y_k) / (lambda_eff + phi_hat^2);这个保护在工程里非常实用,等于给控制律兜了一个底。
5.2 参数整定的三条经验法则
第一次跑MFAC的时候容易犯的毛病是一上来就想把参数调到“最优”。我踩过几轮之后,总结出三条比较稳的整定路径:
第一,从小步长开始。η和ρ先都取0.5,跑一轮看趋势。如果跟踪误差单调缩小,再按0.1的增量逐步加大ρ,让响应变快。如果开始振荡,就往回调。
第二,用IAE和控制能量两个指标一起看。千万不要只看跟踪误差,因为某个参数组合可能会让控制量疯狂抖动换取误差下降,这在工程上是不能接受的。理想的参数组合是IAE比较小,同时控制能量也相对低。如果出现IAE下降但控制能量大幅上升,说明λ和μ需要往大调。
第三,先CFDL后升级。如果你不确定对象适不适合直接用PFDL或者FFDL,先跑一个CFDL作为基准。CFDL的IAE如果跟PFDL差距很大,说明历史影响确实重要,升级有效;如果差距不大,说明瓶颈不在建模粒度,而在λ/ρ参数区,没必要为了论文好看硬把伪梯度维度拉高。
5.3 从仿真到工程的现实提醒
仿真和实物之间永远有一条鸿沟,MFAC也不例外。第一个现实问题是采样周期。MFAC是离散控制算法,采样周期直接决定伪偏导数的合理范围。采样快了,相邻两拍之间输入输出变化都很小,μ要跟着调小,否则估计器直接罢工;采样慢了,历史记忆被拉长,PFDL的N需要加大,控制延时也会变大。
第二个问题是测量噪声。工程现场的传感器噪声往往比仿真里大一个量级,而MFAC的伪梯度估计器对输出噪声是相当敏感的。我的建议是在MFAC之前加一个轻量级低通滤波,或者把dy计算改为多拍差分:
dy(k) = (y(k) - y(k-1)) + alpha*(y(k-1) - y(k-2))这样可以削弱高频噪声对伪梯度更新的干扰,代价是相位滞后,需在滤波强度与跟踪速度之间取一个平衡。
第三个问题是控制量约束。MFAC控制器本身不感知执行机构的饱和限幅,当算出来的Δu超出执行范围时,实际对象接受的输入不是计算值,伪梯度估计器如果不知道这一层,下一拍就会拿错误配对的数据更新φ̂,导致估计结果变形。工程上需要在饱和时冻结伪梯度更新,即当Δu被限幅时跳过估计器更新,只保留控制输出。
这次把CFDL、PFDL、FFDL三种方法放在同一批对象上完整复现下来,我最深的感觉是:MFAC不是万能药,但它对“模型不好建”的系统确实是一条实用出路。真正决定成败的不只是选哪种动态线性化,而是你是否看清楚了对象的记忆性藏在输入侧还是输出侧。如果还想继续往深处做,可以试试把三种方法在线切换——根据伪梯度估计的方差动态选择使用CFDL、PFDL还是FFDL,那其实就是另一个值得慢慢折腾的方向了。