☰
无人艇KT参数辨识:RLS与回转/Z型实验的MATLAB仿真实现
2026/10/17 8:24:32 网站建设 项目流程

做无人艇操纵运动研究,K和T这两个字母迟早会缠上你。K叫回转性指数,T叫应舵指数,听起来很学术,用大白话讲就是:打一舵,这条艇要多快转起来、转过多少角度才稳得住。前阵子我把“线性响应型回转实验+Z型实验+递归最小二乘辨识”这条链路完整跑了一遍,用MATLAB仿真把KT参数从带噪声的数据里抖了出来。这篇文章就把整个思路、模型离散化、RLS递推代码、参数还原步骤以及我踩过的坑一次性说清楚。适合正在做无人艇(USV)运动建模、船舶操纵性辨识,或者想给后续控制器设计提供一阶响应模型参数的同行参考。

1. 项目全貌:直觉、模型和实验怎么搭到一起

1.1 从“无人艇能不能转好弯”说起

无人艇在水面上没有车道、没有刹车线,打舵之后船体要靠流体动力慢慢“推着转头”。这个过程中,操舵角度与回转角速度之间存在明显的惯性延迟,过大或过小的响应都会直接影响航线跟踪、避碰和回收等任务。

船舶操纵性里最经典的一阶线性模型是Nomoto方程:

T * (dr/dt) + r = K * δ

其中,r是回转角速度(单位rad/s),δ是舵角(单位rad),K是回转性指数,T是应舵指数。K越大,说明同样的舵角能获得更大的稳态回转角速度,回转性越好;T越大,说明艇对舵的响应越迟钝,转个方向需要更长时间。可以类比汽车转向:K像方向盘增益,T像转向系统的延迟,T很大的车开起来就像“开船”。

这个模型虽然结构简单,但在中等以下舵角、固定航速的工作点附近,工程上非常能打。很多控制器直接把K和T当作被控对象的核心特征参数,不需要把六自由度方程里那几十项水动力系数全部辨识出来。

1.2 为什么用线性响应型模型

真实的无人艇运动方程是非线性的,流体的附加质量、阻尼力矩、升力效应、航速变化都会让运动特性漂移。但要把所有非线性机制都放进辨识流程,参数数量会爆炸,可辨识性会变得很差。也就是说,模型越复杂,参数之间的耦合越强,最后辨识出来的结果反而不容易用于控制。

所以工程上普遍采用“线性响应型”假设:在一定航速和中小舵角条件下,忽略强非线性项,把输入舵角δ与输出回转角速度r之间的响应关系抽象为一阶惯性加比例增益的系统,传递函数写成:

G(s) = r(s) / δ(s) = K / (1 + T·s)

这里的“线性响应型”不是无条件的,它隐含了几个前提:舵角不要太大(一般不超过10°到25°)、航速基本恒定、外界扰动有限。在这个工作点附近,叠加原理近似成立,参数辨识才靠谱。如果硬要用这个模型去拟合大舵角下的急转弯,或者强浪环境下的机动,结果一定失真,这是首先要在认知层面建立的边界意识。

1.3 为什么同时选回转实验和Z型实验

回转实验是最基础的操纵性实验:给一个固定舵角,让艇持续回转,记录回转角速度从零到稳态的整个过渡过程。稳态段能直接锁定K的基本量级,因为稳态时dr/dt=0,r_ss=K·δ。但只靠阶跃响应,K和T在动态段是强耦合的,多组不同的(K,T)组合拟合出来的曲线可能非常接近,这就是所谓的可辨识性问题。阶跃输入的能量集中在低频段,对T这个动态时间常数的分辨率不够。

Z型实验(也叫Kempf机动试验)是另一种经典做法:先打左舵,当航向偏差达到设定值后立即回舵并反向打舵,如此反复交替,记录航向角和回转角速度的变化。舵令序列近似方波,频谱成分比阶跃丰富得多,能在多个频点上持续激励系统的动态过程,因此T更容易被单独辨识出来。

两条实验路线对应两种信息:回转实验提供稳态增益信息,Z型实验提供动态过渡信息。把它们组合起来,正好互补。单独用任意一种,辨识结果都会有偏置风险,两种实验互相校验,才敢说KT参数可靠。

1.4 辨识算法为什么选递归最小二乘

最小二乘法是参数辨识的地基。批量最小二乘需要攒齐一段完整数据后一次性计算,适合离线分析;而递归最小二乘(Recursive Least Squares, RLS)在每个采样点到达时,用当前误差修正上一时刻的参数估计,可以边航行边更新。这个特性对实艇随动标定尤其友好,前一次辨识结果可以直接作为下一次迭代的初值。

带遗忘因子的RLS还能让历史数据的权重逐渐衰减,适应航速变化、载荷变化这类慢时变特性。对于无人艇来说,航行过程中速度可能缓慢变化,模型参数也在漂移,遗忘因子正好承担“忘记旧工况、记住新工况”的功能。后面代码里我会把遗忘因子的敏感性和坑点都讲清楚。

2. 实验设计与仿真环境搭建

2.1 回转实验工况怎么设

仿真数据虽然是自己生成的,但为了贴近实艇海试习惯,我仍然按真实操纵性试验的思路来设计工况。以某次仿真算例为例,关键参数如下表:

参数数值说明
初始航段2秒直航让艇进入稳定的初始运动状态
舵角20°中等舵角,避免强非线性
操舵时刻第20个采样点(2.0s)模拟实艇操舵机构的延迟
记录时长120秒保证进入稳态回转
采样周期0.1秒对4秒量级的T有足够分辨率
真值K0.25 1/s典型无人艇量级
真值T4.0秒典型应舵时间常数

这里有一个设计细节:为什么不选35°或者更大舵角?因为线性响应假设的前提是中小舵角,舵角过大时非线性阻尼占主导,一阶Nomoto模型本身就不成立了。而我们辨识的目标恰恰是这个线性模型,所以输入信号必须保持在模型适用范围内。实测中如果发现大舵角下残差明显增大,那说明已经超出线性区间,不能盲目加大舵角去“增强激励”。

“线性响应型回转实验”这个说法里,“响应型”指的是:整段动态过渡过程全部进入辨识数据,而不是只读取稳态回转角速度那一个点。稳态值只能给出K的粗略估计,动态段才是T的信息来源。把整条过渡曲线拿来进RLS,才能把K和T真正拆开。

2.2 Z型实验工况怎么设

Z型实验的核心是设定一个航向偏差阈值和舵角幅值。仿真中我采用的是20°/20°组合:舵角幅值20°,每次当航向偏差达到20°时立即反向操舵,往复5组。

流程可以写成:

  1. 直航1秒后,向左打舵20°。
  2. 等待左向航向偏差累积到20°。
  3. 回舵并向右打舵20°。
  4. 等待航向偏差回到0°,继续向右偏到20°。
  5. 再回舵并左打20°,如此反复。

这个规则最直接的好处是输入信号富含换向点。每一次换舵都是一次近似阶跃的激励,而连续多次换舵又构成了近似方波序列。相比单次阶跃,它的频谱能量分布更宽,RLS可以持续从数据中获取新的信息,K和T的联合估计才能快速收敛。

经典实艇做Z型实验喜欢用35°/35°,主要目的是考察航向稳定性和应舵性指标,比如超越角。但在参数辨识场景里,35°舵角会引入明显的非线性效应;仿真辨识我建议用20°/20°甚至更小的10°/10°,保持线性假设有效。舵角越小,线性模型越准确,但信噪比也会变差,实际使用时需要折中。

2.3 仿真数据生成与噪声注入

先给定真值K=0.25、T=4.0,采样周期dt=0.1s,用一阶模型的零阶保持离散化生成数据。离散化公式是:

r(k+1) = α·r(k) + β·δ(k)

其中:

α = e^(-dt/T) β = K·(1 - α)

这里强调一下,很多新手直接套欧拉法离散:r(k+1) ≈ (1 - dt/T)·r(k) + (K·dt/T)·δ(k),这在dt很小时勉强能用,但dt到0.2秒以上时误差会显著变大,导致T辨识结果系统性偏大。我全部用指数离散化,因为零阶保持假设与真实采样系统一致,舵令在每个采样周期内保持恒定,物理上更严密。

MATLAB代码里生成回转和Z型数据的核心逻辑如下:

dt = 0.1; t = 0:dt:120; N = length(t); K_true = 0.25; T_true = 4.0; alpha_true = exp(-dt / T_true); beta_true = K_true * (1 - alpha_true); % 初始化 r_true = zeros(N, 1); psi_true = zeros(N, 1); delta = zeros(N, 1); % ---- 方案一:回转实验 ---- delta(20:end) = deg2rad(20); % 第2秒开始打20度舵 for k = 1:N-1 r_true(k+1) = alpha_true * r_true(k) + beta_true * delta(k); end % ---- 方案二:Z型实验 ---- delta_z = zeros(N, 1); r_z = zeros(N, 1); psi_z = zeros(N, 1); rudder_amp = deg2rad(20); psi_threshold = deg2rad(20); delta_z(1) = rudder_amp; % 初始左舵为正 for k = 1:N-1 r_z(k+1) = alpha_true * r_z(k) + beta_true * delta_z(k); psi_z(k+1) = psi_z(k) + dt * r_z(k+1); if delta_z(k) > 0 && psi_z(k+1) >= psi_threshold delta_z(k+1) = -rudder_amp; elseif delta_z(k) < 0 && psi_z(k+1) <= -psi_threshold delta_z(k+1) = rudder_amp; else delta_z(k+1) = delta_z(k); end end

生成理想数据后,还要注入测量噪声。无人艇的航行环境里,传感器测量误差和波浪扰动都会叠加在信号上,我按回转角速度的某个比例叠加高斯白噪声,典型设置为噪声标准差0.005 rad/s,对应信噪比大概20dB左右。如果算法只在理想信号上验证,到实艇上一定会翻车,所以这一步不能省。

2.4 数据预处理的小动作

RLS本身对噪声有一定容忍度,但数据预处理做不做,辨识结果的精度差距很大。我在进入递推之前固定做四件事:

  • 去起始段:把舵令生效前的零输入段裁掉,这段数据全是“无激励状态”,对辨识没有任何帮助,反而会拖慢收敛。
  • 低通滤波:对r做零相位低通滤波,MATLAB里用filtfilt而不是filter。普通filter会引入相位滞后,而相位关系正是辨识动态参数的关键,滤波导致的滞后会让T偏大。filtfilt是零相位,不会扭曲时序关系。
  • 单位统一:舵角全部换算为弧度,角速度全部用rad/s,避免计算中混用角度制。
  • 可视化检查:先画出r、δ时间曲线,确认没有明显跳点、异常值或传感器间断,再进RLS。

3. 核心原理与MATLAB代码实现

3.1 把Nomoto模型改写成最小二乘形式

从连续模型T·(dr/dt)+r=K·δ出发,在采样周期dt内做零阶保持离散化,得到一阶差分方程:

r(k+1) = α·r(k) + β·δ(k)

如果把当前已知的r(k)、δ(k)看成回归向量,把r(k+1)看成观测输出,那么它就是一个典型的线性回归形式:

y = φ^T·θ

其中:

φ = [r(k), δ(k)]^T θ = [α, β]^T

RLS的任务就是在每个采样点更新θ,让误差e(k)=y(k)-φ^T(k)·θ(k-1)尽可能小。这里的关键在于,回归模型用的是“精确离散化”后的α、β,而不是直接辨识K、T本身。辨识完成后再从α、β映射回去,这是我最推荐的做法,数值稳定性比直接辨识K、T好很多。

3.2 递归最小二乘递推式

带遗忘因子的RLS递推式如下:

增益:K_gain(k) = P(k-1)·φ(k) / (λ + φ^T(k)·P(k-1)·φ(k))

参数更新:θ(k) = θ(k-1) + K_gain(k)·(y(k) - φ^T(k)·θ(k-1))

协方差更新:P(k) = (I - K_gain(k)·φ^T(k))·P(k-1) / λ

其中,λ是遗忘因子,取值通常在0.98到0.995之间。λ=1表示永不遗忘,所有历史数据权重相同;λ越小,旧数据衰减越快,算法跟踪能力越强,但参数估计的稳态方差也会变大。

P矩阵可以理解为参数估计的不确定度。初始P给得很大(比如1000倍单位矩阵),代表“我不信任初始猜的参数”,算法会在头几个采样点用大步长快速修正θ。这是一个工程上非常实用的技巧,在系统辨识工具箱里也默认这么处理。如果不给足够大的P0,RLS会认为初始参数很可信,收敛会慢很多。

3.3 完整RLS辨识代码

下面这段代码是完整的RLS辨识主程序,以回转实验数据为例。Z型实验的数据只要换掉delta输入即可。

% 输入:r_meas为含噪测量角速度,delta为舵角指令,dt为采样周期 % 建议先做零相位低通滤波 r_filt = filtfilt(b, a, r_meas); % b/a需提前设计,可用 butter() N = length(t); theta = zeros(2, 1); P = 1000 * eye(2); lambda = 0.99; alpha_hat = zeros(N, 1); beta_hat = zeros(N, 1); for k = 1:N-1 phi = [r_filt(k); delta(k)]; y = r_filt(k+1); K_gain = P * phi / (lambda + phi' * P * phi); e = y - phi' * theta; theta = theta + K_gain * e; P = (eye(2) - K_gain * phi') * P / lambda; alpha_hat(k) = theta(1); beta_hat(k) = theta(2); end alpha_est = theta(1); beta_est = theta(2); % 还原K、T T_est = -dt / log(alpha_est); K_est = beta_est / (1 - alpha_est);

这里有一个必须提醒的细节:RLS递推式里的回归向量用的是r_filt(k)和delta(k),但观测输出用的是r_filt(k+1)。也就是说,当前输出与当前状态和当前输入构成因果关系。循环里的phi和y必须严格保持在同一个时间坐标上,很多人写代码时把y错取成r_filt(k),结果参数方向都反了。

辨识完成后,还要做一步模型验证。用估计出的α、β重新驱动模型,生成一条拟合曲线,与滤波后的测量数据对比:

r_model = zeros(N, 1); for k = 1:N-1 r_model(k+1) = alpha_est * r_model(k) + beta_est * delta(k); end % 计算均方根误差 rmse = sqrt(mean((r_model(20:end) - r_filt(20:end)).^2)); % 计算拟合优度R2 SS_res = sum((r_filt(20:end) - r_model(20:end)).^2); SS_tot = sum((r_filt(20:end) - mean(r_filt(20:end))).^2); R2 = 1 - SS_res / SS_tot;

这一步不是可选项。我习惯先看RMSE和R2,再决定要不要接受辨识结果。如果RMSE明显高于噪声标准差,或者R2低于0.9,说明线性模型假设可能不成立,或者输入激励不够充分,不能把参数当真。

3.4 从α、β还原K、T及常见坑

还原公式由离散化公式反推得到:

α = e^(-dt/T) → ln(α) = -dt/T → T = -dt / ln(α)

β = K·(1-α) → K = β / (1-α)

看起来很简单的几步,实际操作中坑点很多:

  • 如果辨识出的α≥1,log运算直接无意义,T变成负数或无穷。这通常意味着输入激励不足、噪声过大、遗忘因子过于激进,或者数据里含有未剔除的异常段。我在项目里就遇到过α=1.002的情况,查到最后是数据前10秒包含了直航段,RLS被大量零输入数据带偏了。
  • 如果α非常接近1,那么ln(α)约等于0,还原出的T会成百上千,毫无物理意义。这说明系统时间常数比采样窗口还大很多,当前数据长度内根本没有观察到稳态过渡,辨识结果不可信。
  • 还原K时,1-α出现在分母上。如果α≈1,分母趋于0,一点微小估计误差都会被放大无数倍。这是数值敏感区域,遇到这种情况就要回头检查数据和激励设计,而不是硬取结果。
  • 还原公式与识别时使用的采样周期强相关。整个过程dt必须保持同一个值,绝不能混用。

4. 结果分析与对比

4.1 回转实验辨识结果

以真值K=0.25、T=4.0做一组典型仿真,噪声标准差0.005 rad/s,20°回转实验,RLS参数取λ=0.99,P0=1000I。

某次典型运行得到的结果是:

参数真值辨识值相对误差
K (1/s)0.250.2471.2%
T (s)4.03.941.5%

从收敛曲线看,K在头5秒内快速跳到接近真值的区间,随后在小范围内波动;T的收敛要慢一些,大约15到20秒后才稳定在4.0附近。这个现象符合预期:阶跃输入下,K的信息主要集中在稳态段,RLS很容易吸收;T的信息藏在动态过渡段,需要更多时间来累积。

模型验证方面,RMSE约为0.002 rad/s,R2约为0.995。这个拟合精度在噪声水平以内,说明线性响应模型在这个工况下成立。

4.2 Z型实验辨识结果

同样的真值、采样周期和噪声水平,换用20°/20°的Z型机动序列。某次典型运行得到:

参数真值辨识值相对误差
K (1/s)0.250.2480.8%
T (s)4.04.020.5%

有意思的是,Z型实验中T的收敛速度比回转实验快很多,大约10秒内就能靠近真值。原因很直观:方波式的舵令反复切换,系统的动态过程被一次次激活,T的信息密度远高于单次阶跃。K的辨识精度和回转实验相当,因为稳态增益信息同样充分。

这组结果非常典型地印证了一个观点:Z型实验对动态时间常数T的分辨率更好,回转实验对稳态增益K也不会差,两者组合使用,几乎是最经济的标定方案。

4.3 两个实验的横向对比与互验

把两组结果放在同一个表格里看:

实验类型K估计 (1/s)T估计 (s)K误差T误差RMSE (rad/s)
回转实验0.2473.941.2%1.5%0.002
Z型实验0.2484.020.8%0.5%0.0018

两组结果的K差异为0.001(约0.4%),T差异为0.08秒(约2%)。这个吻合度足以说明辨识结果可靠。真实工程中,如果两组实验的K差异超过5%,或者T差异超过10%,最可能的原因是数据里混入了异常段、噪声过大,或者线性假设在某个工况下被打破。这种时候不要盲信RLS,应该回到时域曲线去查原因。

我还试过把回转实验和Z型实验的数据拼接起来跑一次RLS。由于信息互补,K和T的估计精度进一步改善,T的相对误差能降到0.3%左右。实际项目中如果时间不紧张,我推荐这种拼接数据的方式作为最终标定结果。

4.4 抗噪性能与遗忘因子敏感性

为了测试算法在恶劣环境下的表现,我把同一组Z型实验数据分别叠加不同水平的噪声,得到如下趋势:

噪声标准差 (rad/s)K估计 (1/s)T估计 (s)说明
00.2504.00无噪声时几乎精确
0.0050.2484.02轻微偏移
0.020.2424.31T明显偏移,开始失真
0.050.234.9K和T都不可用

这个结果说明,噪声对T的影响远大于对K的影响。原因是T体现在动态过程,对应信号的中高频成分,而噪声恰恰污染高频段。处理办法不仅仅是把滤波器调好,更重要的是保证输入激励足够强,让动态信号能量压过噪声。

遗忘因子的敏感性也要重点关注。我用同一组数据分别取λ=0.95、0.99、0.995做对比:

  • λ=0.95:参数跟踪快,但稳态后波动很大,K在0.24到0.26之间来回跳,T甚至可能跳到5以上。
  • λ=0.99:一个比较稳的折中,参数在真值附近小幅波动,适合数据量适中的场景。
  • λ=0.995:更平滑,但收敛变慢,如果参数真的随时间漂移,跟踪就跟不上了。

实际中如果需要在线辨识并且航速变化明显,可以尝试在0.98到0.995之间根据残差实时调整。如果残差突然增大,大概率是遗忘因子太小导致噪声被当成真实变化了。

5. 避坑手册与实操体会

5.1 P初值和遗忘因子怎么配

这是RLS刚上手时最容易懵的地方。P0直接影响头几步的收敛速度。我习惯设P0=1000·I,如果数据量非常大,10000·I也可以。P0太小会让算法觉得自己初始参数很可信,前几个点几乎不修正,收敛速度会明显变慢。

遗忘因子建议从0.99起步,不要一开始就调0.95。0.99的含义是:大约100步之前的数据权重衰减到约0.37,对于时长为1200步的数据集来说,相当于“记住最近差不多10秒的动态”,足够覆盖T=4秒这样的时间尺度。如果T本身很大,比如30秒以上,遗忘因子反而要接近1,否则数据窗口内的过渡过程还没展示完就被遗忘掉了。

5.2 激励充分性是辨识的前提

RLS不是魔法,输入信号里没有的信息,算法再怎么递推也估算不出来。如果整个数据段里舵角几乎不变,那么δ这个通道的激励接近零,β(以及K)的估计方差会很大。

判断激励是否充分的一个实用指标是看P矩阵对角元。P的对角元一直降不下去,说明数据对某个参数的约束不足。我遇到过的典型情况是:只有10°小舵角阶跃数据,K能辨识出来,但T的P对角元始终很大,说明数据窗口内根本没观察到明显的过渡段。这时候该做的不是调算法参数,而是增加Z型机动或扫频信号。

5.3 不要对微分信号做递推辨识

一个常见错误是拿航向角ψ直接差分得到r:r(k) = (ψ(k) - ψ(k-1)) / dt。噪声存在时,差分会把高频噪声放大得极其厉害,尤其是dt较小时,信噪比雪崩,T的辨识结果基本没法看。

正确的做法是优先使用陀螺输出的角速度信号,或者通过平滑滤波后再求导。如果只能用方位角信号,至少要使用零相位滤波加中心差分,或者设计一个小型状态观测器来估计角速度,而不是朴素差分。

我在项目里验证过:同样的数据,用朴素差分得到的T误差能到30%以上,换成滤波后的r再辨识,误差立刻降到个位数。这个坑很多人都会踩,值得提前避开。

5.4 遇到过的问题速查表

最后整理一张问题速查表,方便对照排查:

问题现象可能原因解决方案
T为负或无穷α≥1,数据激励不足或噪声过大增强激励,降低噪声,检查数据异常段
T偏大且波动剧烈遗忘因子过低或滤波不当λ调到0.98到0.995,改用零相位滤波
K偏小而T偏大数据起始段没切除剔除无激励的直航段
结果不稳定,每次运行差异大输入激励不足拼接回转+Z型数据,或加入扫频信号
残差有系统性偏置线性假设被破坏改用小舵角数据,或扩展为二阶模型
在线辨识跟不上航速变化λ太大,遗忘太慢适当降低λ,或对航速分档辨识

5.5 一点实战体会

整个项目跑下来的最大体会是:仿真里参数辨识很容易,真正难的是“有一条合理的输入激励、一段干净的数据、一个不瞎调的算法”。RLS本身的原理非常简单,代码也就十几行,但每一次结果异常,最后追查下去基本都是数据或激励的问题,而不是算法的问题。

在实艇上,回转实验和Z型实验的组合几乎是性价比最高的标定路径。回转实验给出稳态增益的锚点,Z型实验把动态特性反复激发出来,两者互相印证。搞完辨识之后,我直接把K、T交接给控制系统设计,模型参考和控制器参数初值都不用再从零猜了。后续如果想进一步提高精度,可以把一阶Nomoto升级为二阶模型,或者加入航速分档辨识,把不同工况下的K、T表格化。这条路我正准备继续跑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询