4. 电池数据集构建与预处理

寿命预测模型的精度上限,往往在数据进入模型之前就已经被决定了。电池老化数据来自充放电测试柜、温箱、BMS 采样通道和实验室记录表,天然带有采样抖动、通信丢包、传感器漂移、人工录入错误和工况不一致等问题。如果直接把这些原始数据拼接成训练集,模型学到的可能是"哪台设备采样更密"或"哪次实验记录更随意",而不是电池真实的衰退规律。因此,数据集构建与预处理的核心目标不是"把数据洗干净",而是构建一条可追溯、可复现、物理意义一致的数据流水线,让任何人用同一份原始数据都能得到同一份训练集。

一、先定义数据契约,再动手清洗

在写任何清洗代码之前,应先明确数据契约:每条记录代表什么对象、什么时间尺度、什么物理量。以常见的磷酸铁锂单体循环老化实验为例,一条标准记录至少应包含:电池编号(cell_id)、循环序号(cycle_index)、时间戳(timestamp)、工步类型(step_type:充电/放电/静置)、电压(V)、电流(I,约定放电为正)、温度(T)、累计安时吞吐量(Ah_throughput)和容量(capacity)。这里必须固定符号约定:本文统一采用放电电流为正、充电电流为负,所有后续计算和图示都遵循这一约定,避免同一份数据在不同脚本中被反向解释。

数据契约还应规定采样频率与聚合粒度。原始采样可能是 1 Hz 甚至 10 Hz,而寿命建模通常关心"每循环一个特征点"。因此需要区分两层数据:原始时序层(保留全部采样点,用于异常检测和曲线分析)与循环特征层(每循环一行,用于建模)。两层之间通过明确的聚合规则连接,例如容量取放电阶段安时积分值,内阻取脉冲前后电压差除以电流。

二、数据清洗与异常值检测

清洗的第一步是物理边界检查,这一步不需要统计模型,只需要领域知识。例如单体电压不应超过 3.65 V 或低于 2.0 V(以 LFP 为例),温度不应超过 60 ℃,电流绝对值不应超过设备量程。超出边界的点应标记为无效而非直接删除,保留标记便于后续统计异常比例。

第二步是统计异常检测。对容量序列,常用方法包括:基于滑动窗口的中位数绝对偏差(MAD)法,以及基于一阶差分的跳变检测。MAD 的稳健性优于 3σ,因为容量衰退本身是单调趋势,σ 会被趋势污染。具体做法是:对每个循环的容量计算其前后各 5 个循环窗口内的中位数 med 和 MAD,若 |cap - med| > 3 × 1.4826 × MAD,则判为可疑点。1.4826 是使 MAD 在正态分布下与标准差一致的比例因子。

需要特别注意的是,容量跳水(knee point)是真实物理现象,不是异常值。LFP 电池在寿命末期常出现容量快速下降,若用统一阈值检测,会把膝点误删,导致模型永远学不会预测突然失效。因此异常检测应结合循环序号分段处理,或在检测后人工复核膝点附近的标记点。

三、缺失值填补与时间对齐

缺失分两类:点缺失(个别采样点丢失)和段缺失(整段工步或整循环丢失)。点缺失可用线性插值或前向填充处理,但插值跨度应设上限,例如连续缺失超过 30 s 就不应插值,而应标记该循环特征为不可靠。段缺失则不能插值,因为缺失的是物理过程本身,只能整循环剔除或从其他通道补测。

时间对齐解决的是多源数据的时间基准问题。测试柜时钟、BMS 时钟和记录表时间往往存在秒级到分钟级偏差。对齐策略是:以测试柜工步日志为主时钟,将 BMS 采样按最近邻或线性重采样到主时钟;对循环级特征,则以"放电起始时刻"为锚点对齐,而不是用绝对时间戳,因为不同电池的循环起止时间本就不同。对齐后应检查每个循环的持续时间是否合理,例如 1C 放电的 LFP 单体放电段通常接近 60 min,若某循环放电段只有 20 min,说明该循环数据不完整。

四、归一化与特征可复现性管理

归一化的关键原则是:统计量只能从训练集计算,再应用到验证集和测试集。如果对全体数据一起做 Z-score,验证集的信息会泄漏进训练过程,导致评估偏乐观。对于按电池编号划分的数据集,更严格的做法是"按电池分组归一化",即用训练电池的均值和标准差去变换测试电池,模拟真实场景中新电池上线的情况。

特征可复现性管理包括三件事:固定随机种子、版本化预处理配置、保存归一化参数。建议把预处理配置写成结构化文件,记录每个特征的变换方式、统计量来源和缺失处理策略。下面是一个可直接参考的配置示例:

preprocess:
  sign_convention: "discharge_positive"
  features:
    capacity:
      transform: "zscore"
      stats_from: "train_cells"
      missing: "drop_cycle"
    internal_resistance:
      transform: "log1p_then_zscore"
      stats_from: "train_cells"
      missing: "interpolate_max_3cycles"
    temperature_avg:
      transform: "minmax"
      range: [15, 45]
      missing: "forward_fill_max_30s"
  outlier:
    method: "mad_window"
    window: 5
    threshold: 3.0
    protect_knee: true
  split:
    by: "cell_id"
    train: ["C01","C02","C03","C04"]
    val:   ["C05"]
    test:  ["C06"]

这份配置的价值在于:任何人拿到原始数据和这份文件,都能复现出完全相同的训练集。归一化参数(均值、标准差、min/max)应随配置一起保存为独立文件,推理时直接加载,而不是重新计算。

电池数据集构建与预处理流水线 原始数据源 测试柜 1Hz 采样 BMS 通道数据 实验记录表 数据契约 字段定义 / 符号约定 放电为正 采样频率 / 聚合粒度 清洗与异常检测 物理边界检查 MAD 滑窗检测 膝点保护 缺失值处理 点缺失:插值 段缺失:剔除 插值跨度上限 时间对齐 主时钟:工步日志 锚点:放电起始 归一化 统计量仅来自训练集 按电池分组变换 可复现性管理 固定随机种子 版本化配置 + 参数 训练/验证/测试集 按电池编号划分 可追溯、可复现 关键检查点 符号约定全文一致:放电为正,充电为负 膝点附近异常标记需人工复核,不可自动删除 连续缺失超过 30 s 不插值,整循环标记为不可靠 归一化统计量仅从训练集计算,防止信息泄漏

五、结果验证与判断依据

预处理完成后,不能只看"代码跑通了",而应检查几个可量化的指标。第一,异常比例:正常实验数据中,被标记为异常或缺失的循环占比通常应低于 5%,若超过 10%,说明要么设备有问题,要么阈值过严。第二,容量序列单调性:清洗后的容量序列应大体单调递减,允许小幅波动,但不应出现反复大幅跳变。第三,训练/测试分布一致性:可对比两组电池的容量均值、内阻均值和温度分布,若差异过大,说明划分方式或归一化策略需要调整。

最后要强调的是,预处理不是一次性工作。当新增电池数据、更换测试设备或调整采样频率时,都应重新走一遍这条流水线,并更新配置版本号。只有把预处理当作可版本化、可审计的工程环节,寿命预测模型的结果才具备工程可信度。