4. 数据采集与预处理:传感器数据采集、异常值检测与处理、缺失值填充、数据平滑与滤波

各位同学,咱们今天聊点实在的。做SOC估算,模型再漂亮,算法再高级,如果数据是垃圾,那结果就是垃圾。我见过太多项目,算法调参调了三个月,最后发现是传感器坏了,数据全是错的。所以,数据采集与预处理,是BMS机器学习项目的基石。

我个人习惯,把数据预处理分成四步走:先搞清楚数据怎么来的,再揪出那些捣乱的异常值,然后填上缺失的坑,最后把数据磨平了、磨顺了。下面咱们一个一个说。

核心观点:数据预处理不是可有可无的“清洁工”,而是决定模型上限的“建筑师”。你花80%的时间做数据清洗,一点都不亏。

4.1 传感器数据采集:源头决定质量

BMS里常用的传感器,无非就是电压、电流、温度这三样。电压用ADC采集,电流用霍尔传感器或分流器,温度用NTC热敏电阻。听起来简单,对吧?但坑都在细节里。

我记得有一次,项目现场反馈SOC跳变特别厉害。排查了三天,最后发现是电流传感器的采样频率太低,只有1Hz。你想想看,电动汽车急加速时电流变化多快?1Hz根本抓不住峰值。后来我们把采样频率提到100Hz,问题就解决了。

这里我给大家列个表,看看不同场景下推荐的采样频率:

应用场景 电压采样频率 电流采样频率 温度采样频率
储能电站(稳态) 1 Hz 10 Hz 0.1 Hz
电动汽车(动态) 10 Hz 100 Hz 1 Hz
消费电子(小电池) 1 Hz 10 Hz 0.2 Hz

另外,传感器本身也有误差。我建议在采集数据之前,先做一次标定。说白了,就是用标准源去校准传感器,把偏移量和增益误差记下来,后面在软件里补偿掉。

4.2 异常值检测与处理:揪出“坏孩子”

异常值,就是那些明显偏离正常范围的数据点。比如电压突然跳到100V,或者电流瞬间变成-5000A。这些数据如果不处理,模型会被它们带偏。

我常用的方法有三种:

  • 3σ原则:假设数据服从正态分布,超过均值±3倍标准差的数据就是异常值。简单粗暴,适合快速筛查。
  • 箱线图法:用四分位数(Q1和Q3)来定义异常值。低于Q1-1.5*IQR或高于Q3+1.5*IQR的数据,就是异常值。这个方法对非正态分布的数据更友好。
  • 基于物理约束:比如锂电池电压不可能超过4.5V,电流不可能超过电池的额定倍率。这些硬性边界,比任何统计方法都可靠。

我曾经在一个项目中,用3σ原则检测异常值,结果把正常的高温数据也误杀了。后来改用物理约束+箱线图组合,效果就好多了。嗯,这里要注意:异常值检测不是越严格越好,要结合业务场景来定。

小技巧:对于时间序列数据,可以先用滑动窗口计算局部均值和标准差,再判断异常。这样能避免把正常的工况变化误判为异常。

处理异常值,我一般有两种策略:

  • 直接删除:如果异常值数量很少(比如不到总数据的1%),直接删掉最省事。
  • 替换为边界值:如果异常值比较多,或者你不想丢失数据,可以用正常范围的边界值(比如Q3+1.5*IQR)来替换。

4.3 缺失值填充:别让数据“断片”

传感器偶尔会掉线,或者通信丢包,导致数据出现空缺。缺失值如果不处理,很多机器学习算法会直接报错。

我常用的填充方法有:

  1. 前向填充:用上一个有效值填充缺失值。适合电压、温度这种变化缓慢的信号。
  2. 线性插值:用缺失点前后的两个有效值,做线性插值。适合电流这种变化相对平滑的信号。
  3. 均值填充:用整个序列的均值填充。这个方法比较粗糙,我一般只在数据缺失率极低(<0.1%)时才用。
  4. 模型预测填充:用KNN或回归模型预测缺失值。这个方法精度高,但计算量大,适合离线处理。

我个人习惯,对于BMS数据,优先用前向填充。为什么?因为电池的电压和温度不会突变,上一个时刻的值就是最合理的估计。我曾经试过用线性插值填充电压缺失,结果在电池快速放电时,插值出来的电压反而比实际值高,导致SOC估算偏大。后来改回前向填充,问题就解决了。

避坑指南:千万不要用全局均值填充!电池的电压和电流是时变的,用全局均值会引入巨大的偏差。我曾经见过一个项目,用均值填充了10%的缺失数据,结果模型精度直接掉了5%。

4.4 数据平滑与滤波:让数据“顺滑”起来

原始数据里总有噪声,比如电磁干扰、量化误差。这些噪声会让SOC估算结果忽高忽低,看起来很不专业。所以,我们需要对数据做平滑处理。

我常用的两种方法:移动平均和中值滤波。

4.4.1 移动平均

移动平均,说白了就是取一个窗口,把窗口内的数据求平均。窗口滑动,平均值也跟着变。公式很简单:

y[t] = (x[t] + x[t-1] + ... + x[t-N+1]) / N

其中N是窗口大小。N越大,平滑效果越好,但信号延迟也越大。我一般把N设为5到20之间,具体看采样频率和噪声水平。

举个例子,假设我们有一组电流数据,用Python实现移动平均:

import numpy as np

def moving_average(data, window_size):
    return np.convolve(data, np.ones(window_size)/window_size, mode='valid')

# 示例数据
current = [10.2, 10.5, 10.1, 9.8, 10.3, 10.0, 9.9, 10.4]
smoothed = moving_average(current, 3)
print(smoothed)  # 输出: [10.27, 10.13, 10.07, 10.03, 10.07, 10.10]

移动平均的优点是计算快,适合实时处理。缺点是它对异常值很敏感,一个大的噪声点会把整个窗口的平均值拉偏。

4.4.2 中值滤波

中值滤波,就是取窗口内的中位数,而不是平均值。它对异常值有天然的鲁棒性。比如窗口内有数据[10, 12, 100],平均值是40.7,但中位数是12。显然,中位数更能代表真实值。

我建议,如果数据里偶尔有尖峰噪声(比如电磁干扰导致的瞬间跳变),用中值滤波效果更好。如果噪声是高斯白噪声(比如ADC量化误差),用移动平均更合适。

下面是一个中值滤波的Python示例:

from scipy.signal import medfilt

# 示例数据,包含一个异常值
voltage = [3.7, 3.71, 3.69, 4.2, 3.7, 3.68, 3.71]
filtered = medfilt(voltage, kernel_size=3)
print(filtered)  # 输出: [3.7, 3.7, 3.71, 3.7, 3.7, 3.7, 3.71]

你看,那个4.2的异常值被直接滤掉了。中值滤波的缺点是计算量比移动平均大,而且会丢失一些细节信息。

我的经验:在实际项目中,我经常把移动平均和中值滤波结合起来用。先用中值滤波去掉尖峰噪声,再用移动平均平滑掉高频抖动。这样既能抗异常,又能保证平滑度。

4.5 本章知识体系总览

为了让大家更直观地理解本章的知识结构,我画了一张流程图。它展示了从原始传感器数据到可用训练数据的完整处理链路。

数据采集与预处理流程 传感器数据采集 异常值检测与处理 缺失值填充 数据平滑与滤波 可用训练数据 3σ原则 / 箱线图 / 物理约束 删除 / 替换为边界值 前向填充 / 线性插值 均值填充 / 模型预测 移动平均 / 中值滤波 组合使用效果更佳

这张图把咱们今天讲的内容串起来了。从传感器采集开始,经过异常值检测、缺失值填充,再到平滑滤波,最后得到干净可用的训练数据。每一步都有多种方法可选,具体用哪个,得看你的数据特点和业务需求。

好了,数据预处理这块就讲到这里。记住一句话:数据质量决定了模型的天花板,算法只是去接近这个天花板。下一章咱们会聊特征工程,到时候这些预处理好的数据就能派上大用场了。


专注资料整理