3. 数据采集与预处理:电池测试数据采集与清洗

各位同学,大家好。今天我们来聊聊数据采集与预处理。说实话,这一步在SOC估算里,比算法本身还重要。我见过太多项目,算法模型调得天花乱坠,结果数据一塌糊涂,最后全白费。所以,咱们得把地基打牢。

3.1 电池测试数据采集:电流、电压、温度

电池测试数据,说白了就是三个核心物理量:电流、电压、温度。这三个量,一个都不能少。

  • 电流:反映电池的充放电速率。单位是安培(A)。正电流表示充电,负电流表示放电。我个人习惯用高精度分流器来采集,精度能到0.1%以上。
  • 电压:单体电压和总电压都要采。单体电压能看出电池的一致性,总电压用于整体SOC估算。采样频率建议至少1Hz,动态工况下要10Hz以上。
  • 温度:电池性能对温度极其敏感。我建议在电池模组的正负极、中心位置都布置温度传感器。NTC热敏电阻是常用方案,便宜且可靠。

重要提醒:数据采集的同步性非常关键。电流、电压、温度必须同一时间戳记录。否则,你算出来的SOC会偏差很大。我在项目中遇到过,因为采集板卡时钟不同步,导致SOC误差超过5%。后来加了硬件同步信号才解决。

3.2 数据清洗:异常值处理与缺失值填充

采集到的原始数据,就像刚挖出来的矿石,杂质很多。数据清洗就是把这些杂质去掉。

3.2.1 异常值处理

异常值怎么判断?我常用的方法有三种:

  1. 3σ原则:假设数据服从正态分布,超出均值±3倍标准差的值视为异常。适合静态工况。
  2. 箱线图法:用四分位数(Q1和Q3)计算IQR,超出Q1-1.5*IQR或Q3+1.5*IQR的值视为异常。适合非正态分布数据。
  3. 物理约束法:根据电池特性设定合理范围。比如,磷酸铁锂电池单体电压不会超过3.65V,低于2.0V就是异常。这个方法最可靠,我强烈推荐。

我的经验:我曾经处理过一批数据,电压值突然跳变到5V。用3σ法没检测出来,因为整体数据量大。后来用物理约束法,直接定位到传感器故障。所以,物理约束法永远是第一道防线

3.2.2 缺失值填充

数据缺失的原因很多:通信丢包、传感器掉线、存储故障。处理方式有几种:

  • 删除法:如果缺失比例小于5%,直接删除该行数据。简单粗暴,但有效。
  • 均值/中位数填充:用前后数据的均值或中位数填充。适合短时间缺失。
  • 插值法:线性插值或样条插值。我个人习惯用线性插值,计算量小,效果也不错。
  • 前向填充:用上一个有效值填充。适合温度这种变化缓慢的量。

注意:缺失值填充不能过度。如果连续缺失超过10个点,我建议直接标记为无效数据段,而不是强行填充。否则会引入虚假信息,影响模型训练。

3.3 数据归一化与标准化

为什么要做归一化?你想想看,电流的范围可能是-200A到200A,电压是2.5V到4.2V,温度是-20℃到60℃。这些量纲完全不同。如果不处理,机器学习模型会天然偏向数值大的特征。

常用的方法有两种:

方法 公式 适用场景
Min-Max归一化 x' = (x - min) / (max - min) 数据分布有明确边界,如电压、温度
Z-score标准化 x' = (x - μ) / σ 数据分布近似正态,如电流波动

我个人习惯:电压和温度用Min-Max归一化,电流用Z-score标准化。为什么?因为电压和温度的范围相对固定,而电流的波动范围变化很大,用Z-score能更好地保留分布信息。

# Python代码示例:归一化与标准化
import numpy as np
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# 假设data是numpy数组,列顺序为[电流, 电压, 温度]
data = np.array([[10, 3.2, 25],
                 [20, 3.3, 26],
                 [15, 3.1, 24]])

# 电压和温度用Min-Max归一化
scaler_minmax = MinMaxScaler()
data[:, 1:3] = scaler_minmax.fit_transform(data[:, 1:3])

# 电流用Z-score标准化
scaler_zscore = StandardScaler()
data[:, 0:1] = scaler_zscore.fit_transform(data[:, 0:1])

print(data)

3.4 特征工程初步:差分与滑动窗口

原始数据直接喂给模型,效果往往不好。我们需要构造更有意义的特征。这里介绍两个最基础的操作:差分滑动窗口

3.4.1 差分

差分就是计算相邻时间点的变化量。比如,电流差分能反映电流的变化率,电压差分能反映电压的波动。公式很简单:

Δx(t) = x(t) - x(t-1)

为什么要做差分?因为电池的SOC变化不仅取决于当前状态,还取决于变化趋势。比如,电流突然增大,说明车辆在急加速,SOC会快速下降。差分特征能捕捉这种动态信息。

避坑指南:我曾经在项目中只用了原始特征,模型精度一直上不去。后来加入电流差分和电压差分,RMSE直接降低了15%。所以,差分特征几乎是必加的

3.4.2 滑动窗口

滑动窗口就是取一段时间内的统计量。比如,过去5秒的平均电流、过去10秒的电压标准差。这些统计量能反映电池的短期历史行为。

常用的滑动窗口特征:

  • 均值:反映趋势
  • 标准差:反映波动程度
  • 最大值/最小值:反映极端情况
  • 积分:反映累计电量(Ah)
# Python代码示例:滑动窗口特征
import pandas as pd

# 假设df是DataFrame,包含'current'列
df['current_mean_5s'] = df['current'].rolling(window=5).mean()
df['current_std_5s'] = df['current'].rolling(window=5).std()
df['current_max_10s'] = df['current'].rolling(window=10).max()

注意:滑动窗口的窗口大小需要根据采样频率和工况来定。采样频率1Hz时,窗口5-10秒比较合适。采样频率10Hz时,窗口可以扩大到50-100个点。窗口太小,噪声大;窗口太大,反应迟钝。嗯,这里需要根据实际数据调试。

好了,数据采集与预处理就讲到这里。下一章我们会正式进入机器学习模型的世界。记住,数据质量决定了模型的上限。把这一步做好,后面的路会顺畅很多。