4. 传感器仿真建模:IMU、GPS、气压计与噪声注入

传感器仿真,说白了就是给飞控造一个「虚拟的感知世界」。你想想看,在HIL测试里,飞控芯片跑的是真实代码,但它以为自己在天上飞。它读到的加速度、角速度、位置、高度,全是我们通过模型算出来喂给它的。

我个人习惯把传感器建模分成两块:理想模型和误差模型。理想模型告诉你「应该是什么值」,误差模型告诉你「实际传感器有多烂」。两者加在一起,才是真实的仿真。

核心原则:仿真不是越精确越好,而是越「像真实传感器」越好。精度太高反而掩盖了算法缺陷。

4.1 IMU模型:加速度计与陀螺仪

IMU是飞控最核心的传感器。加速度计测比力,陀螺仪测角速度。注意,加速度计测的不是重力加速度,而是「载体受到的惯性力与重力的合力」。我在项目中遇到过有人直接把加速度计输出当重力方向用,结果悬停时没问题,一加速就炸了。

4.1.1 理想IMU模型

理想情况下,IMU输出就是载体坐标系下的真实物理量。假设机体坐标系为b系,导航坐标系为n系,那么:

// 加速度计理想输出(比力)
f_b = C_n^b * (a_n - g_n)

// 陀螺仪理想输出(角速度)
ω_b = ω_nb^b

其中C_n^b是旋转矩阵,a_n是导航系下的加速度,g_n是重力向量。嗯,这里要注意:加速度计永远测不到重力本身,它测的是「你推它的力」。自由落体时加速度计输出是0,这个坑我见过不少人踩。

4.1.2 误差模型与注入

真实IMU有三大类误差:

误差类型 来源 典型值(消费级) 仿真注入方式
常值偏置 制造偏差、温度漂移 加速度计:±50 mg
陀螺仪:±5 °/s
加固定常数
随机游走 热噪声、电路噪声 加速度计:0.01 m/s²/√Hz
陀螺仪:0.1 °/s/√Hz
高斯白噪声积分
尺度因子与交轴耦合 安装误差、灵敏度偏差 尺度因子:1±0.01
交轴:< 1°
矩阵乘法
我的经验:常值偏置最容易测出来,飞控一般有在线标定。真正让滤波器头疼的是随机游走。我建议仿真时把随机游走系数设得比datasheet大20%,给算法留点余量。

下面是我常用的IMU误差注入代码框架:

// IMU误差注入函数
void imu_error_inject(ImuData *ideal, ImuData *noisy, ImuErrorParam *param) {
    // 1. 加常值偏置
    noisy->accel.x = ideal->accel.x + param->accel_bias_x;
    noisy->gyro.z = ideal->gyro.z + param->gyro_bias_z;

    // 2. 加随机游走(累积)
    static float accel_rw_x = 0;
    accel_rw_x += param->accel_rw_std * randn() * sqrt(dt);
    noisy->accel.x += accel_rw_x;

    // 3. 尺度因子与交轴
    noisy->accel = scale_matrix * noisy->accel;
}

4.2 GPS模型

GPS仿真比IMU简单,但坑也不少。GPS输出的是位置和速度,更新频率低(通常5-20Hz),而且有延迟。

4.2.1 理想GPS模型

理想GPS直接输出导航系下的位置和速度。假设真实位置为p_n,速度为v_n:

// GPS理想输出
pos_gps = p_n + [0, 0, -altitude]  // 经纬高格式
vel_gps = v_n

注意GPS高度是椭球高,不是气压高。我见过有人直接把GPS高度当海拔用,结果在山区飞控高度控制一直震荡。

4.2.2 GPS误差特性

GPS误差有几个关键点:

  • 水平精度:典型2-5米(单点定位),差分GPS可以到厘米级
  • 垂直精度:比水平差,典型3-8米
  • 速度精度:0.1-0.5 m/s(多普勒测速)
  • 更新延迟:50-200ms,取决于接收机处理时间
  • 丢星:城市峡谷、树荫下会短暂丢失
曾经踩过的坑:有一次我在HIL里把GPS延迟设成0,飞控融合滤波效果特别好。结果真机上电一飞,位置估计直接发散。后来才发现GPS延迟对滤波器收敛影响极大。建议仿真时至少加100ms延迟。

GPS误差注入我一般这样处理:

// GPS误差注入
void gps_error_inject(GpsData *ideal, GpsData *noisy, GpsErrorParam *param) {
    // 位置误差:高斯白噪声 + 相关噪声
    static float pos_err_x = 0;
    pos_err_x = 0.9 * pos_err_x + 0.1 * param->pos_std * randn();
    noisy->lat = ideal->lat + pos_err_x / DEG_TO_METER;

    // 速度误差
    noisy->vel_n = ideal->vel_n + param->vel_std * randn();

    // 延迟模拟:用环形缓冲区
    static GpsData buffer[10];
    static int idx = 0;
    buffer[idx] = *noisy;
    idx = (idx + 1) % 10;
    *noisy = buffer[(idx - DELAY_STEPS + 10) % 10];
}

4.3 气压计模型

气压计用来测高度,原理很简单:气压随高度指数衰减。但实际用起来问题很多。

4.3.1 标准大气模型

国际标准大气(ISA)公式:

// 气压高度换算(对流层,0-11000m)
P = P0 * (1 - 0.0065 * h / T0)^5.2561

// 反算高度
h = (T0 / 0.0065) * (1 - (P / P0)^(1/5.2561))

其中P0=101325 Pa,T0=288.15 K。注意这个公式假设标准大气,实际天气变化会导致气压偏移。

4.3.2 气压计误差源

误差源 影响 典型幅度 仿真方法
温度漂移 零位偏移 ±1.5 m/°C 加温度相关偏置
风压扰动 高频噪声 ±0.5 m 高斯白噪声
天气变化 低频漂移 ±10 m/小时 随机游走
气流冲击 瞬时跳变 ±3 m 脉冲噪声
建议:气压计最怕的是气流冲击。无人机悬停时旋翼下洗气流会直接冲击气压计,导致高度估计跳变。我在仿真里会加一个「旋翼气流扰动」模型,频率和旋翼转速相关,幅度随油门增大。

4.4 噪声与误差注入策略

讲完了各个传感器的误差模型,我们来聊聊怎么把这些误差组合起来。我个人习惯用「误差注入层」的概念:

// 误差注入架构
真实物理量 → 理想传感器模型 → 误差注入层 → 带噪传感器输出
                                    ↓
                            偏置 + 噪声 + 延迟 + 丢包

下面是我在HIL平台里用的误差注入配置结构体:

typedef struct {
    // IMU误差
    float accel_bias[3];      // m/s²
    float accel_rw_std;       // m/s²/√Hz
    float gyro_bias[3];       // rad/s
    float gyro_rw_std;        // rad/s/√Hz
    float scale_factor[3];    // 无量纲

    // GPS误差
    float pos_std_horiz;      // m
    float pos_std_vert;       // m
    float vel_std;            // m/s
    float delay_ms;           // ms
    float dropout_prob;       // 丢星概率

    // 气压计误差
    float press_bias;         // Pa
    float press_noise_std;    // Pa
    float temp_drift_coeff;   // Pa/°C
} SensorErrorConfig;
关键点:误差注入不是越复杂越好。我建议从简单模型开始,先加常值偏置和白噪声,验证飞控能正常工作。然后逐步增加随机游走、延迟、丢包等复杂误差。这样出了问题容易定位。

4.5 传感器仿真整体架构

最后,我把整个传感器仿真建模的流程画成了一张图。你看完应该能明白各个模块怎么配合:

传感器仿真建模整体架构 真实物理量 IMU理想模型 GPS理想模型 气压计理想模型 误差注入层 常值偏置 | 随机游走 | 尺度因子 | 延迟 | 丢包 | 温度漂移 带噪IMU数据 带噪GPS数据 带噪气压计数据 飞控传感器驱动 → 融合滤波 说明:误差注入层可独立开关,方便对比理想/带噪场景下的飞控性能

这张图把整个流程串起来了。你从左边开始看:真实物理量经过三个理想传感器模型,然后进入误差注入层,最后输出带噪数据给飞控。每个环节都可以独立开关,方便调试。

最后提醒一句:传感器仿真模型再逼真,也替代不了真机测试。HIL的价值在于帮你提前发现算法层面的问题,而不是验证传感器本身的特性。别在误差模型上花太多时间精雕细琢,够用就行。