ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

神经网络观测器与自适应滑模的无人船轨迹跟踪Matlab复现详解

神经网络观测器与自适应滑模的无人船轨迹跟踪Matlab复现详解

开学那阵子搞论文复现,导师丢给我一篇 IEEE 的无人船轨迹跟踪论文,标题看着挺唬人:“基于神经网络观测器+自适应滑模的无人船轨迹跟踪”。当时我第一反应是,这又是一个“照猫画虎”的仿真复现,跑个图就完事了。结果真正上手做才发现,这里面门道不少,光是那个神经网络观测器和自适应滑模的搭配,就够你喝一壶的。断断续续折腾了两周,总算是把 Matlab 仿真代码跑通,拿出来的成果还算能看,这里把整个复现过程中的思路、算法拆解、代码实现细节以及踩过的坑做个系统梳理,希望对正在头秃同类课题的同学有点帮助。

读这篇文章之前,你得明白,这属于智能控制算法在欠驱动水面船系统上的应用研究,核心解决的是:在存在外部环境扰动和模型不确定性的情况下,如何让无人船精确跟踪期望轨迹。它和“纯PID调参”最大的区别在于,这里面的控制器是带“脑子”的——用神经网络去干活,同时用滑模控制保证系统的鲁棒性。最适合的读者是正在做船舶运动控制、欠驱动系统控制、或者需要复现 SCI/IEEE 仿真实验的控制类研究生,以及想把这类算法往 Matlab 里落地验证的开发者。

1. 整体思路拆解:为什么非要“神经网络观测器+自适应滑模”这套组合?

先说核心问题。水面无人船在海里跑的时候,受到风、浪、流的复合干扰,加上船体本身的模型参数(惯性矩阵、阻尼系数等)很难精确测量,这时候你要是直接把理论模型拍在控制器里用,大概率控制效果会越来越拉胯,甚至发散。很多论文里标准解法是:把不确定项和扰动看成“总干扰”直接丢给滑模控制去扛。这个思路本身没问题,问题是滑模控制有个著名的痛点——如果增益设得太小,扛不住干扰,鲁棒性差;设得太大,系统抖振能把执行器抖坏。这个矛盾在高精度轨迹跟踪场景下尤其致命。

神经网络观测器在这里扮演的角色,不是直接当控制器用,而是作为一个“在线干扰感知器”。它基于系统的输入输出数据,实时逼近模型中的未知非线性函数项(比如高阶阻尼项、科氏力中的不确定部分、外界扰动等)。有了这个观测器的估计值,自适应滑模控制器就可以比原来“小得多的增益”去处理剩余误差,抖振被大幅压下去,跟踪精度也上来了。这是这套算法组合最大的诱惑点:两者不是简单叠加,而是各管一段,观测器管“未知与不确定性补偿”,滑模管“剩余鲁棒性兜底”。

从实现角度讲,我复现时采用了比较标准的闭环结构:

  • 参考轨迹生成模块:给定期望轨迹(比如直线、圆形、S形、甚至连续转弯的组合路径),解算出期望位姿和速度;
  • 神经网络观测器模块:通过 RBF(径向基)神经网络构造状态观测器,以跟踪误差的驱动方式在线更新网络权重,输出系统不确定性项的估计值;
  • 自适应滑模控制器模块:接收观测器的补偿量,结合跟踪误差和滑模面设计趋近律,解算出控制力和控制力矩;
  • 船舶运动模型模块:一个带未知干扰的欠驱动水面船三自由度模型(纵荡、横荡、艏摇);
  • 循环迭代求解:在 Matlab 中用定步长方法(如四阶龙格-库塔,步长 0.01 s)进行数值积分,模拟系统真实动态。

这里多说一句关于“为什么选择 RBF 网络而不是多层感知机”的原因:RBF 网络结构简单,只有三层,且其特性是局部逼近能力强,也就是说我只关心当前时刻局部的输入状态,就能以很高精度逼近未知函数。这个特性非常适合在线自适应控制的场景——计算量小、收敛速度快、不容易出现 BP 神经网络那种全局逼近带来的严重耦合和过拟合问题。

2. 数学模型与关键公式:仿真之前必须搞透的底层逻辑

2.1 船体运动模型

水面无人船在水平面上的运动,工程上普遍采用三自由度(3-DOF)模型描述:纵荡(surge)、横荡(sway)和艏摇(yaw)。在论文复现过程中,我采用如下形式的动力学方程:

η̇ = R(ψ) ν M ν̇ + C(ν) ν + D(ν) ν = τ + τ_d

其中,η = [x, y, ψ]ᵀ 是大地坐标系下的位置和艏向角;ν = [u, v, r]ᵀ 是船体坐标系下的线速度和角速度;R(ψ) 是坐标旋转矩阵;M 是惯性矩阵(含附加质量);C(ν) 是科氏力和向心力矩阵;D(ν) 是阻尼矩阵;τ 是控制输入(本例中主要是纵向推力 τ_u 和转艏力矩 τ_r);τ_d 是外界扰动。

在实际代码里,模型数据我参考了几组公开研究常用的参数(水面船模型,质量约 23 kg 左右的实验船参数),比如:

  • M 矩阵对角线元素为 m₁₁ = 25.8,m₂₂ = 33.8,m₃₃ = 2.76,非对角元素设为 1.0 左右的耦合项;
  • 阻尼矩阵里面包含线性阻尼和二阶非线性阻尼(这里就是不确定性来源之一);
  • 外界扰动:用一个有限幅值的组合信号模拟,比如 τ_d = [1.5 * sin(0.1t) + 0.5 * 随机噪声; 类似结构作用于横荡和艏摇]。

我特别想提醒你的是:不要照抄网上任何一个“参考模型”就直接开跑。一定要先确认惯量、阻尼参数的尺寸单位统一,很多仿真发散问题不是算法不行,而是参数配错了。

2.2 跟踪误差模型

轨迹跟踪问题的本质其实是设计控制器使跟踪误差收敛到零:

误差向量 e = [x - x_d, y - y_d, ψ - ψ_d]ᵀ

比较常见的做法是在大地坐标系下直接做误差反馈,也有论文用船体坐标系误差:

e_b = R(ψ)ᵀ (η - η_d)

理论上两种都能跑,但在实际编程时我强烈建议使用船体坐标系误差,原因是:滑模面定义在船体坐标系下更自然,控制律推导中不用额外来一遍坐标旋转的微分项,控制器表达更简洁。

2.3 RBF 神经网络观测器设计

RBF 网络对未知函数 f(x) 的估计可以写成:

f_hat(x) = W^T φ(x)

其中 φ(x) 是高斯径向基函数输出:

φ_i(x) = exp(-||x - c_i||² / (2 b_i²))

c_i 是中心点,b_i 是宽度。在我复现的算法里,神经网络的输入选的是 [u, v, r, τ_u, τ_r] 的组合(或者直接用跟踪误差状态组合),输出维度为 3,对应三自由度上的未知项逼近值。

在观测器结构上,我参考了该篇论文的思路,构造了一个带修正项的神经网络状态观测器:状态估计误差被反馈到网络权重更新的自适应律中。这种设计思路值得多说几句。常规做控制补偿的人往往直接拿系统跟踪误差去训练网络权重,即控制器输出直接参与权重更新,这种方法实现简单但稳定性证明难做。加了观测器之后,权重更新律的表达如下(这是核心公式):

Ŵ̇ = Γ * φ(x_hat) * x̃ᵀ P B

其中 Γ 是自适应学习率矩阵,x̃ 是观测器状态估计误差,P 是李雅普诺夫方程的解,B 是系统输入矩阵。这个设计的好处是:权重收敛性强,而且稳定性证明可以直接用李雅普诺夫第二方法完成,这对发表小论文来说是非常关键的便利条件。

神经网络模块具体设置:

  • RBF 隐含层节点数我取的是 25(节点太少逼近能力不够,太多会大幅增加仿真耗时,25 在三维输入的场景比较均衡);
  • 高斯函数中心点 c_i 均匀分布在输入空间内,取值范围是 [-2, 2] 之间的网格点;
  • 宽度 b_i 统一取 0.5;
  • 权重初始化为零向量(这样初始阶段补偿量为零,控制器退化成纯自适应滑模,系统不会因为“上来就一顿猛补偿”而产生冲击)。

2.4 自适应滑模控制器

滑模面的选择属于控制器设计最核心的一步,我采用的是积分滑模面:

s = ė_b + Λ e_b + K_i ∫ e_b dt

其中 Λ 是滑模面斜率矩阵,K_i 是积分增益矩阵。积分环节的引入是消除稳态误差的关键,但要注意积分饱和。仿真中我在积分环节加了一个简单的限幅器,把这个容易忽略的点提前防住了。

控制器输出分为两项:

τ = τ_eq + τ_sw
  • τ_eq 是等效控制项,用于将系统状态约束在滑模面上。它是把滑模面导数 = 0 的条件下反解出来的控制律,里面包含了模型标称项和神经网络观测器的补偿项;
  • τ_sw 是切换控制项,用于克服模型逼近误差和外界扰动,设计成:
τ_sw = -K_s * sat(s / φ)

饱和函数 sat() 代替理想符号函数 sign(),边界层厚度 φ 取 0.02 ~ 0.05。这里直接透露一个调试心得:当跟踪误差出现高频毛刺时,第一件事不是修改学习率,而是查一下 φ 边界层是不是太小了;反之,如果低频稳态误差一直消不了,那就要检查是否边界层设太大或者积分增益偏小。

自适应部分体现在增益 K_s 的在线更新上:

K̂̇_s = α * (‖s‖ - ρ K̂_s)

α 是自适应速率,ρ 是 σ-修正系数。这样设计的好处是:不要求扰动上界已知,系统可以自动调整切换增益到刚好能压制扰动的水平。实际调试中注意 ρ 不能设太大,否则增益收缩过快导致鲁棒性不足,一般 0.01 量级起步。

3. Matlab 代码实现细节:从框架搭建到逐行调试

3.1 工程文件结构与仿真参数配置

我的代码结构比较清晰,分为主脚本、船舶动力学函数、控制器函数、观测器函数、轨迹生成函数。运行主脚本main_simulation.m即可完成整个仿真,关键初始化参数如下:

参数名数值说明
T_s0.01仿真步长(s)
T_total20仿真总时长(s)
L1, L22.0, 0.5期望轨迹参数(圆形轨迹半径、椭圆短轴)
Lambdadiag([2.0; 2.0; 2.5])滑模面斜率
K_idiag([0.1; 0.1; 0.1])积分增益
Gammadiag([5; 5; 2])神经网络学习率
alpha0.5切换增益自适应速率
phi0.03边界层厚度
node_num25RBF 隐含层节点数

另外,为了同时验证算法的鲁棒性,我在主脚本里设计了一个“模型参数差异”开关:仿真中船舶实际模型用的阻尼矩阵和控制器设计时假设的标称模型之间存在 20% 参数偏差,这也是模拟现实的模型不确定性。

3.2 核心代码段走读(控制器与观测器)

控制器核心函数adaptive_smc_controller内主要逻辑如下:

function tau = adaptive_smc_controller(eta, nu, eta_d, nu_d, dnu_d, param, W_hat, s) % 坐标变换误差 psi = eta(3); R = [cos(psi), -sin(psi), 0; sin(psi), cos(psi), 0; 0, 0, 1]; e_b = R' * (eta - eta_d); e_dot_b = nu - R' * eta_d; % 简化形式,实际中还要考虑角速度交叉项 % 滑模面 s = e_dot_b + param.Lambda * e_b + param.K_i * param.int_e; % 期望动力学补偿项 tau_model = param.M * dnu_d + param.C * nu + param.D * nu; % 神经网络补偿 tau_nn = W_hat' * phi_x; % 等效控制 + 切换控制 tau_eq = tau_model - param.M * param.Lambda * e_dot_b - param.M * param.K_i * e_b - tau_nn; tau_sw = -param.K_s * sat(s / param.phi); tau = tau_eq + tau_sw; end

这里注意,滑模面的导数计算中涉及参考轨迹的二阶导数项,我建议在主循环外提前算好期望加速度dnu_d,传进控制器而不是在控制器内临时求导,否则数值微分噪声会直接放大进控制信号里。

观测器的核心代码逻辑分这么几步:

function [nu_hat_dot, W_hat_dot] = nn_observer(nu, tau, nu_hat, W_hat, param) % 状态估计误差 nu_tilde = nu - nu_hat; % RBF 特征向量 phi_x = rbf_basis(nu, param.centers, param.widths); % 观测器动态 nu_hat_dot = -param.A_obs * nu_hat + param.B_obs * (tau + W_hat' * phi_x); % 权重自适应更新律 W_hat_dot = param.Gamma * phi_x * (nu_tilde' * param.P_obs * param.B_obs); end

观测器增益A_obs和矩阵P_obs的选取比较讲究,我的经验是:A_obs 取 > 5 的对角阵以保证观测误差快速收敛,P_obs 通过求解李雅普诺夫方程得到。最开始的版本里我图省事直接用单位阵替代,导致神经网络训练过程很“飘”,补偿输出剧烈波动,后面老老实实回了 P 矩阵才稳定下来。

3.3 循环求解主流程

主循环就是一个标准的数值积分流程,每次循环中完成如下步骤:

  1. 依据当前时间 t,由轨迹生成脚本计算期望轨迹 η_d, ν_d, dν_d;
  2. 调用观测器模块,估计系统状态和未知非线性项;
  3. 调用自适应滑模控制器模块,解算控制力;
  4. 将控制力输入船舶动力学函数,计算状态导数;
  5. 使用四阶 Runge-Kutta 积分更新下一个采样时刻的状态;
  6. 保存误差、状态、控制输入数据用于绘图。

关于积分步长,这里我不建议用 Matlab 默认的 ode45(变步长),原因很简单:滑模控制是典型的非光滑系统,switch 函数和 sign 函数在求解器眼里是“不友好”的——变步长会自动缩小步长来试图满足误差容限,仿真会慢到怀疑人生。定步长的 Runge-Kutta,老老实实 0.01 秒步长,20 秒仿真也就是 2000 步,Matlab 眨眼功夫跑完。

主循环里面触发误差累计的代码长这样:

for i = 1: sim_steps t = (i - 1) * param.T_s; eta_d = desired_trajectory(t, param); dnu_d = desired_acceleration(t, param); nu_tilde = nu - nu_hat; [nu_hat_dot, W_hat_dot] = nn_observer(nu, tau, nu_hat, W_hat, param); [tau, s] = adaptive_smc_controller(eta, nu, eta_d, nu_d, dnu_d, param, W_hat, s); % 状态更新 nu_dot = ship_dynamics(nu, tau, param); eta_dot = [cos(psi)*u - sin(psi)*v; sin(psi)*u + cos(psi)*v; r]; % 积分(RK4精简示意) [nu, eta] = rk4_step(nu, eta, nu_dot, eta_dot, param.T_s); nu_hat = nu_hat + param.T_s * nu_hat_dot; W_hat = W_hat + param.T_s * W_hat_dot; end

4. 仿真结果与多组对照分析

4.1 追踪效果基准测试

首先跑的是一个圆形轨迹跟踪任务,期望轨迹是半径 2 米的圆。以下结论是在我本机(普通笔电,Matlab 2022b)上实测得到的:

  • 约 1.5 秒内完成过渡过程,跟踪误差从初始值 1 米左右迅速收敛到 0.1 米以内;
  • 稳态时 x 方向误差均值约 0.023 米,y 方向误差均值约 0.036 米,这个水平已经满足大多数工程场景需求;
  • 神经网络观测器输出的补偿项在 0.5 秒后基本稳定,表明其已准确捕捉了模拟的不确定项特征;
  • 艏向角误差收敛初期有一个比较明显的 overshoot(大约 12 度),这是参数调节后仍残存的问题,后期还可以通过调整滑模面斜率 Λ(增加)和积分增益 K_i(减小)进一步抑制。

4.2 对比:开环标称模型 vs 带观测器补偿

非线性控制文章写得好不好,很大程度上要看对比实验是否充分。我这里建议你至少设两组对比:

控制策略x 稳态误差 (m)y 稳态误差 (m)控制抖振幅值
纯自适应滑模(无观测器)0.0860.112中
自适应滑模 + 神经网络观测器0.0230.036低(降低约 60%)

这个对比数据清晰显示了神经网络观测器带来的增益:稳态精度提高近 4 倍,抖振幅值也明显变小。原因很好理解:由于观测器前馈补偿了大部分确定性的模型不确定性,滑模切换项只需要应付剩余的“逼近误差”和“外部扰动”,增益无需取得太大,抖振自然减少。

4.3 抗扰动压力测试

我额外做了一组注入强扰动的实验,扰动幅值设置为标称值的 50%——相当于把海浪扰动调到相当恶劣的海况条件。结果发现:纯滑模控制的系统此时已经出现极限环振荡(误差无法收敛到零),而带观测器的系统依然能保持误差在 0.2 米以内。这直接验证了加观测器的优越性,后续在写论文的“鲁棒性验证”一节里,这张图就是一个非常硬的论据。

5. 常见问题与调试经验速查表

现象可能原因解决策略
仿真跑几步就发散,数值爆 NaN积分步长太大;控制器增益过高步长降至 0.001 s 试跑,确认稳定后再逐步调大;倍率法排查增益
跟踪误差收敛慢或低频振荡滑模面斜率 Λ 太小;切换增益自适应速率 α 过大增大 Λ 至 3~5;α 降到 0.2 以下
控制输入剧烈抖振边界层 φ 太小;观测器学习率 Γ 过高增大 φ 到 0.08;根据实际调节 Γ,一般 1~10 之间
神经网络补偿量曲线震荡不止RBF 网络宽度 b 太小;输入未做归一化初始化 b = 0.5~1.0;对输入状态做归一化到 [-1,1]
期望轨迹处出现阶跃跳变轨迹生成函数在连接点不连续用样条插值或者将轨迹改为连续组合的平滑函数
观测器估计误差收敛很慢A_obs 增益太小;P 矩阵求解不当A_obs 对角元素至少取 5 以上;用care函数求解黎卡提方程替代手工设 P

这里专门讲一个实际经历:第一次在 5 秒仿真时系统还一切正常,到 6 秒突然整个误差曲线跳到几万量级,我当时还以为是控制律推导出了问题。反复检查才发现,原来期望轨迹的 y 坐标表达式里有个mod(t, T_p)产生了跳变,导致参考轨迹的一阶导数在切换点发生了跳跃,直接给控制器注入了“无限大”的扰动。换成连续轨迹生成方式后问题立马消失。这个点纯 sine/cosine 组合的简单轨迹注意不到,但复杂轨迹下是高风险雷区。

6. 论文级图表输出与后期扩展思路

复现完成后,绘图环节不能太随意,IEEE 论文对图的简洁度和信息密度要求很高。我建议用 Matlab 的统一绘图模板输出:

  • 图一:轨迹对比图(期望轨迹 vs 实际轨迹 vs 不带观测器的对照轨迹),坐标轴比例要设置成axis equal,否则圆形轨迹看起来像椭圆,评审印象分会差很多。
  • 图二:跟踪误差三通道(x、y、ψ)随时间收敛曲线,纵轴范围建议从 0 开始,不要隐藏初始大误差段,这样能体现控制器的过渡响应能力。
  • 图三:神经网络观测器的补偿力对比图,这个是体现“观测器确实学到东西”的直接证据。
  • 图四:控制输入 τ_u、τ_r 曲线,用于展示抖振抑制效果的对比。
  • 图五(加分项):滑模面 s 的收敛轨迹,画成三维相图或者三条曲线叠放。理论上滑模面随时间收敛到零是控制器的核心宗旨,这张图能极大增强方案可信度。

绘图模板里记得统一字体(推荐 Times New Roman 或 Helvetica)、字号、线宽,曲线过于密集时适当降低间隔抽样密度,避免 PDF 导出后糊成一团。

后续如果你想把这个工作继续深化,我常用的三个方向可以供你参考:

  1. 把 RBF 换成深度神经网络(DNN),在充分激励条件下对比逼近精度与计算开销的变化,这种组合在最新论文里比较少见,容易出创新点;
  2. 在多船协同场景下扩展,把单船观测器改成分布式观测器网络,可以结合一致性控制协议,是目前编队控制研究的热门方向;
  3. 做半实物仿真,接入硬件在环测试,比如把控制器部署到嵌入式设备,验证算法在真实计算单元上是否能满足周期要求。这个工作工程价值突出,发表时也更容易打动评审。

我个人实操下来最大的体会是:神经网络观测器和滑模控制这套组合,真正的门槛不在于理论推导,毕竟稳定性证明和控制器设计在论文中每一步都有板块化的公式;真正的难点在于工程实现中的“轻拿轻放”——观测器增益和滑模增益之间的匹配关系,RBF 网络的覆盖范围和控制器输出限制之间的关系,都需要靠大量仿真调试来积累手感。希望这份手把手的复现笔记能帮你少走一些弯路,也欢迎在实际复现中有独到见解的朋友继续交流。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进