跳转至

传感器数据融合技术

概述

传感器数据融合是将来自多个传感器的数据进行组合和处理,以获得比单个传感器更准确、更可靠的信息。在嵌入式系统中,数据融合技术广泛应用于姿态估计、导航定位、目标跟踪等领域。本教程将深入讲解卡尔曼滤波、互补滤波等核心算法,并提供完整的实现代码。

为什么需要数据融合

  1. 传感器互补性
  2. 加速度计:长期稳定,但对振动敏感
  3. 陀螺仪:短期准确,但存在累积漂移
  4. 磁力计:提供绝对航向,但易受磁场干扰
  5. 融合后:取长补短,获得最佳性能

  6. 提高精度

  7. 单传感器误差:±5°
  8. 融合后误差:±0.5°
  9. 精度提升10倍

  10. 增强鲁棒性

  11. 单传感器失效时系统仍可工作
  12. 抗干扰能力增强
  13. 系统可靠性提高

  14. 实时性能

  15. 优化算法可在MCU上实时运行
  16. 适合无人机、机器人等应用
  17. 低延迟、高更新率

数据融合方法对比

融合算法对比:

┌──────────────┬──────────┬──────────┬──────────┬──────────┐
│ 算法         │ 计算复杂度│ 精度     │ 实时性   │ 适用场景 │
├──────────────┼──────────┼──────────┼──────────┼──────────┤
│ 简单平均     │ 极低     │ 低       │ 极好     │ 简单应用 │
│ 加权平均     │ 低       │ 中       │ 很好     │ 基础融合 │
│ 互补滤波     │ 低       │ 中高     │ 很好     │ 姿态估计 │
│ 卡尔曼滤波   │ 中       │ 高       │ 好       │ 精确估计 │
│ 扩展卡尔曼   │ 高       │ 很高     │ 中       │ 非线性系统│
│ 粒子滤波     │ 极高     │ 极高     │ 差       │ 复杂系统 │
└──────────────┴──────────┴──────────┴──────────┴──────────┘

选择建议:
- 资源受限:互补滤波
- 精度要求高:卡尔曼滤波
- 非线性系统:扩展卡尔曼滤波
- 实时性要求高:互补滤波

第一部分:互补滤波算法

互补滤波原理

基本思想

互补滤波原理图:

加速度计测量              陀螺仪测量
(长期稳定)              (短期准确)
     │                         │
     │ 低通滤波                │ 高通滤波
     │ (1-α)                   │ α
     │                         │
     └────────┬────────────────┘
         融合输出
      (最佳估计)

数学公式:
θ(t) = α × [θ(t-1) + ω×Δt] + (1-α) × θ_accel

其中:
- θ(t): 当前角度估计
- θ(t-1): 上一次角度估计
- ω: 陀螺仪角速度
- Δt: 时间间隔
- θ_accel: 加速度计测量角度
- α: 滤波系数(0-1)

滤波系数选择:
- α = 0.98: 更信任陀螺仪(常用)
- α = 0.95: 平衡
- α = 0.90: 更信任加速度计

频率特性:
- 高频(快速运动):主要来自陀螺仪
- 低频(缓慢漂移):主要来自加速度计

互补滤波实现

头文件定义

/**
 * @file    complementary_filter.h
 * @brief   互补滤波器实现
 */

#ifndef __COMPLEMENTARY_FILTER_H
#define __COMPLEMENTARY_FILTER_H

#include <stdint.h>
#include <stdbool.h>
#include <math.h>

/**
 * @brief  互补滤波器配置
 */
typedef struct {
    float alpha;            // 滤波系数(0-1,推荐0.98)
    float roll;             // 横滚角(度)
    float pitch;            // 俯仰角(度)
    float yaw;              // 偏航角(度)
    uint32_t last_time_ms;  // 上次更新时间(毫秒)
    bool initialized;       // 初始化标志
} ComplementaryFilter_t;

/**
 * @brief  传感器数据结构
 */
typedef struct {
    float accel_x;          // 加速度X (g)
    float accel_y;          // 加速度Y (g)
    float accel_z;          // 加速度Z (g)
    float gyro_x;           // 陀螺仪X (°/s)
    float gyro_y;           // 陀螺仪Y (°/s)
    float gyro_z;           // 陀螺仪Z (°/s)
} SensorData_t;

// 函数声明
void ComplementaryFilter_Init(ComplementaryFilter_t* filter, float alpha);
void ComplementaryFilter_Update(ComplementaryFilter_t* filter, 
                                SensorData_t* data, 
                                uint32_t current_time_ms);
void ComplementaryFilter_GetAngles(ComplementaryFilter_t* filter,
                                   float* roll, float* pitch, float* yaw);
void ComplementaryFilter_Reset(ComplementaryFilter_t* filter);

#endif /* __COMPLEMENTARY_FILTER_H */

源文件实现

/**
 * @file    complementary_filter.c
 * @brief   互补滤波器实现
 */

#include "complementary_filter.h"

#define RAD_TO_DEG  (180.0f / M_PI)
#define DEG_TO_RAD  (M_PI / 180.0f)

/**
 * @brief  初始化互补滤波器
 * @param  filter: 滤波器结构指针
 * @param  alpha: 滤波系数(0-1,推荐0.98)
 */
void ComplementaryFilter_Init(ComplementaryFilter_t* filter, float alpha) {
    filter->alpha = alpha;
    filter->roll = 0.0f;
    filter->pitch = 0.0f;
    filter->yaw = 0.0f;
    filter->last_time_ms = 0;
    filter->initialized = false;
}

/**
 * @brief  更新互补滤波器
 * @param  filter: 滤波器结构指针
 * @param  data: 传感器数据
 * @param  current_time_ms: 当前时间(毫秒)
 */
void ComplementaryFilter_Update(ComplementaryFilter_t* filter,
                                SensorData_t* data,
                                uint32_t current_time_ms) {
    // 首次调用,初始化角度
    if (!filter->initialized) {
        // 使用加速度计初始化横滚角和俯仰角
        filter->roll = atan2f(data->accel_y, data->accel_z) * RAD_TO_DEG;
        filter->pitch = atan2f(-data->accel_x,
                              sqrtf(data->accel_y * data->accel_y +
                                    data->accel_z * data->accel_z)) * RAD_TO_DEG;
        filter->yaw = 0.0f;
        filter->last_time_ms = current_time_ms;
        filter->initialized = true;
        return;
    }

    // 计算时间间隔(秒)
    float dt = (current_time_ms - filter->last_time_ms) / 1000.0f;
    filter->last_time_ms = current_time_ms;

    // 防止时间间隔异常
    if (dt <= 0.0f || dt > 1.0f) {
        return;
    }

    // 步骤1:使用加速度计计算角度
    float accel_roll = atan2f(data->accel_y, data->accel_z) * RAD_TO_DEG;
    float accel_pitch = atan2f(-data->accel_x,
                               sqrtf(data->accel_y * data->accel_y +
                                     data->accel_z * data->accel_z)) * RAD_TO_DEG;

    // 步骤2:使用陀螺仪积分计算角度变化
    float gyro_roll_delta = data->gyro_x * dt;
    float gyro_pitch_delta = data->gyro_y * dt;
    float gyro_yaw_delta = data->gyro_z * dt;

    // 步骤3:互补滤波融合
    // 角度 = α × (上次角度 + 陀螺仪积分) + (1-α) × 加速度计角度
    filter->roll = filter->alpha * (filter->roll + gyro_roll_delta) +
                   (1.0f - filter->alpha) * accel_roll;

    filter->pitch = filter->alpha * (filter->pitch + gyro_pitch_delta) +
                    (1.0f - filter->alpha) * accel_pitch;

    // 偏航角只能通过陀螺仪积分(需要磁力计校正)
    filter->yaw += gyro_yaw_delta;

    // 限制偏航角范围在-180到180度
    while (filter->yaw > 180.0f) filter->yaw -= 360.0f;
    while (filter->yaw < -180.0f) filter->yaw += 360.0f;
}

/**
 * @brief  获取姿态角
 */
void ComplementaryFilter_GetAngles(ComplementaryFilter_t* filter,
                                   float* roll, float* pitch, float* yaw) {
    if (roll) *roll = filter->roll;
    if (pitch) *pitch = filter->pitch;
    if (yaw) *yaw = filter->yaw;
}

/**
 * @brief  重置滤波器
 */
void ComplementaryFilter_Reset(ComplementaryFilter_t* filter) {
    filter->roll = 0.0f;
    filter->pitch = 0.0f;
    filter->yaw = 0.0f;
    filter->initialized = false;
}

第二部分:卡尔曼滤波算法

卡尔曼滤波原理

基本概念

卡尔曼滤波流程:

初始状态
  ├──→ 预测步骤 ────────────┐
  │    - 状态预测           │
  │    - 协方差预测         │
  │                         │
  │                         ↓
  │    ┌─────────────────────┐
  │    │   预测值            │
  │    └─────────────────────┘
  │                         │
  │                         ↓
  └──→ 更新步骤 ←───────────┤
       - 计算卡尔曼增益     │
       - 更新状态估计       │
       - 更新协方差         │
                        输出估计值

数学模型:

预测步骤:
  x̂(k|k-1) = A × x̂(k-1|k-1) + B × u(k)
  P(k|k-1) = A × P(k-1|k-1) × A^T + Q

更新步骤:
  K(k) = P(k|k-1) × H^T × [H × P(k|k-1) × H^T + R]^(-1)
  x̂(k|k) = x̂(k|k-1) + K(k) × [z(k) - H × x̂(k|k-1)]
  P(k|k) = [I - K(k) × H] × P(k|k-1)

符号说明:
- x̂: 状态估计
- P: 估计协方差矩阵
- A: 状态转移矩阵
- B: 控制输入矩阵
- u: 控制输入
- Q: 过程噪声协方差
- K: 卡尔曼增益
- H: 观测矩阵
- z: 观测值
- R: 观测噪声协方差
- I: 单位矩阵

一维卡尔曼滤波实现

简化版本(单变量)

/**
 * @file    kalman_filter_1d.h
 * @brief   一维卡尔曼滤波器
 */

#ifndef __KALMAN_FILTER_1D_H
#define __KALMAN_FILTER_1D_H

#include <stdint.h>
#include <stdbool.h>

/**
 * @brief  一维卡尔曼滤波器结构
 */
typedef struct {
    float x;            // 状态估计
    float P;            // 估计协方差
    float Q;            // 过程噪声协方差
    float R;            // 观测噪声协方差
    float K;            // 卡尔曼增益
    bool initialized;   // 初始化标志
} KalmanFilter1D_t;

// 函数声明
void KalmanFilter1D_Init(KalmanFilter1D_t* kf, float Q, float R);
float KalmanFilter1D_Update(KalmanFilter1D_t* kf, float measurement);
void KalmanFilter1D_Reset(KalmanFilter1D_t* kf);

#endif /* __KALMAN_FILTER_1D_H */
/**
 * @file    kalman_filter_1d.c
 * @brief   一维卡尔曼滤波器实现
 */

#include "kalman_filter_1d.h"

/**
 * @brief  初始化一维卡尔曼滤波器
 * @param  kf: 滤波器结构指针
 * @param  Q: 过程噪声协方差(越大越信任测量值)
 * @param  R: 观测噪声协方差(越大越信任预测值)
 */
void KalmanFilter1D_Init(KalmanFilter1D_t* kf, float Q, float R) {
    kf->x = 0.0f;
    kf->P = 1.0f;
    kf->Q = Q;
    kf->R = R;
    kf->K = 0.0f;
    kf->initialized = false;
}

/**
 * @brief  更新卡尔曼滤波器
 * @param  kf: 滤波器结构指针
 * @param  measurement: 测量值
 * @return 滤波后的估计值
 */
float KalmanFilter1D_Update(KalmanFilter1D_t* kf, float measurement) {
    // 首次调用,直接使用测量值初始化
    if (!kf->initialized) {
        kf->x = measurement;
        kf->initialized = true;
        return kf->x;
    }

    // 预测步骤
    // x̂(k|k-1) = x̂(k-1|k-1)  (假设状态不变)
    // P(k|k-1) = P(k-1|k-1) + Q
    kf->P = kf->P + kf->Q;

    // 更新步骤
    // K(k) = P(k|k-1) / [P(k|k-1) + R]
    kf->K = kf->P / (kf->P + kf->R);

    // x̂(k|k) = x̂(k|k-1) + K(k) × [z(k) - x̂(k|k-1)]
    kf->x = kf->x + kf->K * (measurement - kf->x);

    // P(k|k) = [1 - K(k)] × P(k|k-1)
    kf->P = (1.0f - kf->K) * kf->P;

    return kf->x;
}

/**
 * @brief  重置卡尔曼滤波器
 */
void KalmanFilter1D_Reset(KalmanFilter1D_t* kf) {
    kf->x = 0.0f;
    kf->P = 1.0f;
    kf->K = 0.0f;
    kf->initialized = false;
}

姿态估计卡尔曼滤波

二维卡尔曼滤波(角度+角速度)

/**
 * @file    kalman_filter_angle.h
 * @brief   角度估计卡尔曼滤波器
 */

#ifndef __KALMAN_FILTER_ANGLE_H
#define __KALMAN_FILTER_ANGLE_H

#include <stdint.h>
#include <stdbool.h>

/**
 * @brief  角度卡尔曼滤波器结构
 */
typedef struct {
    // 状态向量 [角度, 角速度偏差]
    float angle;            // 角度估计(度)
    float bias;             // 角速度偏差估计(度/秒)

    // 协方差矩阵 P
    float P[2][2];

    // 噪声参数
    float Q_angle;          // 角度过程噪声
    float Q_bias;           // 偏差过程噪声
    float R_measure;        // 测量噪声

    // 时间间隔
    float dt;

    bool initialized;
} KalmanFilterAngle_t;

// 函数声明
void KalmanFilterAngle_Init(KalmanFilterAngle_t* kf,
                            float Q_angle, float Q_bias, float R_measure);
float KalmanFilterAngle_Update(KalmanFilterAngle_t* kf,
                               float newAngle, float newRate, float dt);
void KalmanFilterAngle_SetAngle(KalmanFilterAngle_t* kf, float angle);
float KalmanFilterAngle_GetAngle(KalmanFilterAngle_t* kf);
float KalmanFilterAngle_GetRate(KalmanFilterAngle_t* kf);

#endif /* __KALMAN_FILTER_ANGLE_H */
/**
 * @file    kalman_filter_angle.c
 * @brief   角度估计卡尔曼滤波器实现
 */

#include "kalman_filter_angle.h"

/**
 * @brief  初始化角度卡尔曼滤波器
 * @param  kf: 滤波器结构指针
 * @param  Q_angle: 角度过程噪声(推荐0.001)
 * @param  Q_bias: 偏差过程噪声(推荐0.003)
 * @param  R_measure: 测量噪声(推荐0.03)
 */
void KalmanFilterAngle_Init(KalmanFilterAngle_t* kf,
                            float Q_angle, float Q_bias, float R_measure) {
    kf->angle = 0.0f;
    kf->bias = 0.0f;

    // 初始化协方差矩阵
    kf->P[0][0] = 0.0f;
    kf->P[0][1] = 0.0f;
    kf->P[1][0] = 0.0f;
    kf->P[1][1] = 0.0f;

    kf->Q_angle = Q_angle;
    kf->Q_bias = Q_bias;
    kf->R_measure = R_measure;

    kf->dt = 0.0f;
    kf->initialized = false;
}

/**
 * @brief  更新卡尔曼滤波器
 * @param  kf: 滤波器结构指针
 * @param  newAngle: 加速度计测量的角度(度)
 * @param  newRate: 陀螺仪测量的角速度(度/秒)
 * @param  dt: 时间间隔(秒)
 * @return 滤波后的角度估计(度)
 */
float KalmanFilterAngle_Update(KalmanFilterAngle_t* kf,
                               float newAngle, float newRate, float dt) {
    // 首次调用,初始化
    if (!kf->initialized) {
        kf->angle = newAngle;
        kf->initialized = true;
        return kf->angle;
    }

    kf->dt = dt;

    // 步骤1:预测
    // 状态预测:angle = angle + dt * (newRate - bias)
    float rate = newRate - kf->bias;
    kf->angle += dt * rate;

    // 协方差预测:P = A * P * A^T + Q
    kf->P[0][0] += dt * (dt * kf->P[1][1] - kf->P[0][1] - kf->P[1][0] + kf->Q_angle);
    kf->P[0][1] -= dt * kf->P[1][1];
    kf->P[1][0] -= dt * kf->P[1][1];
    kf->P[1][1] += kf->Q_bias * dt;

    // 步骤2:更新
    // 计算卡尔曼增益:K = P * H^T * (H * P * H^T + R)^(-1)
    float S = kf->P[0][0] + kf->R_measure;  // 新息协方差
    float K[2];  // 卡尔曼增益
    K[0] = kf->P[0][0] / S;
    K[1] = kf->P[1][0] / S;

    // 更新状态估计:x = x + K * (z - H * x)
    float y = newAngle - kf->angle;  // 新息(测量残差)
    kf->angle += K[0] * y;
    kf->bias += K[1] * y;

    // 更新协方差:P = (I - K * H) * P
    float P00_temp = kf->P[0][0];
    float P01_temp = kf->P[0][1];

    kf->P[0][0] -= K[0] * P00_temp;
    kf->P[0][1] -= K[0] * P01_temp;
    kf->P[1][0] -= K[1] * P00_temp;
    kf->P[1][1] -= K[1] * P01_temp;

    return kf->angle;
}

/**
 * @brief  设置角度
 */
void KalmanFilterAngle_SetAngle(KalmanFilterAngle_t* kf, float angle) {
    kf->angle = angle;
}

/**
 * @brief  获取角度估计
 */
float KalmanFilterAngle_GetAngle(KalmanFilterAngle_t* kf) {
    return kf->angle;
}

/**
 * @brief  获取角速度估计(已去除偏差)
 */
float KalmanFilterAngle_GetRate(KalmanFilterAngle_t* kf) {
    return -kf->bias;  // 返回负偏差作为校正后的角速度
}

第三部分:多传感器融合

AHRS算法(姿态航向参考系统)

AHRS系统架构

AHRS系统组成:

┌─────────────────────────────────────────┐
│         AHRS系统                        │
│                                         │
│  ┌──────────┐  ┌──────────┐  ┌────────┐│
│  │ 加速度计 │  │ 陀螺仪   │  │磁力计  ││
│  │ (3轴)    │  │ (3轴)    │  │(3轴)   ││
│  └────┬─────┘  └────┬─────┘  └───┬────┘│
│       │             │             │     │
│       └─────────────┼─────────────┘     │
│                     │                   │
│              ┌──────▼──────┐            │
│              │  数据融合   │            │
│              │  算法       │            │
│              └──────┬──────┘            │
│                     │                   │
│              ┌──────▼──────┐            │
│              │  姿态输出   │            │
│              │ Roll/Pitch/ │            │
│              │ Yaw         │            │
│              └─────────────┘            │
└─────────────────────────────────────────┘

传感器作用:
- 加速度计:提供横滚角和俯仰角(静态)
- 陀螺仪:提供角速度(动态)
- 磁力计:提供航向角(绝对方向)

融合策略:
1. 加速度计 + 陀螺仪 → Roll/Pitch
2. 磁力计 + 陀螺仪 → Yaw
3. 三者融合 → 完整姿态

九轴传感器融合实现

/**
 * @file    ahrs.h
 * @brief   AHRS姿态解算系统
 */

#ifndef __AHRS_H
#define __AHRS_H

#include <stdint.h>
#include <stdbool.h>
#include <math.h>

/**
 * @brief  九轴传感器数据
 */
typedef struct {
    float accel_x, accel_y, accel_z;    // 加速度 (g)
    float gyro_x, gyro_y, gyro_z;       // 陀螺仪 (°/s)
    float mag_x, mag_y, mag_z;          // 磁力计 (μT)
} AHRS_SensorData_t;

/**
 * @brief  AHRS姿态输出
 */
typedef struct {
    float roll;     // 横滚角 (°)
    float pitch;    // 俯仰角 (°)
    float yaw;      // 偏航角 (°)
} AHRS_Attitude_t;

/**
 * @brief  AHRS系统配置
 */
typedef struct {
    // 卡尔曼滤波器(Roll和Pitch)
    KalmanFilterAngle_t kf_roll;
    KalmanFilterAngle_t kf_pitch;

    // 互补滤波器(Yaw)
    ComplementaryFilter_t cf_yaw;

    // 磁偏角校正
    float magnetic_declination;  // 磁偏角(度)

    // 时间戳
    uint32_t last_time_ms;
    bool initialized;
} AHRS_t;

// 函数声明
void AHRS_Init(AHRS_t* ahrs, float magnetic_declination);
void AHRS_Update(AHRS_t* ahrs, AHRS_SensorData_t* data, uint32_t current_time_ms);
void AHRS_GetAttitude(AHRS_t* ahrs, AHRS_Attitude_t* attitude);
void AHRS_Reset(AHRS_t* ahrs);

#endif /* __AHRS_H */
/**
 * @file    ahrs.c
 * @brief   AHRS姿态解算系统实现
 */

#include "ahrs.h"
#include "kalman_filter_angle.h"
#include "complementary_filter.h"

#define RAD_TO_DEG  (180.0f / M_PI)
#define DEG_TO_RAD  (M_PI / 180.0f)

/**
 * @brief  初始化AHRS系统
 * @param  ahrs: AHRS结构指针
 * @param  magnetic_declination: 磁偏角(度)
 */
void AHRS_Init(AHRS_t* ahrs, float magnetic_declination) {
    // 初始化Roll卡尔曼滤波器
    KalmanFilterAngle_Init(&ahrs->kf_roll, 0.001f, 0.003f, 0.03f);

    // 初始化Pitch卡尔曼滤波器
    KalmanFilterAngle_Init(&ahrs->kf_pitch, 0.001f, 0.003f, 0.03f);

    // 初始化Yaw互补滤波器
    ComplementaryFilter_Init(&ahrs->cf_yaw, 0.98f);

    ahrs->magnetic_declination = magnetic_declination;
    ahrs->last_time_ms = 0;
    ahrs->initialized = false;
}

/**
 * @brief  更新AHRS系统
 * @param  ahrs: AHRS结构指针
 * @param  data: 九轴传感器数据
 * @param  current_time_ms: 当前时间(毫秒)
 */
void AHRS_Update(AHRS_t* ahrs, AHRS_SensorData_t* data, uint32_t current_time_ms) {
    // 计算时间间隔
    float dt;
    if (!ahrs->initialized) {
        dt = 0.01f;  // 假设10ms
        ahrs->last_time_ms = current_time_ms;
        ahrs->initialized = true;
    } else {
        dt = (current_time_ms - ahrs->last_time_ms) / 1000.0f;
        ahrs->last_time_ms = current_time_ms;
    }

    // 防止时间间隔异常
    if (dt <= 0.0f || dt > 1.0f) {
        dt = 0.01f;
    }

    // 步骤1:使用加速度计计算Roll和Pitch
    float accel_roll = atan2f(data->accel_y, data->accel_z) * RAD_TO_DEG;
    float accel_pitch = atan2f(-data->accel_x,
                               sqrtf(data->accel_y * data->accel_y +
                                     data->accel_z * data->accel_z)) * RAD_TO_DEG;

    // 步骤2:使用卡尔曼滤波融合加速度计和陀螺仪
    float roll = KalmanFilterAngle_Update(&ahrs->kf_roll, accel_roll, data->gyro_x, dt);
    float pitch = KalmanFilterAngle_Update(&ahrs->kf_pitch, accel_pitch, data->gyro_y, dt);

    // 步骤3:使用磁力计计算Yaw(航向角)
    // 磁力计倾斜补偿
    float roll_rad = roll * DEG_TO_RAD;
    float pitch_rad = pitch * DEG_TO_RAD;

    float mag_x_comp = data->mag_x * cosf(pitch_rad) +
                       data->mag_y * sinf(roll_rad) * sinf(pitch_rad) +
                       data->mag_z * cosf(roll_rad) * sinf(pitch_rad);

    float mag_y_comp = data->mag_y * cosf(roll_rad) -
                       data->mag_z * sinf(roll_rad);

    // 计算航向角
    float mag_yaw = atan2f(-mag_y_comp, mag_x_comp) * RAD_TO_DEG;

    // 应用磁偏角校正
    mag_yaw += ahrs->magnetic_declination;

    // 限制范围到0-360度
    while (mag_yaw < 0.0f) mag_yaw += 360.0f;
    while (mag_yaw >= 360.0f) mag_yaw -= 360.0f;

    // 步骤4:使用互补滤波融合磁力计和陀螺仪
    // 将磁力计航向角和陀螺仪Z轴数据融合
    SensorData_t yaw_data = {
        .accel_x = 0.0f,
        .accel_y = 0.0f,
        .accel_z = mag_yaw,  // 使用Z轴存储航向角
        .gyro_x = 0.0f,
        .gyro_y = 0.0f,
        .gyro_z = data->gyro_z
    };

    ComplementaryFilter_Update(&ahrs->cf_yaw, &yaw_data, current_time_ms);
}

/**
 * @brief  获取姿态角
 */
void AHRS_GetAttitude(AHRS_t* ahrs, AHRS_Attitude_t* attitude) {
    attitude->roll = KalmanFilterAngle_GetAngle(&ahrs->kf_roll);
    attitude->pitch = KalmanFilterAngle_GetAngle(&ahrs->kf_pitch);
    ComplementaryFilter_GetAngles(&ahrs->cf_yaw, NULL, NULL, &attitude->yaw);
}

/**
 * @brief  重置AHRS系统
 */
void AHRS_Reset(AHRS_t* ahrs) {
    KalmanFilterAngle_Init(&ahrs->kf_roll, 0.001f, 0.003f, 0.03f);
    KalmanFilterAngle_Init(&ahrs->kf_pitch, 0.001f, 0.003f, 0.03f);
    ComplementaryFilter_Reset(&ahrs->cf_yaw);
    ahrs->initialized = false;
}

第四部分:实践应用

应用示例1:互补滤波姿态估计

/**
 * @file    example_complementary_filter.c
 * @brief   互补滤波姿态估计示例
 */

#include "stm32f1xx_hal.h"
#include "mpu6050.h"
#include "complementary_filter.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;

void example_complementary_filter(void) {
    // 初始化MPU6050
    MPU6050_Config mpu_config = {
        .hi2c = &hi2c1,
        .address = MPU6050_ADDR,
        .gyro_fs = MPU6050_GYRO_FS_250,
        .accel_fs = MPU6050_ACCEL_FS_2
    };

    if (!MPU6050_Init(&mpu_config)) {
        printf("MPU6050初始化失败!\n");
        return;
    }

    // 初始化互补滤波器
    ComplementaryFilter_t filter;
    ComplementaryFilter_Init(&filter, 0.98f);

    printf("互补滤波姿态估计\n");
    printf("═══════════════════════════════════════\n\n");

    MPU6050_Data mpu_data;
    SensorData_t sensor_data;
    float roll, pitch, yaw;

    while (1) {
        // 读取MPU6050数据
        if (MPU6050_ReadData(&mpu_config, &mpu_data)) {
            // 转换为传感器数据格式
            sensor_data.accel_x = mpu_data.accel_x;
            sensor_data.accel_y = mpu_data.accel_y;
            sensor_data.accel_z = mpu_data.accel_z;
            sensor_data.gyro_x = mpu_data.gyro_x;
            sensor_data.gyro_y = mpu_data.gyro_y;
            sensor_data.gyro_z = mpu_data.gyro_z;

            // 更新滤波器
            uint32_t current_time = HAL_GetTick();
            ComplementaryFilter_Update(&filter, &sensor_data, current_time);

            // 获取姿态角
            ComplementaryFilter_GetAngles(&filter, &roll, &pitch, &yaw);

            // 打印结果
            printf("姿态角: Roll=%.2f°, Pitch=%.2f°, Yaw=%.2f°\n",
                   roll, pitch, yaw);
        }

        HAL_Delay(10);  // 100Hz更新率
    }
}

应用示例2:卡尔曼滤波角度估计

/**
 * @file    example_kalman_filter.c
 * @brief   卡尔曼滤波角度估计示例
 */

#include "stm32f1xx_hal.h"
#include "mpu6050.h"
#include "kalman_filter_angle.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;

void example_kalman_filter(void) {
    // 初始化MPU6050
    MPU6050_Config mpu_config = {
        .hi2c = &hi2c1,
        .address = MPU6050_ADDR,
        .gyro_fs = MPU6050_GYRO_FS_250,
        .accel_fs = MPU6050_ACCEL_FS_2
    };

    if (!MPU6050_Init(&mpu_config)) {
        printf("MPU6050初始化失败!\n");
        return;
    }

    // 初始化卡尔曼滤波器
    KalmanFilterAngle_t kf_roll, kf_pitch;
    KalmanFilterAngle_Init(&kf_roll, 0.001f, 0.003f, 0.03f);
    KalmanFilterAngle_Init(&kf_pitch, 0.001f, 0.003f, 0.03f);

    printf("卡尔曼滤波角度估计\n");
    printf("═══════════════════════════════════════\n\n");

    MPU6050_Data mpu_data;
    uint32_t last_time = HAL_GetTick();

    while (1) {
        // 读取MPU6050数据
        if (MPU6050_ReadData(&mpu_config, &mpu_data)) {
            // 计算时间间隔
            uint32_t current_time = HAL_GetTick();
            float dt = (current_time - last_time) / 1000.0f;
            last_time = current_time;

            // 使用加速度计计算角度
            float accel_roll = atan2f(mpu_data.accel_y, mpu_data.accel_z) * 180.0f / M_PI;
            float accel_pitch = atan2f(-mpu_data.accel_x,
                                      sqrtf(mpu_data.accel_y * mpu_data.accel_y +
                                            mpu_data.accel_z * mpu_data.accel_z)) * 180.0f / M_PI;

            // 卡尔曼滤波更新
            float roll = KalmanFilterAngle_Update(&kf_roll, accel_roll, mpu_data.gyro_x, dt);
            float pitch = KalmanFilterAngle_Update(&kf_pitch, accel_pitch, mpu_data.gyro_y, dt);

            // 打印结果
            printf("角度: Roll=%.2f°, Pitch=%.2f°\n", roll, pitch);
            printf("  加速度计: Roll=%.2f°, Pitch=%.2f°\n", accel_roll, accel_pitch);
            printf("  陀螺仪: X=%.2f°/s, Y=%.2f°/s\n\n",
                   mpu_data.gyro_x, mpu_data.gyro_y);
        }

        HAL_Delay(10);  // 100Hz更新率
    }
}

应用示例3:性能对比测试

/**
 * @file    example_comparison.c
 * @brief   不同滤波算法性能对比
 */

#include "stm32f1xx_hal.h"
#include "mpu6050.h"
#include "complementary_filter.h"
#include "kalman_filter_angle.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;

void example_comparison(void) {
    // 初始化MPU6050
    MPU6050_Config mpu_config = {
        .hi2c = &hi2c1,
        .address = MPU6050_ADDR,
        .gyro_fs = MPU6050_GYRO_FS_250,
        .accel_fs = MPU6050_ACCEL_FS_2
    };

    if (!MPU6050_Init(&mpu_config)) {
        printf("MPU6050初始化失败!\n");
        return;
    }

    // 初始化三种方法
    ComplementaryFilter_t cf;
    KalmanFilterAngle_t kf;

    ComplementaryFilter_Init(&cf, 0.98f);
    KalmanFilterAngle_Init(&kf, 0.001f, 0.003f, 0.03f);

    printf("滤波算法性能对比\n");
    printf("═══════════════════════════════════════\n\n");
    printf("方法1: 仅加速度计\n");
    printf("方法2: 互补滤波\n");
    printf("方法3: 卡尔曼滤波\n\n");

    MPU6050_Data mpu_data;
    SensorData_t sensor_data;
    uint32_t last_time = HAL_GetTick();

    while (1) {
        if (MPU6050_ReadData(&mpu_config, &mpu_data)) {
            uint32_t current_time = HAL_GetTick();
            float dt = (current_time - last_time) / 1000.0f;
            last_time = current_time;

            // 方法1:仅使用加速度计
            float accel_roll = atan2f(mpu_data.accel_y, mpu_data.accel_z) * 180.0f / M_PI;

            // 方法2:互补滤波
            sensor_data.accel_x = mpu_data.accel_x;
            sensor_data.accel_y = mpu_data.accel_y;
            sensor_data.accel_z = mpu_data.accel_z;
            sensor_data.gyro_x = mpu_data.gyro_x;
            sensor_data.gyro_y = mpu_data.gyro_y;
            sensor_data.gyro_z = mpu_data.gyro_z;

            ComplementaryFilter_Update(&cf, &sensor_data, current_time);
            float cf_roll, cf_pitch, cf_yaw;
            ComplementaryFilter_GetAngles(&cf, &cf_roll, &cf_pitch, &cf_yaw);

            // 方法3:卡尔曼滤波
            float kf_roll = KalmanFilterAngle_Update(&kf, accel_roll, mpu_data.gyro_x, dt);

            // 打印对比结果
            printf("Roll角度对比:\n");
            printf("  加速度计: %.2f°\n", accel_roll);
            printf("  互补滤波: %.2f°\n", cf_roll);
            printf("  卡尔曼滤波: %.2f°\n\n", kf_roll);
        }

        HAL_Delay(100);  // 10Hz更新率
    }
}

应用示例4:无人机姿态稳定

/**
 * @file    example_drone_stabilization.c
 * @brief   无人机姿态稳定应用
 */

#include "stm32f1xx_hal.h"
#include "mpu6050.h"
#include "complementary_filter.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;
extern TIM_HandleTypeDef htim1;  // PWM定时器

// PID控制器结构
typedef struct {
    float Kp;           // 比例系数
    float Ki;           // 积分系数
    float Kd;           // 微分系数
    float integral;     // 积分累积
    float last_error;   // 上次误差
    float output_min;   // 输出最小值
    float output_max;   // 输出最大值
} PID_Controller_t;

/**
 * @brief  PID控制器更新
 */
float PID_Update(PID_Controller_t* pid, float setpoint, float measured, float dt) {
    // 计算误差
    float error = setpoint - measured;

    // 比例项
    float P = pid->Kp * error;

    // 积分项
    pid->integral += error * dt;
    float I = pid->Ki * pid->integral;

    // 微分项
    float D = pid->Kd * (error - pid->last_error) / dt;
    pid->last_error = error;

    // 计算输出
    float output = P + I + D;

    // 限幅
    if (output > pid->output_max) output = pid->output_max;
    if (output < pid->output_min) output = pid->output_min;

    return output;
}

/**
 * @brief  无人机姿态稳定主函数
 */
void example_drone_stabilization(void) {
    // 初始化MPU6050
    MPU6050_Config mpu_config = {
        .hi2c = &hi2c1,
        .address = MPU6050_ADDR,
        .gyro_fs = MPU6050_GYRO_FS_500,
        .accel_fs = MPU6050_ACCEL_FS_4
    };

    if (!MPU6050_Init(&mpu_config)) {
        printf("MPU6050初始化失败!\n");
        return;
    }

    // 初始化互补滤波器
    ComplementaryFilter_t filter;
    ComplementaryFilter_Init(&filter, 0.98f);

    // 初始化PID控制器
    PID_Controller_t pid_roll = {
        .Kp = 1.5f,
        .Ki = 0.05f,
        .Kd = 0.8f,
        .integral = 0.0f,
        .last_error = 0.0f,
        .output_min = -500.0f,
        .output_max = 500.0f
    };

    PID_Controller_t pid_pitch = {
        .Kp = 1.5f,
        .Ki = 0.05f,
        .Kd = 0.8f,
        .integral = 0.0f,
        .last_error = 0.0f,
        .output_min = -500.0f,
        .output_max = 500.0f
    };

    printf("无人机姿态稳定系统\n");
    printf("═══════════════════════════════════════\n\n");

    MPU6050_Data mpu_data;
    SensorData_t sensor_data;
    float roll, pitch, yaw;
    uint32_t last_time = HAL_GetTick();

    // 目标姿态(水平)
    float target_roll = 0.0f;
    float target_pitch = 0.0f;

    while (1) {
        if (MPU6050_ReadData(&mpu_config, &mpu_data)) {
            uint32_t current_time = HAL_GetTick();
            float dt = (current_time - last_time) / 1000.0f;
            last_time = current_time;

            // 更新姿态估计
            sensor_data.accel_x = mpu_data.accel_x;
            sensor_data.accel_y = mpu_data.accel_y;
            sensor_data.accel_z = mpu_data.accel_z;
            sensor_data.gyro_x = mpu_data.gyro_x;
            sensor_data.gyro_y = mpu_data.gyro_y;
            sensor_data.gyro_z = mpu_data.gyro_z;

            ComplementaryFilter_Update(&filter, &sensor_data, current_time);
            ComplementaryFilter_GetAngles(&filter, &roll, &pitch, &yaw);

            // PID控制计算
            float roll_correction = PID_Update(&pid_roll, target_roll, roll, dt);
            float pitch_correction = PID_Update(&pid_pitch, target_pitch, pitch, dt);

            // 计算电机PWM值(假设四旋翼)
            // 基础油门 + 姿态修正
            float base_throttle = 1500.0f;  // 中位值

            float motor1 = base_throttle + roll_correction + pitch_correction;
            float motor2 = base_throttle - roll_correction + pitch_correction;
            float motor3 = base_throttle - roll_correction - pitch_correction;
            float motor4 = base_throttle + roll_correction - pitch_correction;

            // 限制PWM范围(1000-2000μs)
            motor1 = fminf(fmaxf(motor1, 1000.0f), 2000.0f);
            motor2 = fminf(fmaxf(motor2, 1000.0f), 2000.0f);
            motor3 = fminf(fmaxf(motor3, 1000.0f), 2000.0f);
            motor4 = fminf(fmaxf(motor4, 1000.0f), 2000.0f);

            // 输出PWM到电机
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint16_t)motor1);
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, (uint16_t)motor2);
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (uint16_t)motor3);
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, (uint16_t)motor4);

            // 打印调试信息
            printf("姿态: Roll=%.2f°, Pitch=%.2f°\n", roll, pitch);
            printf("修正: Roll=%.2f, Pitch=%.2f\n", roll_correction, pitch_correction);
            printf("电机: M1=%.0f, M2=%.0f, M3=%.0f, M4=%.0f\n\n",
                   motor1, motor2, motor3, motor4);
        }

        HAL_Delay(5);  // 200Hz控制频率
    }
}

应用示例5:数据记录与分析

/**
 * @file    example_data_logging.c
 * @brief   传感器数据记录与分析
 */

#include "stm32f1xx_hal.h"
#include "mpu6050.h"
#include "complementary_filter.h"
#include "kalman_filter_angle.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;

#define LOG_BUFFER_SIZE 1000

// 数据记录结构
typedef struct {
    uint32_t timestamp;
    float accel_roll;
    float cf_roll;
    float kf_roll;
} DataLog_t;

DataLog_t log_buffer[LOG_BUFFER_SIZE];
uint32_t log_index = 0;

/**
 * @brief  记录数据
 */
void log_data(uint32_t timestamp, float accel_roll, float cf_roll, float kf_roll) {
    if (log_index < LOG_BUFFER_SIZE) {
        log_buffer[log_index].timestamp = timestamp;
        log_buffer[log_index].accel_roll = accel_roll;
        log_buffer[log_index].cf_roll = cf_roll;
        log_buffer[log_index].kf_roll = kf_roll;
        log_index++;
    }
}

/**
 * @brief  导出数据(CSV格式)
 */
void export_data(void) {
    printf("\n数据导出(CSV格式)\n");
    printf("═══════════════════════════════════════\n");
    printf("Timestamp,Accel_Roll,CF_Roll,KF_Roll\n");

    for (uint32_t i = 0; i < log_index; i++) {
        printf("%lu,%.3f,%.3f,%.3f\n",
               log_buffer[i].timestamp,
               log_buffer[i].accel_roll,
               log_buffer[i].cf_roll,
               log_buffer[i].kf_roll);
    }

    printf("\n总共记录 %lu 条数据\n", log_index);
}

/**
 * @brief  数据记录主函数
 */
void example_data_logging(void) {
    // 初始化MPU6050
    MPU6050_Config mpu_config = {
        .hi2c = &hi2c1,
        .address = MPU6050_ADDR,
        .gyro_fs = MPU6050_GYRO_FS_250,
        .accel_fs = MPU6050_ACCEL_FS_2
    };

    if (!MPU6050_Init(&mpu_config)) {
        printf("MPU6050初始化失败!\n");
        return;
    }

    // 初始化滤波器
    ComplementaryFilter_t cf;
    KalmanFilterAngle_t kf;

    ComplementaryFilter_Init(&cf, 0.98f);
    KalmanFilterAngle_Init(&kf, 0.001f, 0.003f, 0.03f);

    printf("传感器数据记录\n");
    printf("═══════════════════════════════════════\n");
    printf("记录时间: 10秒\n");
    printf("采样率: 100Hz\n\n");

    MPU6050_Data mpu_data;
    SensorData_t sensor_data;
    uint32_t start_time = HAL_GetTick();
    uint32_t last_time = start_time;

    // 记录10秒数据
    while ((HAL_GetTick() - start_time) < 10000 && log_index < LOG_BUFFER_SIZE) {
        if (MPU6050_ReadData(&mpu_config, &mpu_data)) {
            uint32_t current_time = HAL_GetTick();
            float dt = (current_time - last_time) / 1000.0f;
            last_time = current_time;

            // 计算加速度计角度
            float accel_roll = atan2f(mpu_data.accel_y, mpu_data.accel_z) * 180.0f / M_PI;

            // 互补滤波
            sensor_data.accel_x = mpu_data.accel_x;
            sensor_data.accel_y = mpu_data.accel_y;
            sensor_data.accel_z = mpu_data.accel_z;
            sensor_data.gyro_x = mpu_data.gyro_x;
            sensor_data.gyro_y = mpu_data.gyro_y;
            sensor_data.gyro_z = mpu_data.gyro_z;

            ComplementaryFilter_Update(&cf, &sensor_data, current_time);
            float cf_roll, cf_pitch, cf_yaw;
            ComplementaryFilter_GetAngles(&cf, &cf_roll, &cf_pitch, &cf_yaw);

            // 卡尔曼滤波
            float kf_roll = KalmanFilterAngle_Update(&kf, accel_roll, mpu_data.gyro_x, dt);

            // 记录数据
            log_data(current_time - start_time, accel_roll, cf_roll, kf_roll);

            // 显示进度
            if (log_index % 100 == 0) {
                printf("已记录 %lu 条数据...\n", log_index);
            }
        }

        HAL_Delay(10);  // 100Hz采样率
    }

    printf("\n记录完成!\n\n");

    // 导出数据
    export_data();
}

第五部分:高级主题

参数调优指南

互补滤波参数调优

互补滤波系数α的选择:

α值影响:
┌─────────┬──────────────┬──────────────┐
│ α值     │ 特性         │ 适用场景     │
├─────────┼──────────────┼──────────────┤
│ 0.90    │ 更信任加速度计│ 静态应用     │
│ 0.95    │ 平衡         │ 一般应用     │
│ 0.98    │ 更信任陀螺仪 │ 动态应用     │
│ 0.99    │ 极度信任陀螺仪│ 高速运动     │
└─────────┴──────────────┴──────────────┘

调优步骤:
1. 从α=0.95开始测试
2. 如果对振动敏感,增大α(如0.98)
3. 如果存在明显漂移,减小α(如0.90)
4. 观察响应速度和稳定性
5. 在实际应用场景中验证

经验公式:
α = τ / (τ + Δt)

其中:
- τ: 时间常数(秒)
- Δt: 采样周期(秒)

示例:
- τ = 0.5s, Δt = 0.01s → α = 0.98
- τ = 0.2s, Δt = 0.01s → α = 0.95

卡尔曼滤波参数调优

卡尔曼滤波噪声参数:

Q_angle(角度过程噪声):
- 推荐值:0.001
- 增大:更快响应,但更不稳定
- 减小:更稳定,但响应慢

Q_bias(偏差过程噪声):
- 推荐值:0.003
- 增大:更快适应陀螺仪漂移
- 减小:更稳定的偏差估计

R_measure(测量噪声):
- 推荐值:0.03
- 增大:更信任预测值
- 减小:更信任测量值

调优方法:
1. 固定R_measure = 0.03
2. 调整Q_angle观察响应速度
3. 调整Q_bias观察漂移补偿
4. 在实际环境中微调

参数关系:
Q/R比值越大 → 越信任测量值
Q/R比值越小 → 越信任预测值

性能优化技巧

计算优化

/**
 * @brief  快速平方根倒数(Quake III算法)
 */
float fast_inv_sqrt(float x) {
    float halfx = 0.5f * x;
    float y = x;
    long i = *(long*)&y;
    i = 0x5f3759df - (i >> 1);
    y = *(float*)&i;
    y = y * (1.5f - (halfx * y * y));
    return y;
}

/**
 * @brief  优化的向量归一化
 */
void normalize_vector(float* x, float* y, float* z) {
    float inv_norm = fast_inv_sqrt(*x * *x + *y * *y + *z * *z);
    *x *= inv_norm;
    *y *= inv_norm;
    *z *= inv_norm;
}

/**
 * @brief  查表法三角函数(适用于精度要求不高的场景)
 */
#define SIN_TABLE_SIZE 360
static float sin_table[SIN_TABLE_SIZE];

void init_sin_table(void) {
    for (int i = 0; i < SIN_TABLE_SIZE; i++) {
        sin_table[i] = sinf(i * M_PI / 180.0f);
    }
}

float fast_sin(float angle_deg) {
    int index = (int)angle_deg % 360;
    if (index < 0) index += 360;
    return sin_table[index];
}

float fast_cos(float angle_deg) {
    return fast_sin(angle_deg + 90.0f);
}

内存优化

/**
 * @brief  使用定点数代替浮点数(节省内存和计算)
 */
typedef int32_t fixed_point_t;

#define FIXED_POINT_SHIFT 16
#define FIXED_POINT_ONE (1 << FIXED_POINT_SHIFT)

// 浮点转定点
fixed_point_t float_to_fixed(float f) {
    return (fixed_point_t)(f * FIXED_POINT_ONE);
}

// 定点转浮点
float fixed_to_float(fixed_point_t fp) {
    return (float)fp / FIXED_POINT_ONE;
}

// 定点乘法
fixed_point_t fixed_mul(fixed_point_t a, fixed_point_t b) {
    return (fixed_point_t)(((int64_t)a * b) >> FIXED_POINT_SHIFT);
}

// 定点除法
fixed_point_t fixed_div(fixed_point_t a, fixed_point_t b) {
    return (fixed_point_t)(((int64_t)a << FIXED_POINT_SHIFT) / b);
}

故障诊断与调试

常见问题诊断

问题1:角度估计不稳定,抖动严重
原因:
- 加速度计噪声过大
- 滤波参数不合适
- 采样率过低

解决方案:
1. 增大互补滤波α值(如0.98)
2. 增大卡尔曼滤波R_measure
3. 添加低通滤波器
4. 提高采样率到100Hz以上

问题2:角度估计存在漂移
原因:
- 陀螺仪零点偏移
- 温度影响
- 滤波参数不合适

解决方案:
1. 进行陀螺仪校准
2. 减小互补滤波α值(如0.95)
3. 增大卡尔曼滤波Q_bias
4. 添加温度补偿

问题3:响应速度慢
原因:
- 滤波参数过于保守
- 采样率过低
- 计算延迟

解决方案:
1. 减小卡尔曼滤波R_measure
2. 增大Q_angle
3. 提高采样率
4. 优化计算代码

问题4:磁力计干扰严重
原因:
- 附近有强磁场
- 电机电流干扰
- 金属物体影响

解决方案:
1. 远离干扰源
2. 磁力计校准
3. 使用软铁/硬铁补偿
4. 降低磁力计权重

调试工具

/**
 * @brief  实时数据监控
 */
void debug_monitor(void) {
    static uint32_t last_print = 0;
    uint32_t current_time = HAL_GetTick();

    // 每100ms打印一次
    if (current_time - last_print >= 100) {
        last_print = current_time;

        printf("=== 传感器融合调试信息 ===\n");
        printf("时间: %lu ms\n", current_time);
        printf("加速度: X=%.3f, Y=%.3f, Z=%.3f g\n",
               sensor_data.accel_x, sensor_data.accel_y, sensor_data.accel_z);
        printf("陀螺仪: X=%.2f, Y=%.2f, Z=%.2f °/s\n",
               sensor_data.gyro_x, sensor_data.gyro_y, sensor_data.gyro_z);
        printf("姿态角: Roll=%.2f, Pitch=%.2f, Yaw=%.2f °\n",
               attitude.roll, attitude.pitch, attitude.yaw);
        printf("卡尔曼增益: %.4f\n", kf.K);
        printf("协方差: P00=%.6f, P11=%.6f\n\n", kf.P[0][0], kf.P[1][1]);
    }
}

/**
 * @brief  性能分析
 */
void performance_analysis(void) {
    uint32_t start_time, end_time;
    uint32_t total_time = 0;
    uint32_t iterations = 1000;

    printf("性能分析\n");
    printf("═══════════════════════════════════════\n\n");

    // 测试互补滤波性能
    start_time = HAL_GetTick();
    for (uint32_t i = 0; i < iterations; i++) {
        ComplementaryFilter_Update(&cf, &sensor_data, HAL_GetTick());
    }
    end_time = HAL_GetTick();
    total_time = end_time - start_time;

    printf("互补滤波:\n");
    printf("  总时间: %lu ms\n", total_time);
    printf("  平均时间: %.3f ms\n", (float)total_time / iterations);
    printf("  最大频率: %.0f Hz\n\n", 1000.0f * iterations / total_time);

    // 测试卡尔曼滤波性能
    start_time = HAL_GetTick();
    for (uint32_t i = 0; i < iterations; i++) {
        KalmanFilterAngle_Update(&kf, 0.0f, 0.0f, 0.01f);
    }
    end_time = HAL_GetTick();
    total_time = end_time - start_time;

    printf("卡尔曼滤波:\n");
    printf("  总时间: %lu ms\n", total_time);
    printf("  平均时间: %.3f ms\n", (float)total_time / iterations);
    printf("  最大频率: %.0f Hz\n\n", 1000.0f * iterations / total_time);
}

总结

关键要点

  1. 数据融合的必要性
  2. 单传感器存在固有缺陷
  3. 融合可以取长补短
  4. 提高精度和鲁棒性
  5. 适应不同应用场景

  6. 互补滤波

  7. 计算简单,实时性好
  8. 适合资源受限的嵌入式系统
  9. 参数调优相对简单
  10. 精度中等,满足大多数应用

  11. 卡尔曼滤波

  12. 理论基础扎实,精度高
  13. 可以估计系统状态和噪声
  14. 计算量适中,可在MCU上运行
  15. 参数调优需要经验

  16. AHRS系统

  17. 九轴传感器融合
  18. 提供完整姿态信息
  19. 适用于导航和控制
  20. 需要磁力计校准

  21. 实际应用

  22. 无人机姿态稳定
  23. 机器人平衡控制
  24. 可穿戴设备
  25. 虚拟现实追踪

算法选择建议

应用场景与算法选择:

┌──────────────────┬──────────────┬──────────────┐
│ 应用场景         │ 推荐算法     │ 理由         │
├──────────────────┼──────────────┼──────────────┤
│ 简单姿态检测     │ 互补滤波     │ 简单高效     │
│ 无人机飞控       │ 卡尔曼滤波   │ 精度要求高   │
│ 机器人导航       │ AHRS系统     │ 需要航向角   │
│ 可穿戴设备       │ 互补滤波     │ 功耗低       │
│ 虚拟现实         │ 卡尔曼滤波   │ 低延迟高精度 │
│ 工业测量         │ 卡尔曼滤波   │ 精度要求高   │
└──────────────────┴──────────────┴──────────────┘

性能对比:
- 计算复杂度:互补滤波 < 卡尔曼滤波 < 扩展卡尔曼
- 精度:互补滤波 < 卡尔曼滤波 < 扩展卡尔曼
- 实时性:互补滤波 > 卡尔曼滤波 > 扩展卡尔曼
- 易用性:互补滤波 > 卡尔曼滤波 > 扩展卡尔曼

最佳实践

  1. 传感器校准
  2. 定期进行零点校准
  3. 记录温度补偿系数
  4. 磁力计需要三维校准
  5. 保存校准数据到Flash

  6. 参数调优

  7. 从推荐值开始
  8. 在实际环境中测试
  9. 记录不同参数的效果
  10. 建立参数数据库

  11. 性能优化

  12. 使用定点数代替浮点数
  13. 查表法替代三角函数
  14. 减少不必要的计算
  15. 使用DMA传输数据

  16. 错误处理

  17. 检测传感器故障
  18. 处理数据异常值
  19. 实现故障安全机制
  20. 记录错误日志

  21. 测试验证

  22. 静态精度测试
  23. 动态响应测试
  24. 长时间稳定性测试
  25. 极端环境测试

常见误区

  1. 误区1:滤波参数越大越好
  2. 错误:盲目增大滤波参数
  3. 正确:根据应用场景选择合适参数
  4. 原因:参数过大会导致响应慢或不稳定

  5. 误区2:采样率越高越好

  6. 错误:无限提高采样率
  7. 正确:选择合适的采样率(通常100-200Hz)
  8. 原因:过高采样率增加计算负担,收益递减

  9. 误区3:只使用一种传感器

  10. 错误:仅依赖加速度计或陀螺仪
  11. 正确:融合多种传感器数据
  12. 原因:单传感器无法克服固有缺陷

  13. 误区4:忽略传感器校准

  14. 错误:直接使用原始数据
  15. 正确:定期校准传感器
  16. 原因:零点偏移会严重影响精度

  17. 误区5:过度依赖滤波算法

  18. 错误:期望滤波解决所有问题
  19. 正确:从硬件设计开始优化
  20. 原因:算法无法弥补硬件缺陷

进阶学习

  1. 扩展卡尔曼滤波(EKF)
  2. 处理非线性系统
  3. 更高的精度
  4. 更复杂的实现

  5. 无迹卡尔曼滤波(UKF)

  6. 更好的非线性处理
  7. 不需要计算雅可比矩阵
  8. 计算量较大

  9. 粒子滤波

  10. 处理非高斯噪声
  11. 多模态分布
  12. 计算量极大

  13. 四元数姿态表示

  14. 避免万向节死锁
  15. 计算效率高
  16. 插值平滑

  17. 传感器标定

  18. 六面法标定
  19. 椭球拟合
  20. 温度补偿

参考资料

书籍: - 《卡尔曼滤波原理及应用》 - 《惯性导航系统》 - 《传感器融合算法》 - 《现代控制理论》

论文: - "Keeping a Good Attitude: A Quaternion-Based Orientation Filter" - "An efficient orientation filter for inertial and inertial/magnetic sensor arrays" - "Complementary Filter Design on the Special Orthogonal Group SO(3)"

开源项目: - MultiWii:多旋翼飞控 - Betaflight:竞速无人机飞控 - PX4:专业飞控系统 - Madgwick AHRS:开源姿态解算算法

在线资源: - InvenSense开发者中心 - STM32传感器应用笔记 - Arduino传感器库 - ROS IMU驱动包

实践建议

  1. 从简单开始
  2. 先实现互补滤波
  3. 理解基本原理
  4. 逐步增加复杂度

  5. 充分测试

  6. 静态测试
  7. 动态测试
  8. 边界条件测试
  9. 长时间运行测试

  10. 记录数据

  11. 保存原始数据
  12. 记录滤波结果
  13. 分析性能指标
  14. 建立数据库

  15. 持续优化

  16. 分析性能瓶颈
  17. 优化关键代码
  18. 调整参数
  19. 验证改进效果

  20. 学习交流

  21. 参与开源项目
  22. 阅读他人代码
  23. 分享经验
  24. 持续学习

下一步学习: - 传感器校准与误差补偿 - 智能环境监测站项目 - 无刷电机FOC控制

相关内容: - 加速度计与陀螺仪基础 - 生物传感器:心率与血氧检测 - PID控制算法实战