数据采集与预处理:电池充放电数据采集、数据清洗、异常值处理、数据归一化与标准化

做SOH算法这些年,我最大的体会就是:数据质量决定了算法上限。你模型再花哨,喂进去一堆脏数据,结果也是白搭。今天咱们就聊聊数据采集与预处理这档子事。

电池充放电数据采集

数据采集是第一步,也是最容易被忽视的一步。我个人习惯把采集分成两个层面:实验室级实车级

实验室数据,说白了就是你在恒温箱里,用充放电柜跑出来的。电压、电流、温度、容量,一条条记录得清清楚楚。我刚开始做的时候,总觉得实验室数据够干净,后来发现——太干净了反而不好。为什么?因为实车数据根本不是这样。

实车数据就复杂多了。你想想看,车辆启动、急加速、能量回收、停车休眠……各种工况混在一起。采样频率也不固定,有的CAN总线1秒传一次,有的10秒才传一次。嗯,这里要注意:采样频率不一致,后期对齐很麻烦

核心采集参数:

  • 电压(单体/总压)
  • 电流(充放电方向)
  • 温度(电芯/模组/环境)
  • 时间戳(精确到毫秒)
  • 累计充放电容量(Ah)

我在项目中遇到过一件事:某款车的数据里,电流值偶尔会跳成负数。查了半天,发现是霍尔传感器零点漂移了。所以啊,采集端加个校验逻辑,能省后面很多事。

数据清洗

数据拿到手,第一件事不是建模,是洗数据。我见过太多人上来就跑算法,结果跑出来一堆垃圾。

清洗什么?

  • 重复数据:同一时间戳出现多条记录,保留第一条或取平均
  • 缺失数据:时间戳断了,用插值还是直接删?看情况
  • 无效数据:比如电压为0、电流为0但SOC在变化——这明显不合理

举个例子,你拿到一段充电数据,电压从3.0V到4.2V,中间突然跳了个3.8V又跳回3.1V。这种大概率是通信丢包或者传感器误报。我一般用滑动窗口滤波来处理:

def sliding_window_filter(data, window_size=5, threshold=0.1):
    filtered = []
    for i in range(len(data)):
        if i < window_size or i >= len(data) - window_size:
            filtered.append(data[i])
            continue
        window = data[i-window_size:i+window_size+1]
        median = np.median(window)
        if abs(data[i] - median) > threshold:
            filtered.append(median)  # 用中位数替换
        else:
            filtered.append(data[i])
    return filtered

小技巧:清洗时别太激进。我曾经一刀切删了太多数据,导致后面训练集不够用。建议先可视化看看分布,再决定清洗策略。

异常值处理

异常值,说白了就是那些「看着就不对」的数据。但怎么定义「不对」?

常见异常类型:

异常类型 示例 处理方法
物理限值超限 电压>5V(磷酸铁锂单体) 直接剔除
跳变异常 1秒内电压变化>0.5V 中值滤波或插值
趋势异常 充电时电压持续下降 检查传感器/剔除片段
静态异常 长时间电压纹丝不动 可能是休眠数据,保留但标记

我记得有一次,某批电池的SOH估算总是偏低。排查了很久,发现是数据里混入了一些「充电未满」的片段。这些片段电压到了4.1V就停了,但实际还没充满。算法误以为容量衰减了。后来我加了个充电截止条件判断:只有电压达到4.2V且电流小于C/20的片段才用来算容量。

避坑指南:我曾经把「温度异常」直接当异常值删了,结果发现冬天低温数据全没了,模型在低温工况下完全失效。后来我改成:异常值先标记,再单独分析,不轻易删除。

数据归一化与标准化

这一步很多人觉得简单,不就是把数据缩放到0~1嘛。其实没那么简单。

归一化(Min-Max Scaling):

def min_max_scaler(data, min_val, max_val):
    return (data - min_val) / (max_val - min_val)

适合电压、温度这种有明确物理边界的参数。比如电压3.0V~4.2V,归一化后就是0~1。但要注意:如果新数据超出了训练时的范围,归一化会失效。我遇到过实车电压跑到2.8V的情况,归一化后变成了负数,模型直接懵了。

标准化(Z-score Normalization):

def z_score_scaler(data, mean, std):
    return (data - mean) / std

适合电流、功率这种分布不确定的参数。标准化后均值为0,方差为1。我个人习惯对电流做标准化,因为电流正负都有,归一化反而不方便。

怎么选?

  • 有明确上下界的参数(电压、温度)→ 归一化
  • 分布未知或存在离群值的参数(电流、功率)→ 标准化
  • 同一批数据里,训练集和测试集要用相同的scaler,别各算各的

我的经验:归一化和标准化不是二选一。有时候我会对电压做归一化,对电流做标准化,对容量做对数变换。关键是理解你的数据分布,而不是套公式。

你想想看,如果电压和电流的量纲差了几十倍,不归一化的话,模型会天然偏向数值大的特征。说白了,预处理做得好,模型训练事半功倍

嗯,数据采集与预处理就聊到这儿。下一章咱们聊聊特征工程——怎么从这些数据里挖出对SOH有用的信息。