1. 陀螺仪数据读取与预处理

陀螺仪数据读取与预处理 学习卡片

任务说明

本案例实现运动相机IMU陀螺仪数据的读取与预处理闭环:从传感器读取原始三轴角速度,经过去噪(滑动平均滤波)与校准(零偏扣除),输出可直接用于后续EIS算法的角速度序列。代码基于通用I2C接口的IMU(以MPU6050为例),通过模拟数据接口保证可独立运行验证。

核心实现

import numpy as np
import time

# ---------- 模拟IMU驱动(真实场景替换为寄存器读写) ----------
class MockIMU:
    """模拟MPU6050陀螺仪,输出含噪声与零偏的原始数据"""
    def __init__(self, fs=1000.0, gyro_bias=(0.5, -0.3, 0.8), noise_std=0.15):
        self.fs = fs
        self.dt = 1.0 / fs
        self.bias = np.array(gyro_bias, dtype=np.float64)
        self.noise_std = noise_std
        self.t = 0.0
        # 真实角速度:低频摆动 + 高频抖动
        self.true_rate = lambda t: np.array([
            2.0 * np.sin(2 * np.pi * 1.2 * t),
            1.5 * np.cos(2 * np.pi * 0.8 * t),
            0.8 * np.sin(2 * np.pi * 2.0 * t)
        ])

    def read_gyro(self):
        """返回原始三轴角速度(deg/s),含零偏与高斯噪声"""
        raw = self.true_rate(self.t) + self.bias
        raw += np.random.normal(0, self.noise_std, 3)
        self.t += self.dt
        return raw.copy()

# ---------- 预处理核心 ----------
class GyroPreprocessor:
    def __init__(self, window_size=5):
        self.window_size = window_size
        self.buffer = []          # 滑动窗口缓存
        self.bias_estimate = None # 静态零偏估计

    def calibrate_bias(self, imu, samples=200):
        """静止状态下采集N个样本,取均值作为零偏"""
        if self.bias_estimate is not None:
            return self.bias_estimate
        samples_list = []
        for _ in range(samples):
            samples_list.append(imu.read_gyro())
        self.bias_estimate = np.mean(samples_list, axis=0)
        return self.bias_estimate

    def denoise(self, sample):
        """滑动平均去噪,返回滤波后的单点值"""
        self.buffer.append(sample.copy())
        if len(self.buffer) > self.window_size:
            self.buffer.pop(0)
        return np.mean(self.buffer, axis=0)

    def process_sample(self, raw_sample):
        """完整预处理:去噪 -> 去零偏"""
        filtered = self.denoise(raw_sample)
        if self.bias_estimate is None:
            raise RuntimeError("请先调用calibrate_bias()完成零偏校准")
        return filtered - self.bias_estimate

# ---------- 主流程 ----------
def main():
    # 初始化IMU与预处理器
    imu = MockIMU(fs=500.0)
    pre = GyroPreprocessor(window_size=5)

    # 1. 静止校准(前200个样本)
    bias = pre.calibrate_bias(imu, samples=200)
    print(f"校准零偏(deg/s): X={bias[0]:.3f}, Y={bias[1]:.3f}, Z={bias[2]:.3f}")

    # 2. 采集并预处理100个样本
    processed_series = []
    raw_series = []
    for _ in range(100):
        raw = imu.read_gyro()
        raw_series.append(raw.copy())
        clean = pre.process_sample(raw)
        processed_series.append(clean.copy())

    # 3. 输出统计结果
    raw_arr = np.array(raw_series)
    clean_arr = np.array(processed_series)
    print(f"\n原始数据均值(含零偏): {np.mean(raw_arr, axis=0)}")
    print(f"预处理后均值(应接近真实值): {np.mean(clean_arr, axis=0)}")
    print(f"预处理后标准差(噪声抑制效果): {np.std(clean_arr, axis=0)}")

if __name__ == "__main__":
    main()

落地与验证

运行方式:保存为gyro_preprocess.py,执行python gyro_preprocess.py。依赖仅需NumPy。

验证方法:观察输出中“预处理后均值”应接近模拟真实角速度的统计均值(由于模拟信号为周期函数,100个样本内均值应接近0附近),且“预处理后标准差”应明显小于原始含噪数据的标准差(原始噪声σ=0.15,滤波后理论σ≈0.15/√5≈0.067)。若校准零偏输出与设定值(0.5,-0.3,0.8)偏差小于0.05,且预处理后均值较原始均值更接近0,则判定通过。

陀螺仪数据预处理流水线 IMU传感器 原始三轴角速度 含零偏+噪声 零偏校准 静止采集N样本 计算均值 bias 输出: bias向量 滑动平均去噪 窗口大小 W=5 抑制高频噪声 输出: 滤波后样本 去零偏 sample - bias 输出: 干净角速度 数据流与验证观测点 ① 原始样本: raw = true_rate(t) + bias + noise ② 校准阶段: bias_est = mean(raw[0:200]) → 应接近设定零偏(0.5,-0.3,0.8) ③ 滤波阶段: 窗口均值抑制噪声 → 标准差应降至 σ/√5 ≈ 0.067 ④ 输出验证: clean = filtered - bias_est → 均值应接近真实角速度均值(≈0)

判定标准

1. 校准零偏输出与设定值(0.5, -0.3, 0.8)的误差小于0.05 deg/s;
2. 预处理后角速度序列的均值值小于0.1 deg/s(原始含零偏数据均值约为0.5~0.8);
3. 预处理后标准差小于0.1 deg/s,明显低于原始噪声水平0.15 deg/s。
满足以上三点即验证通过。真实硬件场景下,将MockIMU替换为I2C寄存器读取驱动,并保持预处理逻辑不变即可直接复用。