1. 加速度计数据采集与预处理

加速度计数据采集与预处理 学习卡片

任务说明

本案例完成MPU6050三轴加速度数据的采集与预处理,输出滤波后的加速度幅值序列,作为后续步数计数算法的输入。预处理链路包含:原始数据读取→零漂移除→低通滤波→合成幅值。代码在PC端模拟I2C读取逻辑,可直接对接真实硬件或使用内置仿真数据验证。

硬件连接与数据格式

MCU (I2C Master) MPU6050 (I2C Slave 0x68) SCL SDA VCC 3.3V GND 加速度寄存器 (ACCEL_XOUT_H 0x3B 起) | 15:8 X轴 | 7:0 X轴 | 15:8 Y轴 | 7:0 Y轴 | 15:8 Z轴 | 7:0 Z轴 | 每个轴16位有符号整数,量程±2g时灵敏度16384 LSB/g

代码实现


import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# ========== 1. 模拟MPU6050 I2C读取 ==========
class MPU6050Sim:
    """模拟真实传感器:生成含噪声和零漂的加速度数据"""
    def __init__(self, fs=50, duration=10.0, seed=42):
        self.fs = fs
        self.n = int(fs * duration)
        self.rng = np.random.default_rng(seed)
        # 真实加速度:模拟步行时约1Hz的周期性摆动
        t = np.arange(self.n) / fs
        self.true_acc = np.column_stack([
            0.3 * np.sin(2*np.pi*1.0*t) + 0.05 * self.rng.standard_normal(self.n),   # X轴
            0.2 * np.cos(2*np.pi*1.0*t) + 0.05 * self.rng.standard_normal(self.n),   # Y轴
            1.0 + 0.4 * np.sin(2*np.pi*2.0*t) + 0.08 * self.rng.standard_normal(self.n)  # Z轴含重力
        ])
        # 加入零漂和量化噪声
        self.bias = np.array([0.15, -0.10, 0.20])
        self.raw = self.true_acc + self.bias + \
                   0.02 * self.rng.standard_normal((self.n, 3))

    def read_accel(self):
        """模拟I2C读取原始寄存器值(返回g单位)"""
        return self.raw.copy()

# ========== 2. 预处理核心函数 ==========
def remove_bias(data, axis=0):
    """零漂移除:减去每个轴的平均值"""
    return data - np.mean(data, axis=axis)

def lowpass_filter(data, fs, cutoff=5.0, order=4):
    """Butterworth低通滤波器,保留步行频率(0.5~3Hz)"""
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = signal.butter(order, normal_cutoff, btype='low')
    return signal.filtfilt(b, a, data, axis=0)

def compute_magnitude(acc):
    """合成三轴幅值:sqrt(x^2 + y^2 + z^2)"""
    return np.sqrt(np.sum(acc**2, axis=1))

# ========== 3. 主流程 ==========
def main():
    # 初始化传感器(实际使用时替换为真实I2C读取)
    mpu = MPU6050Sim(fs=50, duration=10.0)
    raw_data = mpu.read_accel()
    fs = 50.0

    # 预处理链路
    debiased = remove_bias(raw_data)          # 步骤1:零漂移除
    filtered = lowpass_filter(debiased, fs)   # 步骤2:低通滤波
    magnitude = compute_magnitude(filtered)   # 步骤3:合成幅值

    # 输出结果(供步数计数模块使用)
    print(f"原始数据形状: {raw_data.shape}")
    print(f"滤波后幅值范围: [{magnitude.min():.3f}, {magnitude.max():.3f}] g")
    print(f"幅值均值: {magnitude.mean():.3f} g (应接近1.0g重力加速度)")

    # 可视化对比(可选)
    t = np.arange(len(raw_data)) / fs
    fig, axes = plt.subplots(2, 1, figsize=(10, 6))
    axes[0].plot(t, raw_data[:, 2], alpha=0.5, label='原始Z轴')
    axes[0].plot(t, filtered[:, 2], 'r-', label='滤波后Z轴')
    axes[0].set_ylabel('加速度 (g)')
    axes[0].legend()
    axes[1].plot(t, magnitude, 'g-', label='合成幅值')
    axes[1].set_xlabel('时间 (s)')
    axes[1].set_ylabel('幅值 (g)')
    axes[1].legend()
    plt.tight_layout()
    plt.savefig('preprocessing_result.png', dpi=100)
    print("已保存预处理结果图: preprocessing_result.png")

if __name__ == "__main__":
    main()

运行与验证

依赖安装:


pip install numpy scipy matplotlib

运行方式:


python mpu6050_preprocess.py

验证方法:

  1. 程序正常结束且无异常报错;
  2. 输出幅值均值在0.95~1.05g之间(因包含重力分量);
  3. 生成preprocessing_result.png,图中滤波后曲线明显比原始曲线平滑,毛刺减少;
  4. 幅值曲线呈现周期性波动(对应步行频率约1~2Hz),证明有效保留了步态特征。

判定标准:满足上述4条即视为预处理链路工作正常,输出数据可直接用于后续步数计数算法。

真实硬件替换说明

若使用真实MPU6050,将MPU6050Sim.read_accel()替换为通过smbus2读取寄存器0x3B~0x40的代码,并配置量程为±2g(寄存器0x1C设为0x00),其余预处理逻辑完全不变。仿真数据已包含零漂、噪声和重力分量,与真实传感器特性一致。