01.3|从日志到模型:最小二乘、激励与残差
上一课列出了物理结构,却没有给某一台机器人填写参数。本课把“猜一个阻尼”“调一个映射”变成可重复的计算。输入是时间对齐后的命令、速度与姿态数据;输出是参数、可辨识性诊断与留出数据上的预测残差。先用单轴模型说明线性回归,再辨识项目水平效能矩阵。所有例子均为离线合成数据,练习不需要连接任何推进器。
开始前:把“拟合”变成一个可以手算的问题
先读 00.3 方程、秩与最小二乘,以及 00.2 导数与时间差分。辨识不是让程序寻找一串看起来合适的数字:先选未知参数,再写每个样本提供的方程,最后检查这些方程是否提供不同信息。先手解本课的三条无噪声方程,再读带噪声的优化推导。
| 符号 | 含义与维度 | 单位/坐标约定 |
|---|---|---|
| 前向相对水速、其导数、已标定推力 | 、、N;前轴 | |
| 有效质量、线性与二次阻尼 | kg、、 | |
| 回归矩阵、力数据、残差 | 每行乘参数后为N | |
| 2通道归一化命令、效能、水平加速度 | 无量纲;为每单位命令 | |
| 命令样本矩阵、加速度样本矩阵、噪声协方差、正则权重 | 为;为;依输出单位 |
线性于参数,不要求线性于速度
暂时限制到单一平移轴,姿态近似固定、海流已知或静水、耦合项可忽略,并且推力已经由推力曲线换成牛顿。动力学对速度含有绝对值,因此是非线性运动方程;但未知参数只以一次乘法出现,所以仍是线性参数回归。每个时刻提供一行,把所有时刻纵向堆叠就得到超定方程。
(1.15)
式先写一行数据,再谈回归
第 行必须来自同一物理时刻或同一个积分窗口。 是已经换算成牛顿的推力, 是机体前向速度分量导数, 是相对水速度;若直接使用对地DVL速度,海流就会被错误地塞进阻尼参数。参数向量 的三个分量不同单位,而回归行三项乘相应参数后都应成为牛顿。
例如 、,参数 预测 。二次阻尼写成 而不是 ,因为反向运动时阻力也要反向。令 且 ,预测推力为 。这个正反号测试应在拟合真实数据之前通过。
平方误差是一个二次函数。对参数求导,先用链式法则产生负回归矩阵转置,再令梯度为零,就得到正规方程。满列秩使解唯一;若列相关,存在多组参数产生同样的预测。正规方程用于手推,实际求解优先QR或SVD,因为显式构造平方矩阵会把条件数平方。TB01-S4
(1.16)
不跳过求导:先对每一个未知参数展开
设 是第 个样本、第 个参数的已知系数, 是未知参数, 是该样本观测。残差与目标函数为
是样本数。只改变第 个参数时,,因为其他参数暂时固定。平方求导产生二,恰好抵消二分之一:
把 三个导数竖着堆起来,才得到 。梯度为零意味着往任何参数方向小改一点都不能一阶降低代价;还要检查 正定,才能保证唯一最小值。满列秩时,对任意非零变化 都有 ,这正是所需条件。样本数大于参数数不保证满秩,重复同一工况仍可能缺信息。
式从几何上说,是让残差垂直于所有解释变量
的微分为 ;将 前的系数转置,就得到梯度。最优时 ,其中 是残差。因此残差与回归矩阵每一列正交,意味着在当前模型允许的方向上继续调整参数不能再降低误差。它不意味着每个残差为零,更不意味着遗漏的物理项不存在。
正规矩阵的逆写法只是闭式表达。手写实现可用带列尺度的QR,或者在本课三参数的小例中使用带主元消元来观察过程。若主元接近零,应报告不可辨识,而不是用极小数替代主元继续生成巨大参数。训练段残差小而验证段残差大时,首先查看工况是否变化以及噪声是否进入回归量。
手算三行辨识:第一行取速度零、加速度1 、推力30 N,立即得到有效质量30 kg。第二行取速度1 、加速度零、推力20 N,得到;第三行速度2 、加速度零、推力64 N,得到。第三式减两倍第二式给,故、。这里两种速度幅值使线性与二次阻尼可以区分;只有一个速度幅值时,无论记录多久都无法完成同样任务。
(1.17)
式是刻意设计的三次实验
第一行隔离质量,后两行隔离阻尼,设计目的不是让数据“好看”,而是让未知数可区分。加速度一的单位为米每二次方秒,所以第一行的三十不是无量纲比例,而是有效质量三十千克。第二、第三行都是稳态点,它们不能单独告诉你质量。
如果将第三行速度二改成速度一,后两行完全相同,方程组不再唯一。即使每行重复采集一百万次,仍然不能修复这个结构问题。实际实验会使用更多有噪声的数据,最小二乘是把这种可区分的关系平均起来;实验设计和估计器不能互相替代。
为什么有些实验“数据很多,信息很少”
若全程匀速,第一列加速度全为零,质量根本未进入观测;若始终以同一速度绝对值运动,后两列成比例,线性和二次阻尼混在一起。激励应覆盖加速、减速、多个速度幅值及正反方向,还应避免执行器一直饱和。用奇异值描述这种信息:最小奇异值接近零意味着某个参数组合几乎不影响输出。比较条件数前,应先按有物理意义的尺度归一化列,否则单位差异会伪装成坏条件数。
(1.18)
式中的奇异值在量什么
和 是左、右奇异向量矩阵,不是前面的控制命令矩阵; 在这里是参数个数,不是位置或角速度。沿某个右奇异向量改变参数一个单位,输出变化大小就是对应奇异值。最小奇异值很小意味着这一组合只能从微弱的输出变化中辨认,因此特别容易受噪声影响。
协方差式还用了回归量无误差与独立同方差残差的假设。若速度含噪声且又被用来构造回归矩阵,这些条件就不满足,公式可能过于乐观。实际判断时同时报告尺度归一化后的奇异值、验证误差和参数物理合理性,不应把很小的训练误差当成参数可靠性的全部证据。
加速度通常不是直接测得的机体分量导数:IMU比力要补重力、偏置和旋转项;速度差分会放大噪声。若速度噪声独立且方差为,前向差分的噪声方差是。更高采样率不自动让差分加速度更干净。可先时间对齐并采用平滑微分,也可把方程在窗口积分,减少直接微分;积分后各行噪声往往相关,需要重新考虑权重。
(1.19)
式说明为何“采样更快”不等于“差分更准”
两帧独立速度噪声相减,方差相加成为 ;除以时间间隔后,方差再除以 。如果速度噪声标准差是 ,间隔 时差分标准差约 ,间隔缩到 则变为 。这不是物理加速度变大,而是微分放大高频误差。
积分式则直接用牛顿方程在窗口内积分。质量项通过微积分基本定理变成端点速度差,阻尼项保留数值积分。实现可用梯形积分,但两端速度误差仍存在,重叠窗口也会引入相关噪声。选择窗口长度是在时间分辨率与噪声之间折中,不是任意越长越好。
若推力本身未知,只知道归一化命令并假设,那么将整个运动方程乘同一个非零比例不会改变预测。没有独立质量或推力标定,能识别的通常是、、,而不是四个绝对物理量。先判断参数是否在数学上可区分,比选择更复杂的优化器更重要。闭环数据还有一个问题:控制命令可能与测量噪声相关,普通最小二乘的无偏条件不再自动成立;应保留独立验证段,必要时用独立激励或工具变量。
项目的水平效能矩阵:两列输入决定四个系数
在一个姿态、速度和负载附近,可把机体水平加速度写成两个归一化通道命令的线性映射。的每列就是只激励一个通道时的两个轴响应。它把推进器、混控、惯性与局部工作点综合在一起,是经验效能,不是六自由度惯性,也不是几何分配。对N条记录,用每行存一个命令,矩阵维度决定了转置的位置。
(1.20)
式怎样逐列恢复水平效能
和 是无量纲前向、侧向命令, 是两维加速度偏置。四个正负轴向样本足以给出直观解:前向正负响应之差除以命令差,得到第一列;侧向正负响应之差得到第二列;对称响应均值给偏置。增广矩阵最后一列全一,使两轴偏置一起作为未知数估计。
例如前向命令 与 的前向加速度差为 ,相除得 ;同样两次实验的侧向加速度差为 ,得到交叉项 。先识别列的物理含义,再写矩阵转置,可避免把“前推引起侧移”与“侧推引起前移”交换。
偏置列吸收小的常值扰动力或传感器零偏;它不应替代明确的重力补偿。若两个命令永远相等,只有一维信息,只能看见两列之和。训练前应先核对实际施加命令,而非饱和前请求。对于项目矩阵,行列式是18.2630,逆映射将目标变成约;代回原矩阵应恢复原目标。
(1.21)
式的逆映射不包含阻尼预测
二阶矩阵求逆来自余子式:对角元素交换、非对角元素反号,再除以行列式。行列式非零表示两个命令在当前线性近似下产生独立的加速度方向。它不保证命令在允许范围内,也不保证离开辨识工作点后仍准确。
本例分子分别是 与 ,再除以 得到两条命令。若目标加速度整体放大十倍,命令也放大十倍,很快会超出归一化边界。将超界命令公共缩放能保持方向,但会牺牲幅值;还需要将可实现加速度反馈给速度积分器。
加权、正则与残差应回答不同问题
噪声方差不同的样本可使用逆协方差加权;正则项则体现参数向先验靠拢,两者不是同一种“平滑”。对下面目标求导仍得到线性方程。是参数尺度或差分结构,0是先验;若用单位阵,必须先把不同单位的参数缩放到可比较尺度。正则能稳定数值,但不能凭空创造未激励方向的信息。
(1.22)
式把可信程度和先验约束分开
是观测噪声协方差,不是参数协方差。若某条力测量标准差是其他测量的两倍,其方差四倍,相应逆方差权重只有四分之一。 控制先验项强度, 给参数尺度或结构, 是先验中心。数据项和先验项各求一次梯度,移项后才得到右端的先验贡献。
当某个方向没有激励时,正则化仍可输出一个数,但该方向主要来自先验。应通过改变先验强度、留出工况与残差结构来理解这个数,而不是把它称为实验发现。程序可先对数据做白化,再把先验伪观测拼成增广最小二乘,避免直接构造一个条件很差的大正规矩阵。
拟合之后看残差,而不是只看参数的小数位。残差均值明显不为零,可能缺偏置;随速度增长,可能缺二次阻尼;与延迟后的命令相关,可能遗漏执行器动态或时间偏移。白残差是支持模型的一条证据,不是物理正确的充分条件。按整段时间划分训练与验证,避免把强相关的相邻样本随机散到两边,制造虚假的泛化表现。
参考实现:C++17,先独立手写再展开
// 独立教学实现:修正Gram-Schmidt QR求最小二乘,C++17
#include <array>
#include <vector>
#include <cmath>
#include <cassert>
#include <stdexcept>
#include <iostream>
using Row=std::array<double,3>;
Row leastSquares(std::vector<Row> X,const std::vector<double>& y){
const int n=static_cast<int>(X.size());
if(n<3 || y.size()!=X.size())throw std::runtime_error("bad shape");
double R[3][3]{}; std::vector<Row> Q(n);
for(int j=0;j<3;++j){
std::vector<double> z(n);for(int k=0;k<n;++k)z[k]=X[k][j];
for(int i=0;i<j;++i){
for(int k=0;k<n;++k)R[i][j]+=Q[k][i]*z[k];
for(int k=0;k<n;++k)z[k]-=R[i][j]*Q[k][i];
}
for(double x:z)R[j][j]+=x*x;
R[j][j]=std::sqrt(R[j][j]);
if(R[j][j]<1e-10)throw std::runtime_error("rank deficient");
for(int k=0;k<n;++k)Q[k][j]=z[k]/R[j][j];
}
Row rhs{},theta{};
for(int j=0;j<3;++j)for(int k=0;k<n;++k)rhs[j]+=Q[k][j]*y[k];
for(int j=2;j>=0;--j){
double value=rhs[j];for(int k=j+1;k<3;++k)value-=R[j][k]*theta[k];
theta[j]=value/R[j][j];
}
return theta;
}
int main(){
auto theta=leastSquares({{1,0,0},{0,1,1},{0,2,4}}, {30,20,64});
assert(std::abs(theta[0]-30)<1e-10);
assert(std::abs(theta[1]-8)<1e-10 && std::abs(theta[2]-12)<1e-10);
std::vector<Row> X{{.2,0,1},{-.2,0,1},{0,.2,1},{0,-.2,1}};
std::vector<double> ax,ay;
for(auto x:X){ax.push_back(5.33*x[0]-.83*x[1]+.03);ay.push_back(1.39*x[0]+3.21*x[1]-.02);}
auto gx=leastSquares(X,ax),gy=leastSquares(X,ay);
assert(std::abs(gx[0]-5.33)<1e-10 && std::abs(gy[1]-3.21)<1e-10);
bool rejected=false;
try { leastSquares({{1,1,1},{2,2,1},{3,3,1}},{1,2,3}); }
catch(const std::runtime_error&){rejected=true;}
assert(rejected);
std::cout<<theta[0]<<" "<<theta[1]<<" "<<theta[2]<<"\n";
}
项目映射:libraries/AC_PosControl 中 update_xy_controller_poshold_impl 生成加速度目标,accel_target_to_xy_thrust 完成姿态转换与效能逆映射。先将除100成为,再对求解;AP_Motors6DOF后续还会限幅,因此辨识数据应记录真正应用的命令。DVLVelocityFilter::update 与惯导输出的时间关系,也决定了命令—加速度配对是否成立。
手写练习:不调用优化库,先用三行数据手解质量和阻尼;然后用四条正负轴向命令求与偏置。答案要点:对每轴正负响应取差除以0.4得到相应列,正负响应取平均得到偏置。把所有命令改成(t,t),再观察最小奇异值和矩阵秩;答案是无法分别恢复两列。最后在验证数据加入0.1 命令延迟,画残差与命令互相关,应出现非零时移结构,而不是简单宣称“噪声增大”。
TB01-S4 · NumPy 开发者:numpy.linalg.lstsq
精读返回的rank与singular values;残差数组为空不等于误差必然为零,应自行计算-X。
从正规方程走到可以手写的QR求解器
为什么参考实现没有直接计算 ?因为两个几乎相关的回归方向在正规矩阵里会变得更难区分。QR方法先把回归列分解为正交方向与上三角系数。令 ,其中 , 是上三角矩阵;下标只是避免与滤波噪声矩阵重名。把残差分成列空间投影和正交补,两部分平方相加,得到:
第二项不含未知参数,因此只需令第一项最小。满列秩时上三角矩阵可逆,从最后一个参数开始回代,便得到 。程序中 rhs 对应右端,逆序循环对应回代;没有任何一步需要显式求逆。若某个对角主元很小,意味着一个回归列几乎落在前面列的张成空间中,应停止并重新设计激励。
教学代码用修正Gram–Schmidt:每次从当前待处理列中减去已知正交列的投影,再归一化。对于差异很大的单位,先按预计参数尺度归一化回归列;高条件数生产问题更适合Householder QR或SVD。此处目的不是重写工业线性代数库,而是让每一次点乘、投影和回代都能与最小二乘推导对应。
你可以继续完成一个不依赖外部库的完整实验:生成前向正负加速与多个稳态速度的数据;用已知参数算出无噪声推力;加入固定随机种子的测量噪声;将前半段用于拟合、后半段用于预测;分别输出每个参数与每条残差。然后删去所有加速段,再运行相同求解器。正确行为不是输出一串看似精确的质量,而是指出质量方向没有信息。将两种实验放在一起,才能真正理解算法和数据各自承担的责任。
零基础停步自检
三个参数记录了一千个完全相同的稳态速度样本,是否一定能辨识?
展开答案与原因
不能。稳态加速度列为零,且相同速度重复不会增加矩阵秩;质量不可辨识,两个阻尼贡献也无法分开。