4、数据预处理:去噪、滤波(低通/高通)、归一化、滑动窗口分割等常用技术
TinyML 传感器建模的起点并非模型结构,而是数据质量。传感器采集到的原始信号是物理世界与电路噪声、环境干扰、量化误差的混合体。若将未经处理的原始数据直接送入端侧模型,轻则导致模型收敛缓慢、泛化能力差,重则使分类器学习到噪声的“伪特征”,在真实部署时完全失效。本章围绕去噪、滤波、归一化与滑动窗口分割四项核心技术展开,帮助读者建立一套适用于资源受限设备的传感器数据预处理流水线。
4.1 去噪:从时域到频域的噪声识别
传感器噪声来源多样:热噪声(白噪声)、电源纹波(50Hz/100Hz 及其谐波)、机械振动耦合、量化噪声(ADC 分辨率不足)以及环境电磁干扰。在 TinyML 场景下,去噪的目标不是“完美还原真实信号”,而是在计算资源与延迟约束内,最大化信噪比(SNR),使后续特征提取更稳定。
核心原理:噪声通常表现为高频成分或与信号频带重叠的干扰。去噪的本质是设计一个滤波器,让目标信号频带通过,抑制非目标频带。对于加速度计、陀螺仪等惯性传感器,人体活动信号主要集中在 0.5Hz~20Hz;对于麦克风,语音信号在 300Hz~3.4kHz;对于环境温湿度传感器,变化极为缓慢,低于 1Hz。因此,去噪策略必须依据信号频带与噪声频带的相对关系选择。
判断方法:在开始滤波之前,建议先对原始数据做一次快速频谱分析(如 FFT),观察信号与噪声的频带分布。若噪声均匀分布在整个频带(白噪声),低通滤波即可;若存在明显的 50Hz 工频尖峰,则需要陷波器(Notch Filter);若基线缓慢漂移(如温度变化导致传感器零点偏移),则需高通滤波。
y[n] = α·x[n] + (1-α)·y[n-1])仅需 2 次乘法和 1 次加法,即可实现有效的低通滤波,适合 Cortex-M0 级别的内核。α 值由截止频率与采样率决定:α = 1 / (1 + 2π·fc/fs)。
4.2 滤波技术:低通、高通与带通的选择策略
滤波是数据预处理的核心环节。在 TinyML 中,滤波器的选择直接影响模型输入的质量与计算开销。
| 滤波器类型 | 传递函数(一阶) | 典型应用 | MCU 计算量 | 注意事项 |
|---|---|---|---|---|
| 低通 (LPF) | y[n] = y[n-1] + α·(x[n] - y[n-1]) | 加速度计去高频振动 | 2 乘 1 加 | 截止频率需高于信号最高频率 |
| 高通 (HPF) | y[n] = α·(y[n-1] + x[n] - x[n-1]) | 去除呼吸信号中的基线漂移 | 2 乘 2 加 | 会衰减低频有效成分 |
| 带通 (BPF) | LPF + HPF 级联 | 心电信号 (0.5-40Hz) | 4 乘 3 加 | 需分别设定上下截止频率 |
| 中值滤波 | 排序取中值(窗口 N=3/5) | 去除脉冲噪声(尖峰) | N·log(N) 比较 | 窗口不宜过大,否则延迟明显 |
操作流程:首先确定采样率 fs(如 IMU 常用 50Hz~200Hz)。然后根据信号物理特性确定截止频率 fc。例如,人体步态识别中,步行频率约 1~2.5Hz,跑步约 2.5~4Hz,因此低通截止频率设为 10Hz 即可保留主要能量并滤除高频抖动。若使用 IIR 滤波,需注意相位失真问题——IIR 滤波器在截止频率附近会产生非线性相位偏移,可能导致波形畸变。对于需要保持波形形态的应用(如心电 R 波检测),建议使用零相位滤波(如 scipy.signal.filtfilt)在离线阶段处理,或使用 FIR 滤波器保证线性相位。
4.3 归一化:让特征尺度一致
不同传感器通道的量纲和数值范围差异巨大。例如,加速度计输出范围为 ±2g(约 ±19.6 m/s²),而陀螺仪输出范围为 ±250°/s,磁力计则可能输出 ±4800mGauss。若直接拼接这些特征输入模型,数值范围大的通道会主导梯度更新,导致模型偏向某些传感器,降低泛化能力。
核心原理:归一化将各通道数据映射到统一尺度(如 [0,1] 或均值为 0、方差为 1),使模型能够平等对待每个特征维度。两种最常用的方法:
- Min-Max 归一化:
x' = (x - x_min) / (x_max - x_min),将数据线性映射到 [0,1]。适用于已知数据边界且无极端离群值的场景。缺点是对离群值敏感,一个异常尖峰会压缩正常数据的分布范围。 - Z-score 标准化:
x' = (x - μ) / σ,使数据服从均值为 0、标准差为 1 的分布。适用于数据近似高斯分布或存在离群值的场景。在 TinyML 中,μ 和 σ 需在训练集上预先计算并固化为常量,部署时直接代入。
操作流程:在训练集上计算每个通道的 min/max 或 μ/σ,保存为 C 语言头文件中的常量数组。推理时,对每个新样本执行相同的线性变换。注意:归一化参数只能从训练集统计,不能使用测试集或实时数据的统计值,否则会引入数据泄漏(Data Leakage),导致评估结果过于乐观。
norm_params.h 头文件,MCU 端仅需 6 次减法、6 次乘法即可完成归一化。
4.4 滑动窗口分割:构建时间序列样本
传感器数据是连续的时间序列流,而分类模型通常需要固定长度的输入。滑动窗口分割将无限长的数据流切分为有限长度的样本片段,每个片段对应一个分类标签。
核心参数:窗口长度(W)与步长(S)。窗口长度决定了单个样本包含的时间跨度,需覆盖至少 1~2 个完整活动周期。例如,步态周期约 1~1.2 秒,窗口长度设为 2 秒(100Hz 采样率下为 200 个采样点)可确保包含完整的步态周期。步长决定了相邻窗口的重叠率(Overlap = 1 - S/W)。重叠率越高,样本数量越多,模型训练更充分,但推理时计算量也越大。
标签对齐策略:窗口的标签通常取窗口中心时刻的标签(适用于实时分类),或取窗口内多数投票标签(适用于离线标注)。对于动作切换的过渡段,建议丢弃或单独标注,避免标签噪声。
// 滑动窗口分割伪代码(C 语言风格)
#define WINDOW_SIZE 200 // 2秒 @ 100Hz
#define STEP_SIZE 50 // 0.5秒步长,重叠率 75%
#define NUM_CHANNELS 6 // 3轴加速度 + 3轴陀螺仪
float buffer[WINDOW_SIZE][NUM_CHANNELS];
int buffer_index = 0;
void process_sample(float* sample) {
// 将新样本写入环形缓冲区
memcpy(buffer[buffer_index], sample, NUM_CHANNELS * sizeof(float));
buffer_index = (buffer_index + 1) % WINDOW_SIZE;
// 每积累 STEP_SIZE 个新样本,触发一次推理
static int step_counter = 0;
if (++step_counter >= STEP_SIZE) {
step_counter = 0;
// 从缓冲区按顺序提取窗口数据(注意环形缓冲区的索引映射)
float window[WINDOW_SIZE][NUM_CHANNELS];
for (int i = 0; i < WINDOW_SIZE; i++) {
int idx = (buffer_index + i) % WINDOW_SIZE;
memcpy(window[i], buffer[idx], NUM_CHANNELS * sizeof(float));
}
// 调用模型推理函数
run_inference(window);
}
}
案例拆解:某工业设备预测性维护项目,使用振动传感器(采样率 20kHz)监测轴承故障。原始数据包含正常、内圈故障、外圈故障、滚动体故障四种状态。初始方案采用 W=1024 点(约 51ms),S=512 点,重叠率 50%。模型准确率仅 91.2%。分析发现:轴承故障特征频率(BPFO/BPFI)在 100~400Hz 之间,1024 点窗口仅包含 2~5 个故障周期,特征不充分。调整后:W=4096 点(约 205ms),S=512 点,重叠率 87.5%。准确率提升至 97.8%。但代价是推理延迟从 25ms 增至 100ms,且内存占用从 4KB 增至 16KB。最终通过降低采样率至 10kHz(W=2048 点)平衡了精度与资源。
4.5 预处理流水线的工程落地与验证
在 MCU 上实现预处理流水线时,需考虑内存、延迟与功耗的平衡。建议采用“分阶段处理”架构:传感器中断服务程序(ISR)中仅做数据搬运和轻量级去噪(如移动平均),主循环中完成归一化与窗口分割,推理任务由独立任务或硬件加速器(如 CMSIS-DSP)执行。
验证方法:在 PC 端使用 Python 完成预处理后,将处理后的数据导出为 C 数组,在 MCU 上运行相同的预处理代码,对比输出是否一致(允许浮点误差 < 1e-5)。同时,记录每个阶段的耗时与内存峰值,确保满足实时性要求。
| 阶段 | 内存占用(典型值) | 延迟(@100Hz 采样) | 优化建议 |
|---|---|---|---|
| 原始数据缓冲 | W × C × 4 字节 | 0ms(DMA 搬运) | 使用环形缓冲区,避免 memcpy |
| 滤波 | 滤波器状态变量(每通道 2-4 字节) | < 0.1ms | 定点数替代浮点,使用 CMSIS-DSP |
| 归一化 | 参数表(每通道 8 字节) | < 0.05ms | 预计算 1/σ,用乘法替代除法 |
| 窗口分割 | 窗口数据副本(W × C × 4 字节) | < 0.2ms | 使用指针索引,避免数据拷贝 |
总结复盘:数据预处理不是“一刀切”的固定流程,而是需要根据传感器类型、目标信号频带、MCU 资源约束进行定制。核心原则是:先分析信号与噪声的频带分布,再选择滤波策略;先确定窗口长度覆盖完整活动周期,再调整步长平衡样本量与延迟;归一化参数必须在训练集上统计并固化。建议在项目初期建立一套自动化的预处理评估脚本,对比不同参数组合下的模型准确率、内存占用与推理延迟,以数据驱动的方式确定最优配置。