第三节:传感器特性与误差模型

IMU、GPS、磁力计、气压计、里程计——这五个传感器,基本构成了我们做导航融合的“家底”。

说实话,我见过太多人一上来就调卡尔曼滤波参数,结果发现效果不好。为什么?因为根本没搞清楚每个传感器的脾气。你想想看,连传感器的误差特性都没摸透,融合出来的结果能靠谱吗?

3.1 IMU:加速度计与陀螺仪

IMU是导航融合的核心,但也是最“坑”的传感器。我习惯把IMU分成两类:消费级的(比如手机里的)和工业级的(比如用在无人机上的)。

加速度计的主要误差有:

  • 零偏(Bias):静止时输出不为0。我遇到过最夸张的一次,某款国产IMU的零偏竟然有0.5g,相当于一直以为自己在加速。
  • 比例因子误差:输入和输出不成正比。说白了就是“刻度不准”。
  • 交叉轴耦合:X轴受力,Y轴也有输出。这在高精度应用里特别要命。

陀螺仪呢?除了零偏和比例因子,还有个头疼的东西——角度随机游走。这个后面用Allan方差能算出来。

重要提醒:IMU的零偏是随时间变化的。你开机时标定好的零偏,半小时后可能就变了。这就是为什么很多系统需要在线估计零偏。

3.2 GPS:位置与速度观测

GPS的误差模型相对成熟,但陷阱也不少。

GPS误差主要分两类:

  • 公共误差:电离层延迟、对流层延迟、卫星钟差。这些可以通过差分GPS(RTK)消除。
  • 非公共误差:多路径效应、接收机噪声。这些是随机的,很难建模。

我个人习惯把GPS的观测噪声设成高斯白噪声,但实际中你会发现——GPS的误差不是白噪声。尤其是在城市峡谷里,多路径效应会导致误差出现“拖尾”现象。嗯,这里要注意,如果你用标准卡尔曼滤波,遇到这种情况很容易发散。

小技巧:我建议在GPS信号好的时候,先跑一段Allan方差,看看实际噪声特性。别直接套手册上的参数。

3.3 磁力计:航向参考

磁力计这东西,说简单也简单,说复杂也复杂。简单是因为原理就是测地磁场,复杂是因为——地磁场太弱了,随便一个电机电流就能把它淹没。

磁力计的主要误差:

  • 硬铁干扰:传感器附近的永磁体造成的固定偏置。比如扬声器、马达。
  • 软铁干扰:铁磁性材料对磁力线的扭曲。这个比硬铁难处理,因为它会改变比例因子。
  • 罗差:安装角度偏差导致的误差。

我曾经在一个机器人项目里,磁力计死活不准。折腾了两天,最后发现是底盘上的一个螺丝钉是铁的。你想想看,一颗螺丝钉就能让航向偏了十几度。

警告:磁力计标定不是一劳永逸的。换一个环境(比如从室内到室外),硬铁干扰就可能变化。我建议每次启动时都做一次快速标定。

3.4 气压计:高度参考

气压计用来测高度,原理很简单——气压随高度变化。但实际用起来,坑也不少。

主要问题:

  • 温度漂移:气压计对温度敏感。我测过一款传感器,温度变化10度,高度读数能漂移2米。
  • 风的影响:无人机在风中飞行时,气压计读数会剧烈抖动。
  • 天气变化:同一个高度,晴天和阴天的气压能差几十帕,对应好几米的高度差。

我个人习惯的做法是:只用气压计的相对变化,不用绝对高度。比如,起飞时记录一个基准气压,然后只关心相对变化量。

3.5 里程计:速度与位移

里程计(轮式编码器)在机器人里很常见。它的误差模型相对简单:

  • 刻度因子误差:轮子直径不准,或者打滑。
  • 量化误差:编码器分辨率有限。
  • 非系统误差:地面不平、轮胎磨损等。

我记得有一次做AGV小车,里程计积分出来的位置和实际差了10%。查了半天,发现是轮胎气压不足,导致轮子直径变小了。嗯,这种坑防不胜防。

3.6 Allan方差建模方法

好了,前面说了这么多传感器的误差特性,那怎么定量分析呢?Allan方差就是干这个的。

Allan方差的本质是:把传感器的输出数据,按不同的时间尺度做方差分析。通过观察方差随积分时间的变化曲线,可以识别出不同类型的噪声。

具体步骤:

  1. 采集一段长时间的静态数据(至少1小时,我建议2小时以上)。
  2. 把数据按不同的时间窗口长度τ进行分段。
  3. 计算每个窗口内的平均值,然后求相邻窗口平均值的差。
  4. 计算这些差值的方差,得到Allan方差σ²(τ)。
  5. 绘制log(σ) vs log(τ)曲线。

从Allan方差曲线上,你能读出:

  • 斜率-1/2:角度随机游走(陀螺)或速度随机游走(加速度计)。
  • 斜率0:零偏不稳定性。这是IMU最重要的指标之一。
  • 斜率+1/2:速率斜坡(低频漂移)。
  • 斜率+1:量化噪声。

下面是一个简单的Allan方差计算代码(Python):

import numpy as np

def allan_variance(data, max_tau):
    """
    计算Allan方差
    data: 传感器静态数据
    max_tau: 最大积分时间
    """
    n = len(data)
    tau_values = []
    avar_values = []
    
    for tau in range(1, min(max_tau, n//2)):
        # 计算每个窗口的平均值
        m = n // tau
        means = np.mean(data[:m*tau].reshape(-1, tau), axis=1)
        # 计算相邻窗口的差值
        diff = np.diff(means)
        # 计算Allan方差
        avar = 0.5 * np.mean(diff**2)
        
        tau_values.append(tau)
        avar_values.append(avar)
    
    return np.array(tau_values), np.array(avar_values)

# 使用示例
# tau, avar = allan_variance(imu_data, 1000)
# 然后绘制log-log图

关键点:Allan方差曲线的最低点对应的τ值,就是传感器的最佳积分时间。在这个时间尺度上,传感器的噪声最小。这个参数对设计滤波器的时间常数很有参考价值。

3.7 实战建议

说了这么多,总结几条我踩过的坑:

  • 别信手册上的参数。每个传感器都有个体差异,一定要自己测。
  • Allan方差要跑够时间。我见过有人只采了10分钟数据就跑Allan方差,结果曲线全是噪声,啥也看不出来。
  • 温度影响不能忽略。尤其是IMU和气压计,温度变化带来的漂移可能比随机噪声还大。
  • 磁力计标定要勤快。每次换环境,最好都重新标定一次。

好了,这一节的内容就到这里。下一节我们会讲怎么把这些误差模型用到卡尔曼滤波里。到时候你会发现——误差模型建得好,滤波器调参少一半