IMU误差模型与标定:确定性误差与随机误差

各位同学,今天我们来聊聊IMU误差模型与标定。说实话,IMU这东西看着简单,但真正用起来,坑是真不少。我刚开始做自动驾驶融合的时候,就被IMU的零偏坑过——车子停着不动,速度却显示在慢慢漂移。嗯,那感觉就像你明明站着没动,导航却说你在走路。

IMU的误差,说白了分两大类:确定性误差和随机误差。前者可以建模补偿,后者只能靠滤波去估计。我们一个一个来看。

确定性误差:零偏、尺度因子、轴偏差

确定性误差,就是那些有固定规律的误差。你想想看,如果每次测量都偏一个固定值,那是不是很好补偿?对,这就是零偏。

1. 零偏(Bias)

零偏就是当IMU静止时,输出不为零的那个值。比如加速度计平放着,理论上Z轴应该是1g,但实际可能是1.02g。多出来的0.02g就是零偏。

我在项目中遇到过一件事:某款IMU的零偏随温度变化特别大,从-40°C到85°C能漂移好几个mg。后来我们不得不做了温度补偿表,每5°C一个点,插值补偿。所以啊,零偏不是一成不变的,温度、时间都会影响它。

2. 尺度因子(Scale Factor)

尺度因子,就是输入和输出之间的比例关系不准确。比如你转了100°/s,IMU输出却是98°/s。这个2%的偏差就是尺度因子误差。

我习惯把尺度因子写成矩阵形式:

S = [s_x  0   0
     0   s_y  0
     0    0  s_z]

每个轴都有自己的尺度因子,而且它们之间还可能互相影响。嗯,这就引出了下一个问题——轴偏差。

3. 轴偏差(Misalignment)

理想情况下,IMU的三个轴应该是互相垂直的。但实际制造时,总会有几分的偏差。这个偏差会导致一个轴的测量值串扰到另一个轴上去。

我曾经调试过一个系统,发现Y轴有加速度时,X轴也跟着有反应。查了半天,原来是轴偏差导致的串扰。补偿矩阵长这样:

M = [1     α_xy  α_xz
     α_yx  1     α_yz
     α_zx  α_zy  1   ]

其中α就是轴间的偏差角度,单位通常是弧度。

确定性误差补偿公式:
ω_true = M^(-1) * S^(-1) * (ω_raw - b)
其中b是零偏,S是尺度因子矩阵,M是轴偏差矩阵。

随机误差:角度随机游走与速率随机游走

确定性误差可以补偿,但随机误差就没那么听话了。随机误差是IMU内部噪声的体现,说白了就是——你永远不知道下一秒它会偏多少。

1. 角度随机游走(Angle Random Walk, ARW)

角度随机游走是陀螺仪的白噪声积分结果。你想想看,白噪声是随机的,积分之后就成了随机游走。这个误差的单位是 °/√h,表示每小时的均方根漂移。

我习惯用Allan方差来提取ARW值。具体做法是:采集静止数据,然后做Allan方差分析,在斜率-1/2处读取数值。

2. 速率随机游走(Rate Random Walk, RRW)

速率随机游走是陀螺仪零偏的慢变漂移。它不像ARW那样高频抖动,而是像潮水一样慢慢涨落。RRW的单位是 °/h/√h,或者更直观地说,是零偏的变化率。

为什么会这样?因为IMU内部的温度变化、电路老化等因素,会导致零偏随时间缓慢变化。这个变化本身也是一个随机过程。

我的经验:
在卡尔曼滤波中,ARW通常作为过程噪声的Q矩阵对角元素,而RRW则作为零偏状态的过程噪声。两者缺一不可,否则滤波会发散。

Allan方差分析:读懂IMU的噪声指纹

Allan方差,说白了就是IMU的噪声体检报告。它能告诉你:你的IMU到底有多吵,噪声成分是什么。

Allan方差曲线有典型的形状:

  • 斜率-1/2段:对应角度随机游走(ARW)
  • 斜率0段(平底):对应零偏稳定性(Bias Instability)
  • 斜率+1/2段:对应速率随机游走(RRW)
  • 斜率+1段:对应量化噪声

我给大家一个简单的Python代码,用来计算Allan方差:

import numpy as np

def allan_variance(data, fs):
    """计算Allan方差
    data: 输入数据(静止状态)
    fs: 采样率(Hz)
    """
    N = len(data)
    max_m = int(np.log2(N)) - 1
    tau = np.zeros(max_m)
    avar = np.zeros(max_m)
    
    for m in range(1, max_m + 1):
        tau[m-1] = m / fs
        # 分块平均
        block_size = m
        num_blocks = N // block_size
        blocks = data[:num_blocks * block_size].reshape(-1, block_size)
        means = np.mean(blocks, axis=1)
        # 计算方差
        avar[m-1] = 0.5 * np.mean((means[1:] - means[:-1])**2)
    
    return tau, avar
注意:
Allan方差分析需要足够长的静止数据。我一般建议至少采集2小时以上,采样率100Hz以上。数据太短,长相关时间的噪声特征就看不出来了。

六面法标定流程

六面法,是标定加速度计确定性误差的经典方法。说白了,就是利用重力这个已知的参考,来反推IMU的误差参数。

具体做法是这样的:

  1. 将IMU固定在水平平台上,分别让六个面朝上(+X, -X, +Y, -Y, +Z, -Z)
  2. 每个位置采集30秒以上的静止数据
  3. 取每个位置的平均值
  4. 建立方程组,求解零偏、尺度因子、轴偏差

我给大家一个简化的标定模型:

# 六面法标定加速度计
# 假设六个位置的测量值分别为 a_xp, a_xn, a_yp, a_yn, a_zp, a_zn
# 每个位置的理论值应该是 [0, 0, g] 或 [0, 0, -g] 等

# 建立观测方程
# a_measured = S * M * a_true + b

# 其中 a_true 是已知的重力向量
# 通过最小二乘法求解 S, M, b

我在实际项目中,六面法标定后,加速度计的精度从几十mg提升到了几个mg。效果还是很明显的。不过要注意,六面法只适用于加速度计,陀螺仪的标定需要转台或者多位置法。

标定后的验证:
标定完成后,一定要做验证实验。我的习惯是:
1. 静止测试:看零偏是否接近0
2. 旋转测试:看角度积分是否准确
3. 温度循环:看误差是否随温度变化

好了,IMU误差模型和标定就讲到这里。这些内容看起来有点枯燥,但却是传感器融合的基础。你想想看,如果IMU的误差都没搞清楚,后面做融合滤波,那不就是空中楼阁吗?

我个人建议,大家拿到一个新IMU,第一件事就是做Allan方差分析和六面法标定。把这两个事情做扎实了,后面的融合工作会顺利很多。


可可精品资料库