1. 项目背景与数据理解
做电池状态预测这一块的人,大概率都绕不开NASA PCoE(Prognostics Center of Excellence)那套锂离子电池老化数据集。这套数据从2003年左右开始公开,到现在快二十年了,依然是电池健康管理领域用得最多的公开基准数据集之一。我最初接触它是在做动力电池SOH估算相关的课题,当时死活找不到合适的实测数据,公司自测数据又涉及保密问题,最后兜兜转转还是回到了NASA这套数据上。
它之所以“好用”,核心在于:完整记录了一批18650电芯从出厂到寿命终结的反复充放电循环,并且包含了每个循环下的电压、电流、温度曲线。换句话说,你既能从里面提取出内阻、容量这类直接健康因子,也能构造出等压时间差、IC曲线峰高等间接健康因子。
这套数据里用得最多的是第5到第7组(B0005、B0006、B0007、B0018等)。每组包含多个电芯,每颗电芯都是在室温下重复“恒流恒压充电 + 恒流放电”循环,中间每隔一段时间插入一次阻抗测量。注意,它并不是每个循环都测阻抗,而是定期测,所以想拿阻抗做连续特征的话,还得先处理采样不均匀的问题。
1.1 数据文件结构与预处理判断
数据文件是MATLAB格式的 .mat,这个是个坑点,很多人一开始装了 scipy.io.loadmat 就直接读,结果发现读出来的结构体层层嵌套,半天拼不出一个DataFrame。我建议用下面这个方式,一次把电池编号、循环类型、电压、电流、温度都整理清楚:
python复制import scipy.io
import pandas as pd
import numpy as np
def load_nasa_battery(path):
mat = scipy.io.loadmat(path)
# 典型的NASA电池文件结构是 data[0][0]['cycle'][0][0]
cycles = mat[list(mat.keys())[-1]][0, 0]['cycle'][0, 0]
records = []
for i in range(cycles.shape[1]):
cyc = cycles[0, i]
cyc_type = str(cyc['type'][0])
if cyc_type == 'discharge':
# 放电循环
volt = cyc['data'][0, 0]['Voltage_measured'][0, 0].flatten()
curr = cyc['data'][0, 0]['Current_measured'][0, 0].flatten()
temp = cyc['data'][0, 0]['Temperature_measured'][0, 0].flatten()
time = cyc['data'][0, 0]['Time'][0, 0].flatten()
cap = cyc['data'][0, 0]['Capacity'][0, 0].flatten()[-1] # 放电容量
records.append({
'cycle': i + 1,
'type': cyc_type,
'voltage': volt,
'current': curr,
'temperature': temp,
'time': time,
'capacity': cap
})
elif cyc_type == 'charge':
# 充电循环同样提取,但容量不在此列
volt = cyc['data'][0, 0]['Voltage_measured'][0, 0].flatten()
curr = cyc['data'][0, 0]['Current_measured'][0, 0].flatten()
temp = cyc['data'][0, 0]['Temperature_measured'][0, 0].flatten()
time = cyc['data'][0, 0]['Time'][0, 0].flatten()
records.append({
'cycle': i + 1,
'type': cyc_type,
'voltage': v
