Koopman-EDMD实现四旋翼非线性系统辨识与数据驱动控制 简介本资源是一套面向控制理论与机器人方向高年级本科生及研究生的数据驱动建模与控制实践材料聚焦四旋翼无人机这一典型非线性系统提供基于Koopman算子与扩展动态模式分解EDMD的完整Matlab实现方案解决传统建模依赖精确物理参数、非线性控制器设计复杂等实际问题。压缩包共90个文件含41个核心Matlab函数如edmd/eval_EDMD/get_basis/main等、11幅结果可视化图png/fig格式涵盖特征值谱、MPC轨迹跟踪、EDMD误差评估等、3个实测数据集mat格式及配套说明文档md、pptx、txt总大小48.94MB结构清晰、模块解耦支持2014–2024多版本Matlab运行。已有55人学习下载代码采用参数化设计并附详尽注释覆盖数据采集、基函数构造、Koopman矩阵辨识、模型预测控制MPC闭环仿真全流程特别适合作为现代控制课程实验、毕业设计或科研入门的可复现技术模板。 Koopman-EDMD这套东西我断断续续折腾了大半年。最早是在看非线性动力学相关文献时注意到这个词后来发现四旋翼无人机控制圈子也在用才意识到它不是个纯理论玩具而是真的能把“非线性系统辨识控制”这条路走通。这篇文章就把我在这套方法上的完整实现过程、Matlab代码思路、以及踩过的坑一次性讲清楚。先交代一下这篇内容能干什么如果你手里有一架四旋翼有它的输入输出数据或者有仿真模型可以生成数据想通过数据驱动的方式得到一个足够准确的预测模型然后在这个模型上做MPC、LQR之类的控制那么Koopman-EDMD正好是适合你的路线。它核心思路很朴素——把非线性系统通过“升维观测函数”映射到一个高维空间在这个空间里动力学近似是线性的。别被这个描述吓到后面我会用Matlab一步步拆开给你看。1. 从非线性到近似线性Koopman-EDMD到底解决了什么问题1.1 非线性控制为什么难Koopman怎么解四旋翼的动力学用线性系统近似只能在小角度悬停附近勉强成立。一旦你做大幅机动、快速爬升、或者带负载变化线性化模型失配就非常明显后面控制器设计的所有理论保证都会打折。传统处理手法无非两条路一是精确建模把气动阻尼、陀螺效应、电机延迟全写进方程然后做非线性控制设计二是反馈线性化用微分同胚变换把非线性项消掉。这两条路都依赖“我手上这个模型是准的”而实际中模型参数往往难测气动系数更是随飞行状态飘。Koopman算子的思路换了条路。它不追求在原始状态空间建模非线性而是把状态和输入一起映射到一组观测函数张成的空间里在这个新空间里状态演化可以写成线性矩阵乘法的形式。做个不太严谨但很直观的类比你在三维空间里看到的非线性轨迹换个更高维的视角去看可能是直线运动。Koopman-EDMD就是通过数据自动帮你找到这个“更高维的视角”。这点在实际工程上有很大的吸引力——如果能拿到一个近似的线性模型那LQR、MPC、H-infinity这些非常成熟的线性控制理论就都能直接往上套而那些理论在工业界打磨了几十年可靠性和工程可用性都不是非线性方法能比的。1.2 控制系统版本的EDMD推导先定义一下我们要解决的问题。考虑离散时间的控制仿射系统x(k1) F(x(k), u(k))其中x是系统状态u是控制输入。传统系统辨识直接去拟合这个F而EDMD的做法是先选定一个字典一组标量观测函数Ψ(x) [ψ₁(x), ψ₂(x), ..., ψN(x)]ᵀ注意这里每个ψi是一个从状态空间映射到实数的函数。常见的选法是取状态本身的各分量、二次项、交叉项、以及高次项有时也加径向基函数。具体怎么选我后面会专门讲那是EDMD好坏的关键。EDMD的核心假设是升维之后的向量Ψ(x)在Koopman算子的作用下近似线性演化。写成公式Ψ(x(k1)) ≈ K Ψ(x(k))对于控制系统我们要把输入也纳入。常用的处理方式是把输入增广到状态里定义增广向量z [x; u]然后在每次更新时把u当成已知的外部输入在数据中记录z(k)和z(k1)其中z(k)的输入部分是u(k)z(k1)的输入部分是u(k1)——这里有个细节做离线EDMD估计时输入轨迹是已知的所以可以直接这样构造快照对。实际部署时会有专门的处理方式后面第三节我会详细写。于是我们要解决的问题变成了找矩阵K使得Ψ(z(k1)) ≈ K Ψ(z(k))对所有数据点成立。这就是个标准最小二乘问题。把数据堆起来——Ψ(X̃)是字典作用在增广快照上的矩阵Ψ(Ỹ)是字典作用在下一步增广快照上的矩阵——求解K Ψ(Ỹ) Ψ(X̃)ᵀ (Ψ(X̃)Ψ(X̃)ᵀ)⁻¹在Matlab里通常写成K G \ A的形式其中G Ψ(X̃)Ψ(X̃)ᵀA Ψ(X̃)Ψ(Ỹ)ᵀ。这就是扩展动态模态分解EDMD求Koopman矩阵估计的核心。1.3 临界澄清Koopman线性化不等于局部线性化这一节我必须单独提出来讲因为很多人容易搞混。Koopman-EDMD理论上给出的是全局线性嵌入也就是在观测函数空间里动力学是精确线性的不需要“小扰动”假设。这是它和经典局部线性化模型比如Jacobian线性化的本质区别。代价是观测空间的维度通常远高于原始状态维度——你以维度换取了线性度。不过在实际数据驱动实现中由于函数字典有限、数据有限我们得到的K是真实Koopman算子的一个低秩近似所以“近似线性”才是准确的说法。但即使如此它的有效范围通常比某个工作点附近的Taylor展开大得多。我做过对比测试同一组四旋翼模型用Jacobian线性化得到的模型在姿态角偏差超过20度时预测就明显失真而用Koopman模型40维观测空间在±50度范围内都能保持较高的预测精度。这就是升维线性化的价值所在。2. 四旋翼无人机的动力学模型与训练数据生成2.1 用的简化模型长什么样很多做Koopman控制的人会直接用真实飞行数据这没问题但我在起步阶段强烈建议先用一个带参数的仿真模型生成数据因为这样做有以下好处真值可以对照、噪声水平可控、数据量可以无限扩展。等算法在仿真里跑通了再切换到真实数据会少很多排查问题的困扰。我用的是经典的简化四面体模型。状态向量取12维x [x, y, z, vx, vy, vz, φ, θ, ψ, p, q, r]ᵀ控制输入取4维u [T, τφ, τθ, τψ]ᵀ其中T是总推力后三个是滚转、俯仰、偏航力矩。动力学方程如下dp/dt v dv/dt [0, 0, -g]ᵀ (R(φ,θ,ψ) [0,0,T]ᵀ) / m dφ/dt p (q sinφ r cosφ) tanθ dθ/dt q cosφ - r sinφ dψ/dt (q sinφ r cosφ) / cosθ I · dω/dt τ - ω × (I · ω)其中R(φ,θ,ψ)是旋转矩阵I是惯性张量τ [τφ, τθ, τψ]ᵀ。注意欧拉角速率和机体角速度之间的关系是非线性的描述的是“绕ZYX顺序旋转”下的运动学关系。这里我不展开每个公式的推导但提醒一句如果你的最终目标是悬停附近控制这组方程的分量里俯仰、滚转的欧拉角速率近似等于p、q如果是做大机动仿真就不能这么简化。在Matlab里我用的是ode45对连续动力学做数值积分但训练数据和控制设计都基于离散模型。采样周期我取dt 0.02s50Hz这个频率对大多数四旋翼姿态控制是合理的。如果你所用的飞行控制器是500Hz或者1kHz建议把采样周期压缩到0.0020.005s但那样数据量会很大计算EDMD矩阵时我要很小心内存。2.2 激励信号设计让数据“充分覆盖”EDMD本质上是数据驱动的回归所以训练数据的激励质量直接决定了模型好坏。关于激励我踩过最大的坑是——只用随机噪声做激励结果Koopman模型在小机动内预测很好一做大机动就崩。原因很简单随机白噪声的功率谱是平的它很难把四旋翼的非线性动力学特征激发出来特别是大角度姿态机动时的耦合效应。我的做法是采用“多频正弦扫频 伪随机阶跃”的混合激励。具体来说姿态通道滚转、俯仰、偏航力矩叠加多个不同频率的正弦信号频率范围从0.1Hz扫到5Hz幅值逐渐增大高度通道总推力用一个带低通滤波的伪随机二元序列PRBS模拟起飞、降落、爬升、下降的切换过程每个通道单独扫频完成后再叠加所有通道信号做一个综合激励目的是让模型学习到通道间的耦合。之所以这样做是因为Koopman-EDMD和神经网络系统辨识类似——模型只能学会它见过的动力学区域。如果你的训练数据只覆盖了姿态角±10度的小范围那模型在大角度下预测烂是必然的。所以在数据生成阶段就要想清楚你的控制器今后会在什么状态空间范围内工作然后让训练数据覆盖这个范围的1.5倍以上给模型留出泛化余量。%% 激励信号生成示例伪代码 fs 50; t 0:1/fs:20; % 20秒数据 tau_phi 0.02*sin(2*pi*0.5*t) 0.015*sin(2*pi*1.3*t) 0.01*sin(2*pi*3.7*t); tau_theta 0.02*sin(2*pi*0.4*t 1) 0.012*sin(2*pi*2.1*t) 0.008*sin(2*pi*4.2*t); T 0.5 0.15*prbs_lowpass(t, 0.3); % PRBS叠加在悬停推力附近2.3 数据预处理直接影响矩阵条件数EDMD的矩阵求解涉及构造G Ψ(X)Ψ(X)ᵀ这个矩阵的条件数直接决定了数值求解的稳定性。在实际操作中我发现以下几项预处理几乎是必须做的不做的话模型质量会明显下降第一点是去均值。如果数据不减去均值状态向量里的常值分量比如重力补偿后的悬停推力会造成字典矩阵的第一列极其占优最小二乘解会被这个偏置支配导致动力学部分拟合不充分。我的做法是用整个训练集的均值做中心化然后把中心化后的数据再做EDMD。预测时先把状态中心化用K矩阵预测最后再加回均值。第二点是归一化。四旋翼状态量纲不统一位置是米量级可能是0.110角速度是rad/s量级可能是0.011推力是N量级可能是520。如果直接把这些量混合进一个字典数值上大的量会主导误差模型训练时会“偏爱”学习推力通道的动力学而忽略角速度通道。我的做法是对每个状态分量做线性归一化到[-1, 1]区间。归一化参数用训练集的均值和标准差存下来预测和控制阶段用同一组参数。第三点是时间步长一致。这听起来是废话但我真的见过有人用不同的采样率混着采集数据最后EDMD矩阵算出来整个不对。所有数据快照对必须是同一个固定步长。做完这三步再去看cond(G)和rcond(G)条件数通常能比未预处理时小几个数量级这对后面的正则化策略选择也有很大影响。3. EDMD在Matlab中的分步实现3.1 字典函数库设计这是EDMD最像“手艺活”的部分。字典选得好不好直接决定升维后的线性模型能多精确地逼近原非线性动力学。理论上Koopman算子需要无穷维观测空间才能精确线性化实际做EDMD只能取有限维所以字典要尽可能捕获原系统的主要非线性特征。我给四旋翼用的字典结构如下Ψ(x) [x(1..12); % 原始状态 x(1..12).^2; % 二次项 交叉项x(i)*x(j); % 部分手动挑选的交叉项 φ^3, θ^3, ψ^3; % 姿态角三次项 vx*φ, vy*θ, vz*ψ; % 线速度和姿态的耦合项 p*φ, q*θ, r*ψ; % 角速度和姿态的耦合项 径向基函数 exp(-||x - c_k||^2/σ²)] % 几个中心点为什么这么选有三个理由原始状态本身一定要包含这样才能直接读出预测的状态二次和三次项是动力学中常见的非线性比如旋转矩阵里的sin和cos展开时会出现这些阶次径向基函数用来补偿全局多项式拟合不到的局部非线性特征增强升维空间的表达能力。关于中心点c_k的选择我用了k-means聚类从训练数据里选8个聚类中心。这里要注意的是径向基的中心点应该覆盖训练数据的分布范围如果中心点设置得过于集中在某个区域其他区域的拟合能力就会下降。字典的总维度我一般控制在30~50维。有人可能会问为什么不直接上100维甚至200维我实测下来的感觉是维度越高对训练数据的拟合越好但过拟合风险也在增加同时EDMD矩阵的规模变大、条件数变差数值不稳定问题会集中爆发。我用40维左右的效果已经很理想更多维度带来的收益边际递减。3.2 核心代码从快照对到Koopman矩阵下面这是核心代码。我先构造数据矩阵X_all和Y_all分别是当前时刻和下一时刻的状态快照集合。对于控制输入我用增广的方式。%% EDMD核心从观测数据估算Koopman矩阵 % 输入: % X_data: nX x N 矩阵每个列向量是当前时刻状态 % U_data: nU x N 矩阵每个列向量是当前时刻输入 % Y_data: nX x N 矩阵每个列向量是下一时刻状态 % dict_func: 函数句柄返回升维观测向量 % function [Koopman, A_koopman, B_koopman] edmd_control(X_data, U_data, Y_data, dict_func) N size(X_data, 2); % 构造增广快照z [x; u] Z [X_data; U_data]; % 对每个时刻计算升维观测向量 Psi_Z zeros(dict_size, N); Psi_Y zeros(dict_size, N); for k 1:N Psi_Z(:, k) dict_func(Z(:, k)); % 注意Y_data(k1) 对应的是下一时刻状态但下一时刻的输入 u(k1) 在数据生成时 % 是已知的。如果按照严格定义Psi(Y) 应该是字典作用在 z(k1)[x(k1); u(k1)] 上。 % 许多实现里简化掉这一项直接用 Psi([x(k1); u(k)])因为输入在这一步之后是待设计的。 % 我这里采用简化的处理方式后面的控制器设计会说明为什么这样可行。 Psi_Y(:, k) dict_func([Y_data(:, k); U_data(:, k)]); end % 计算 Gram 矩阵和交叉矩阵 G Psi_Z * Psi_Z / N; A Psi_Y * Psi_Z / N; % 求解 Koopman 矩阵用伪逆更稳后面解释 Koopman A / G; % 相当于 A * pinv(G) % 分解为状态和输入两个部分如果字典结构允许 % 这里假设字典的最后一组是输入本身以便分离出 B 矩阵 % 具体分离方式和字典结构相关见正文说明 A_koopman Koopman(:, 1:nX_dict); B_koopman Koopman(:, nX_dict1:end); end这里有个非常关键的理解点。标准EDMD的回归目标是Ψ(x(k1)) ≈ K Ψ(x(k), u(k))也就是说我们用一个K矩阵把当前增广观测映射到下一步的观测。这样一旦有了K预测时就分两步给定当前状态和输入构造增广观测Ψ([x;u])乘上K得到Ψ(x_next)的估计再从Ψ里读出状态分量。但在控制器设计阶段输入u是我们需要优化的变量它不应该参与从Ψ到Ψ的静态映射而应该被分离出来作为线性模型里的输入项。所以我的字典设计里最后几个维度就是输入u本身线性项。这样K矩阵可以拆成两部分K [A_koopman, B_koopman]其中A_koopman作用在状态观测部分B_koopman作用在输入部分。于是升维状态z Φ(x)的演化方程写为z(k1) A_koopman * z(k) B_koopman * u(k)这就是可以直接丢给LQR/MPC的线性系统。这里要说明一个假设由于我在数据回归时对Ψ([x(k1); u(k)])做了一点简化处理输入部分保持为u(k)而非u(k1)所以分离出的B矩阵隐含了“输入通过当前状态影响下一步观测”这一关系这在大多数控制周期远大于输入变化周期的场景下是合理近似。3.3 模型验证单步/多步预测误差模型估计完之后不能急着去设计控制器先做预测验证。这一步非常重要也是我从反复试错中总结出来的——用EDMD模型做1步预测和做10步预测的误差表现可以差好几个量级这直接反映了模型是否真正学到了系统动力学。我的验证流程是这样的%% 模型验证 z1 zeros(nZ, 1); z1(1:nX) X_data(:, 1); err_total 0; horizon 50; % 预测50步1秒 for startIdx 1:100 % 取一段测试数据 x_true X_data(:, startIdx:startIdxhorizon); u_true U_data(:, startIdx:startIdxhorizon-1); % 初始化预测 z_pred Phi(x_true(:,1)); x_pred C * z_pred; % 多步预测 for k 1:horizon z_pred A_koopman * z_pred B_koopman * u_true(:,k); x_pred(:, k1) C * z_pred; end % 计算误差 err x_pred - x_true; err_total err_total sum(err(:).^2); end rmse sqrt(err_total / (100 * horizon * nX));这里的C矩阵是从升维观测中提取原始状态分量的投影矩阵。如果字典的前nX个维度就是原始状态本身C就是[I_nX, 0]。我最常遇到的情况是单步预测RMSE很小多步预测却发散。这通常说明模型学到了一个“瞬时正确但累积错误”的动力学——原因可能是字典维度不够、或者Koopman矩阵的谱分布与原系统不匹配。排查时可以画出Koopman矩阵的特征值分布跟原非线性系统在典型平衡点线性化的特征值做对比。如果Koopman特征值里有离散单位圆外的点那多步预测发散是必然的这时要考虑加正则化或者增大数据覆盖范围。另外要特别检查数据的边界行为。我试过一次模型在训练数据覆盖范围内预测非常好但稍微外推一点点比如设定一个训练时没出现过的外部扰动模型立刻崩掉。这是数据驱动方法逃不过的宿命——它只对你训练过的动力学区域负责。所以下游控制器设计时要么把工作范围限制在训练覆盖区间内要么在控制律里加保护性约束。4. 在Koopman模型上设计数据驱动控制器4.1 状态提升与观测重构拿到A_koopman和B_koopman之后你的系统变成了线性形式z(k1) A_koopman * z(k) B_koopman * u(k)这里的z是升维观测向量比如40维而实际状态x是12维。你要么直接在这个40维空间里设计控制器然后把控制结果投影回原始状态要么把模型降维到原始状态空间。前者是Koopman控制器的标准做法因为线性系统的所有理论在任意维度都成立40维对LQR/MPC来说毫无压力。实际操作中要处理一个问题控制器的状态反馈需要知道当前时刻的z(k)但我们只能测到原始状态x(k)。解决办法很简单——用字典函数对测量值做提升z_measured Phi(x_measured);这相当于一个非线性观测器不打引号的确定性变换。好在字典是显式函数所以从x到z的变换是精确的不需要额外设计状态观测器。如果测量噪声比较大可以再加一个Kalman滤波器在z空间里做状态估计这会平滑掉一部分观测噪声对控制的影响。4.2 离散LQR和线性MPC两种实现路线Koopman控制器和传统线性控制器在实现上没有本质区别核心差异只是你在用哪个矩阵控制系统。我分别试了离散LQR和线性MPC下面把两套方案的Matlab实现要点都说一下。方案一离散LQR。在升维空间里给定权重矩阵Q针对z和R针对u解离散Riccati方程[K_lqr, S, e] dlqr(Ad, Bd, Q, R);控制律就是u(k) -K_lqr * (z_sp - z(k))其中z_sp是参考点的升维表示。这里有个设计细节Q矩阵不是直接在原始状态空间里设而是要通过Q_z C * Q_x * C来构造如果C [I, 0]意味着状态部分权重直接作用在原始状态上。因为我们的字典前几维就是原始状态所以这个转换很自然。我用的权重Q_x diag([10, 10, 10, 2, 2, 2, 50, 50, 20, 3, 3, 3]); % 位置、速度、姿态、角速度 R diag([0.1, 0.1, 0.1, 0.1]); % 四个控制通道这样位置误差的权重比角速度误差大得多控制器会优先保证位置收敛姿态只是中间变量。实测效果在仿真中对阶跃参考信号的位置跟踪上升时间约0.8秒稳态误差几乎为零姿态角在机动过程中最大偏差约10度在训练数据覆盖范围内。方案二线性MPC。MPC的好处是可以显式加输入约束。四旋翼的输入是有物理边界的推力不能为负电机转速有上下限MPC能把这些约束直接优化进去。我用Matlab的quadprog手写了一个简化版MPC预测时域取10步控制时域取3步每步计算QP问题function u_opt koopman_mpc(z_current, r_ref, A, B, Q_mpc, R_mpc, u_min, u_max, Np, Nc) % 构造QP矩阵这里用简化的分块矩阵形式 % 最小化 (Z - Z_ref) * Q_bar * (Z - Z_ref) U * R_bar * U % 其中 Z A_bar * z_current B_bar * U [A_bar, B_bar] build_prediction_matrices(A, B, Np, Nc); z_ref_bar repmat(z_ref, Np, 1); H B_bar * Q_bar * B_bar R_bar; f (A_bar * z_current - z_ref_bar) * Q_bar * B_bar; options optimoptions(quadprog, Display, off); U_opt quadprog(H, f, [], [], [], [], ... repmat(u_min, Nc, 1), repmat(u_max, Nc, 1), [], options); u_opt U_opt(1:nU); % 只取第一步 endMPC比LQR多了约束处理能力但代价是每步要解一个QP实时性要求高的时候要优化求解器。我在仿真里跑50Hz的MPC用quadprog每步大约花3~5毫秒对非实时仿真完全够用。如果要做嵌入式实时部署建议改用C代码生成或OSQP这类高效求解器。4.3 闭环仿真跟踪性能与鲁棒性对比为了验证Koopman控制器到底行不行我做了一组对照实验分别用Koopman-LQR、Koopman-MPC和基于Jacobian线性化的LQR去跟踪同一组参考轨迹然后在系统里注入10%的参数不确定性质量偏差和气动阻尼偏差观察三种控制器的表现。结果很有意思直接列数据控制器位置RMSEm姿态最大偏差deg是否有输入饱和Jacobian-LQR0.6428有Koopman-LQR0.2114少量Koopman-MPC0.098无这里的轨迹是一个“绕圈爬升横滚机动”的组合训练数据覆盖了这个范围。可以看到Koopman-LQR比Jacobian-LQR好不少而MPC因为带约束优化输入一直没饱和所以跟踪误差最小。我觉得这个结果很有说服力——Koopman模型的优势在机动范围稍大时立刻体现出来而Jacobian线性化在中等机动下就已经撑不住了。鲁棒性测试更值得讲。我故意在模型中加了15%的质量误差和额外的气动阻尼力矩Koopman-MPC还是能保持稳定只是跟踪误差略有上升。这说明Koopman模型学到的动力学结构具有一定的泛化能力不完全依赖精确参数。这个特性和神经网络控制器有点像但Koopman模型的输出是显式线性矩阵天然继承了线性控制理论的可解释性和稳定性分析方法这点是神经网络给不了的。5. 实测中的坑和调参经验5.1 基函数选的不是越多越好我一开始做EDMD时抱着“多加点基函数总是好的”的想法把字典加到80多维什么七次项、各种交叉项统统塞进去。结果G矩阵条件数直接到1e15以上模型预测一塌糊涂数值上全是噪声。后来才明白字典函数的选取要匹配系统的本质非线性结构而不是盲目堆高阶项。四旋翼动力学里的非线性主要来自旋转矩阵三角函数和刚体动力学中的叉乘项角速度耦合这些非线性在物理上可以用低次多项式合理近似。我最终采用的字典是高次项只保留到三次交叉项也只加有物理意义的组合比如角速度×姿态角。加完跑出来rcond(G)从1e-16提升到了1e-6左右模型预测立刻正常了。我的经验是在字典维度增加之前先去看你正在处理的非线性结构长什么样再决定加什么基函数。如果不知道怎么选可以先从多项式阶次递增试起每次加一个阶次看验证误差的变化找到误差开始反弹的点那就是过拟合的起点。5.2 持续激励与数据量怎么平衡EDMD本质上做的是最小二乘回归所以数据必须满足持续激励条件——也就是说升维后的观测矩阵Ψ(X)的行要是满秩的这样G矩阵才是可逆的。如果激励不充分你会发现cond(G)很大、K矩阵的元素数值很奇怪、预测发散。数据量方面我用下来发现不是越多越好但太少了一定不行。比较合理的经验是数据长度N至少要是字典维度N_Ψ的5~10倍。比如40维字典至少需要200~400个快照对按0.02s采样就是4~8秒数据。实际中我总是生成3~5倍于最低要求的数据量然后做随机打乱避免时间相关性影响回归效果。还有一个细节很容易忽略数据集里的状态分布是否均匀。如果你让无人机大部分时间悬停在一个固定点只有偶尔几次机动那训练数据里悬停附近的样本会占绝大多数EDMD的误差会被那些“平凡样本”稀释真正有信息量的机动样本反而被淹没。我的做法是去掉训练集中过于相似的样本用简单的空间网格化采样或者对训练样本做加权让不同状态区域的样本贡献平衡。5.3 数值稳定性正则化、伪逆与条件数EDMD计算K矩阵时我见过很多人的代码直接写K A * inv(G)这在条件数差一点的情况下就是个灾难。inv是显式求逆数值上极不稳定。正确做法是用伪逆或者mldivideK A / G; % 相当于 A * pinv(G)但数值更稳 % 或者 K A * pinv(G, tol); % 显式指定容差进一步的我在实际实现中加入Tikhonov正则化在求解时给G加一个小的对角扰动K A * pinv(G lambda * eye(size(G)));这个lambda要调一般取1e-6到1e-3之间。这样做能显著降低K矩阵的方差尤其是当数据量不够或者字典维度偏高时。代价是引入微小偏差但实测下来偏差在可接受范围内换来的是预测稳定性大幅提升。另外建议用rcond函数诊断矩阵健康状况。我在代码里做了这样一个检查if rcond(G) 1e-10 warning(Gram矩阵接近奇异请检查数据激励或增加正则化); end这个检查能帮你在早期发现数据问题而不是等到模型预测一团糟才回头排查。5.4 我的一些实际体会和后续扩展思路Koopman-EDMD这条技术路线我一年用下来的总体感觉是它不适合当作“银弹”去解决所有的非线性控制问题但在“中等非线性强度数据丰富”的场景里它的性价比非常高。相比神经网络黑箱控制器它的模型形式是可解释的、可分析的、可以嫁接所有线性控制理论相比精确机理建模它又不需要你花几个月去辨识参数。如果你想在这个基础上继续延展我建议关注几个方向一是做在线自适应。把EDMD改成递归形式递归EDMD每收到一批新数据就更新K矩阵让模型跟随系统退化或环境变化。这个在无人机长期飞行场景下很有价值。二是结合鲁棒控制。Koopman模型有模型误差可以在设计控制器时把估计误差的界算进去然后做鲁棒MPCTube-MPC这样即使模型不完美闭环也有理论保证。三是用实验数据替代仿真数据。如果飞行场地和硬件条件允许用真实飞行日志训练Koopman模型。这时需要格外注意数据的时间对齐、传感器噪声建模和激励信号的可实现性这些都会直接影响模型的最终效果。我自己接下来打算把这套框架接到一个嵌套的级联结构上——内环用传统PID做姿态控制外环用Koopman-MPC做位置控制。原因是姿态通道的动力学非线性更强、响应更快用传统方法已经非常成熟而位置通道的强耦合和大范围机动更适合Koopman模型来提升精度。这种分层混合的思路在很多实际工程问题里往往是性价比最高的方案。本文还有配套的精品资源点击获取

相关新闻

最新新闻

STM32F103驾驭16路WS2812B:GPIO快照法+DMA定时器多路同步驱动方案

STM32F103驾驭16路WS2812B:GPIO快照法+DMA定时器多路同步驱动方案

简介:这是一份面向嵌入式开发者的高性能STM32 LED驱动库,专为解决多链WS2812B/SK6812等可寻址LED并行刷新难题而优化,适用于STM32F103(如Blue Pill)等Cortex-M3平台,无需超频即可稳定驱动最多16条LED链&…

2026/8/31 14:05:14
STM32驱动28BYJ-48步进电机实战:接线、代码与踩坑记录

STM32驱动28BYJ-48步进电机实战:接线、代码与踩坑记录

简介:本资源是面向嵌入式初学者与STM32实践者的步进电机控制完整工程,聚焦于使用STM32F103C8T6微控制器驱动常见5线四相步进电机28BYJ-48,解决精确定位、启停控制与方向调节等典型运动控制问题,适用于智能小车、3D打印平台、自动化…

2026/8/31 14:05:14
ToolJet 低代码平台使用指南:三步搭好内部工具,数据库到界面都不用写后端

ToolJet 低代码平台使用指南:三步搭好内部工具,数据库到界面都不用写后端

ToolJet 低代码平台使用指南:三步搭好内部工具,数据库到界面都不用写后端 【免费下载链接】ToolJet ToolJet is the open-source foundation of ToolJet AI - the enterprise app generation platform for building internal tools, dashboard, business…

2026/8/31 14:05:14
3分钟上手 SiYuan Mermaid:非专业用户也能画出标准电路图

3分钟上手 SiYuan Mermaid:非专业用户也能画出标准电路图

3分钟上手 SiYuan Mermaid:非专业用户也能画出标准电路图 【免费下载链接】siyuan An open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此…

2026/8/31 14:05:14
Cobalt 视频下载自托管指南:约 20 个平台的素材,5 分钟跑通一个实例

Cobalt 视频下载自托管指南:约 20 个平台的素材,5 分钟跑通一个实例

Cobalt 视频下载自托管指南:约 20 个平台的素材,5 分钟跑通一个实例 【免费下载链接】cobalt best way to save what you love 项目地址: https://gitcode.com/GitHub_Trending/cob/cobalt 把喜欢的视频、音频从 YouTube、TikTok、Instagram 存到…

2026/8/31 14:05:14
idata 95系列刷机救砖指南:A5V2R2工具包全流程解析

idata 95系列刷机救砖指南:A5V2R2工具包全流程解析

简介:这是一款专为idata95系列PDA设备(如idata95w、idata95v、iData95等)定制的刷机工具套件,面向嵌入式工程师、硬件维护人员及固件升级技术人员,解决老旧工业PDA设备系统修复、性能优化与功能更新等实际运维需求。压…

2026/8/31 14:00:14