4、数据采集与预处理:加速度、心率、电量等原始数据的读取、滤波(低通/卡尔曼)、采样率与窗口化处理

智能穿戴设备的本地告警功能,其判断依据完全依赖于传感器采集到的原始数据。无论是跌倒检测所需的加速度突变,还是心率异常识别所需的PPG信号特征,亦或是低电量提醒所依赖的ADC电压读数,这些数据在进入告警算法之前,都必须经过严格的采集与预处理流程。本章将深入剖析加速度计、心率传感器(PPG)和电量监测模块的原始数据读取方式,重点讲解低通滤波与卡尔曼滤波在信号清洗中的工程应用,并详细阐述采样率设定与滑动窗口化处理对告警实时性和准确性的决定性影响。

穿戴设备数据采集与预处理链路 加速度计 (ADXL345) ±16g / 三轴 / 数字输出 ODR: 100Hz 心率传感器 (PPG) 绿光/红光双通道 采样率: 50Hz 电量监测 (ADC) 电压/电流/温度 采样率: 1Hz 预处理模块 低通滤波 (移动平均) 截止频率: 5Hz (加速度) 卡尔曼滤波 (1D) 过程噪声: 0.01 滑动窗口 窗口: 2s / 步长: 0.5s 特征提取 SVM / 均值 / 峰值 告警判断引擎 跌倒检测 SVM > 阈值 心率异常 HR > 120bpm 久坐提醒 连续1h静止 低电量 电压 < 3.3V 本地告警 振动/声音 关键参数:加速度计ODR=100Hz,心率PPG=50Hz,电量ADC=1Hz;窗口重叠率75% 滤波策略:加速度使用移动平均(窗口5),心率使用卡尔曼滤波(噪声协方差0.01) 告警延迟目标:跌倒<3s,心率异常<10s,低电量<1min

上图展示了从传感器原始数据到告警判断的完整工程链路。在实际嵌入式系统中,这条链路的每一个环节都直接影响着告警的准确性与响应速度。下面我们将分模块深入解析。

4.1 原始数据读取:从寄存器到内存的工程实现

穿戴设备常用的加速度计(如ADXL345、LIS3DH)通过I2C或SPI接口与MCU通信。读取过程并非简单的"读寄存器",而是需要遵循严格的时序要求。以ADXL345为例,其数据寄存器为0x32~0x37,分别存储X、Y、Z轴的低字节和高字节。每次读取需要先设置寄存器地址,然后连续读取6个字节。关键工程要点包括:

  • 字节序处理:加速度数据为16位有符号整数,需将高低字节拼接为int16_t类型,再乘以灵敏度系数(如±16g量程下为3.9mg/LSB)。
  • FIFO缓冲:多数加速度计内置32级FIFO,建议启用FIFO中断,批量读取数据以减少I2C通信开销,降低MCU唤醒频率。
  • 时间戳同步:每次读取需记录当前系统时间(如RTC或Tick值),为后续窗口化处理提供时间基准。

心率传感器(如MAX30102)的读取更为复杂。其内部包含红光和红外光LED及对应的光电二极管,数据寄存器存储的是ADC转换后的原始光电容积脉搏波(PPG)信号。读取时需注意:

// MAX30102 初始化与读取示例(伪代码)
max30102_init(I2C_BUS, 0x57);
max30102_set_mode(HR_MODE);          // 心率模式
max30102_set_sampling_rate(50);      // 50Hz采样
max30102_set_pulse_width(411);       // 411μs脉冲宽度
max30102_set_led_current(RED_LED, 6.4mA);
max30102_set_led_current(IR_LED, 6.4mA);

// 读取FIFO数据
uint32_t red_val, ir_val;
max30102_read_fifo(&red_val, &ir_val);
// 原始值需经过环境光消除和信号归一化处理

电量监测通常利用MCU内置ADC读取电池电压。由于电池电压存在纹波和负载波动,单次采样不可靠,工程上常采用多次采样取平均或使用专用电量计芯片(如MAX17048)直接读取电量百分比。

工程经验:加速度计和心率传感器的I2C通信速率建议设为400kHz(快速模式),但需注意总线电容和上拉电阻匹配。若使用SPI,速率可达1MHz以上,但会占用更多GPIO。对于低功耗设计,建议在每次读取后立即将传感器置于待机模式,仅在需要采集时唤醒。

4.2 滤波处理:低通滤波与卡尔曼滤波的工程选型

原始传感器数据包含大量噪声。加速度计噪声主要来自高频振动(如走路时的冲击)和电气干扰;PPG信号则受环境光、运动伪迹和皮肤血流变化影响;电池电压存在高频纹波。滤波的目标是在保留有效信号特征的同时,最大限度抑制噪声。

4.2.1 低通滤波:移动平均与IIR滤波器

对于加速度数据,跌倒检测关注的是0.5~5Hz频段的信号变化,而走路、跑步的冲击频率通常在10Hz以上。因此,采用截止频率约5Hz的低通滤波器是合理选择。工程中最简单有效的是移动平均滤波:

// 移动平均滤波实现(窗口大小N=5)
#define FILTER_WINDOW 5
float filter_buffer[FILTER_WINDOW];
uint8_t filter_index = 0;
float filter_sum = 0;

float lowpass_filter(float new_sample) {
    filter_sum -= filter_buffer[filter_index];
    filter_buffer[filter_index] = new_sample;
    filter_sum += new_sample;
    filter_index = (filter_index + 1) % FILTER_WINDOW;
    return filter_sum / FILTER_WINDOW;
}

移动平均滤波的优点是计算量小、无相位偏移,但频率响应存在旁瓣泄漏。对于更陡峭的截止特性,可使用二阶IIR巴特沃斯滤波器,但需注意定点数实现时的系数精度问题。

4.2.2 卡尔曼滤波:最优状态估计

卡尔曼滤波在心率信号处理中表现优异,因为它能同时估计信号的真实值和噪声方差。对于一维PPG信号,状态方程和观测方程可简化为:

// 一维卡尔曼滤波核心公式
// 预测:x_pred = x_prev, P_pred = P_prev + Q
// 更新:K = P_pred / (P_pred + R)
//       x_new = x_pred + K * (z - x_pred)
//       P_new = (1 - K) * P_pred

float kalman_filter(float measurement) {
    // 预测
    float P_pred = P_prev + Q;
    // 更新
    float K = P_pred / (P_pred + R);
    float x_new = x_pred + K * (measurement - x_pred);
    float P_new = (1 - K) * P_pred;
    // 更新状态
    x_pred = x_new;
    P_prev = P_new;
    return x_new;
}

关键参数Q(过程噪声协方差)和R(测量噪声协方差)需要根据实际传感器特性调整。对于PPG信号,Q通常设为0.01~0.1,R设为0.1~1.0。Q越大,滤波器响应越快但平滑度降低;R越大,平滑度提高但延迟增加。

滤波策略对比:
指标移动平均IIR低通卡尔曼滤波
计算量极低(O(1))低(O(1))中(O(1))
内存占用需N个样本需2个状态变量需2个状态变量
延迟(N-1)/2个采样周期相位延迟自适应延迟
适用场景加速度预处理电池电压平滑心率信号去噪

4.3 采样率设定与窗口化处理

采样率的选择直接影响功耗和算法性能。过高的采样率导致MCU频繁唤醒,增加功耗;过低的采样率则可能丢失关键信号特征。根据奈奎斯特定理,采样率至少为信号最高频率的2倍,但工程上通常取5~10倍以保证特征提取质量。

4.3.1 各传感器采样率推荐

  • 加速度计:100Hz(ODR)。跌倒检测需要捕捉约50ms的冲击峰值,100Hz可提供10个采样点,足够计算SVM(信号向量模)和峰值特征。
  • 心率传感器:50Hz。PPG信号的主要能量集中在0.5~5Hz,50Hz采样可满足心率变异性(HRV)分析需求,同时降低LED功耗。
  • 电量监测:1Hz。电池电压变化缓慢,1Hz采样足够,且可在每次采样后立即进入低功耗模式。

4.3.2 滑动窗口设计

窗口化处理是连接数据采集与特征提取的桥梁。窗口长度和重叠率需根据告警类型优化:

// 滑动窗口实现(窗口2s,步长0.5s,采样率100Hz)
#define WINDOW_SIZE 200    // 2s * 100Hz
#define STEP_SIZE 50       // 0.5s * 100Hz
#define BUFFER_SIZE 256    // 环形缓冲区

float accel_buffer[BUFFER_SIZE][3];  // 三轴数据
uint16_t write_index = 0;
uint16_t read_index = 0;

void process_window() {
    float window_data[WINDOW_SIZE][3];
    // 从环形缓冲区复制窗口数据
    for (int i = 0; i < WINDOW_SIZE; i++) {
        uint16_t idx = (read_index + i) % BUFFER_SIZE;
        window_data[i][0] = accel_buffer[idx][0];
        window_data[i][1] = accel_buffer[idx][1];
        window_data[i][2] = accel_buffer[idx][2];
    }
    // 计算特征:SVM、均值、峰值等
    float svm = calculate_svm(window_data, WINDOW_SIZE);
    // 更新读指针
    read_index = (read_index + STEP_SIZE) % BUFFER_SIZE;
}

窗口参数选择原则:跌倒检测窗口宜短(1~2s),以快速响应;久坐检测窗口宜长(10~30min),以减少误报;心率异常检测窗口适中(5~10s),平衡实时性与稳定性。

常见误区:窗口重叠率过高(>90%)会显著增加计算量,但特征变化不大;重叠率过低(<50%)可能导致关键事件被窗口边界截断。建议跌倒检测采用75%重叠率,心率检测采用50%重叠率。此外,窗口内数据需保证时间连续性,避免因中断处理导致数据丢失。

4.4 实战案例:跌倒检测数据链路优化

某智能手环项目在开发跌倒检测功能时,初期方案直接使用原始加速度数据计算SVM,导致误报率高达15%。通过数据采集与预处理链路优化,最终将误报率降至2%以下。

初始现象与约束:设备采用Cortex-M4F内核MCU,主频80MHz,电池容量180mAh。原始方案中加速度计以400Hz采样,未启用FIFO,MCU每2.5ms唤醒一次读取数据,导致功耗高达3.5mA。同时,未滤波的SVM信号在走路时峰值可达3.5g,与跌倒时的4g阈值接近,造成大量误报。

关键参数与问题分析:

参数原始方案优化方案
采样率400Hz100Hz
滤波方式无移动平均(窗口5)
窗口长度1s(400点)2s(200点)
重叠率0%75%
MCU唤醒频率400次/秒20次/秒(FIFO批量读取)
功耗3.5mA0.8mA

优化步骤:

  1. 将加速度计ODR从400Hz降至100Hz,启用32级FIFO,设置FIFO中断阈值20个样本,MCU每200ms唤醒一次批量读取。
  2. 在读取函数后立即执行移动平均滤波(窗口5),有效抑制10Hz以上的高频振动噪声。
  3. 将滑动窗口从1s延长至2s,重叠率设为75%,确保跌倒冲击峰值完整落入至少一个窗口内。
  4. 在特征提取中增加"峰值持续时间"特征,要求SVM超过阈值且持续至少80ms才触发告警。

结果对比:优化后,走路时的SVM峰值降至2.2g,与跌倒阈值4g的区分度显著提高。误报率从15%降至1.8%,漏报率保持0%。功耗降低77%,电池续航从3天延长至10天。

风险与代价:窗口延长至2s导致告警延迟增加约0.5s,但仍在3s的响应目标内。FIFO批量读取增加了代码复杂度,需要处理FIFO溢出中断。此外,移动平均滤波引入了约25ms的群延迟,对实时性要求极高的场景需谨慎评估。

复盘经验:数据预处理不是简单的"加个滤波",而是需要根据告警算法的具体需求反向设计。采样率、滤波截止频率、窗口参数三者必须协同优化。建议在开发初期就建立数据采集-预处理-算法评估的完整测试链路,使用真实场景数据(走路、跑步、跌倒模拟)进行参数调优。

调优建议:在调试阶段,可通过蓝牙将预处理后的数据实时传输到PC端,使用Python脚本绘制波形图,直观观察滤波效果和窗口划分是否合理。同时记录每次告警触发前后的原始数据,用于离线回放和算法迭代。

数据采集与预处理是智能穿戴告警系统的"地基"。一个设计良好的预处理链路,不仅能提升告警准确率,还能显著降低系统功耗,延长设备续航。在实际项目中,建议遵循"先采集真实数据、再设计滤波策略、最后优化窗口参数"的开发顺序,避免盲目套用理论参数。