
简介这份NASA锂电池试验数据集面向电池管理、储能系统与新能源方向的研究人员和工程师提供锂离子电池充放电循环过程中的实测记录可用于分析电池性能衰退、优化充电策略并支撑剩余寿命预测等研究。压缩包共65个文件约28.56MB以mat数据文件为核心辅以xml、h、c、rsp等工程与代码文件以及txt说明文档兼顾数据读取与算法验证需求。目前已有528人学习下载具备一定参考热度。读者可借助其中的电压、电流、温度等时序数据开展充放电速率影响、高低温环境表现及长期老化建模等分析也可用于训练机器学习模型进行状态识别与故障诊断是电池科学与数据驱动研究结合的实用素材。1. 电池充放电数据集从一份 NASA 锂电池试验数据说起做电池健康管理BHM和剩余寿命RUL预测的人绕不开一个尴尬算法写得再花哨没有带真实衰减轨迹的数据模型就是空中楼阁。这份「电池充放电数据集-NASA锂电池试验数据集.zip」解决的正是这个起点问题——它把多颗 18650 电芯在恒流恒压充放电循环下的电压、电流、温度、容量随循环衰减的完整记录打包在一起属于公开的电池老化基准数据。适合三类人刚入门 RUL 想跑通第一条预测曲线的新手、需要横向对比 LSTM/GRU/Transformer 等模型的老手、以及做电池均衡与 SOH 估计的工程验证人员。它不提供现成模型提供的是可复现的衰减事实。2. 数据集结构与充放电循环原理先看懂再动手2.1 文件组织与字段含义拿到压缩包解压后常见做法是按电芯编号分目录每个目录下是若干.mat或.csv文件对应一次完整的充放电测试。以典型的 NASA 锂电池数据组织方式为例结构大致如下NASA_Battery_Data/ ├── B0005/ │ ├── charge_1.csv │ ├── discharge_1.csv │ └── impedance_1.csv ├── B0006/ ├── B0007/ └── B0018/每个文件里最关键的几列是字段含义单位用途Voltage_measured端电压V判断充放电截止、提取 IC 曲线Current_measured实测电流A计算安时积分容量Temperature_measured表面温度℃热特性与异常检测Current_charge充电电流设定A区分 CC/CV 阶段Capacity放电容量AhSOH 标签的直接来源需要提醒的是不同电芯的循环次数并不一致B0005 和 B0006 通常能到 160 次以上B0018 可能只有 130 次左右。这不是数据缺失而是电芯在容量跌到失效阈值后测试就停止了。做多电芯联合训练时必须按各自的有效循环数截断否则会引入大量填充值污染标签。2.2 充放电循环的物理过程锂电池一次完整循环分三段恒流充电CC、恒压充电CV、恒流放电。CC 阶段电流恒定电压从下限爬升到上限CV 阶段电压钉在上限电流指数衰减到截止值放电阶段电流反向电压从上限滑到下限。容量衰减的本质是活性锂损失和阻抗增加表现为同一放电截止电压下能放出的安时数逐循环减少。理解这一点才能明白为什么特征工程里常提取「等压差时间」「IC 曲线峰值」「放电初期电压降」——它们分别对应阻抗、相变和极化。如果只把原始电压序列丢进网络模型很难学到衰减的物理含义这也是很多人跑出来 RMSE 忽高忽低的玄学来源。2.3 用 Python 快速加载并画出容量衰减曲线下面这段代码完成三件事读取单颗电芯的放电文件、按循环提取容量、画出 SOH 曲线。依赖pandas、numpy、matplotlib。import pandas as pd import numpy as np import matplotlib.pyplot as plt from pathlib import Path # 数据根目录按实际解压路径修改 DATA_ROOT Path(./NASA_Battery_Data) CELL B0005 def load_discharge_capacity(cell_dir: Path): 遍历放电文件提取每个循环的放电容量 records [] # 按文件名中的循环序号排序避免字符串排序错乱 files sorted(cell_dir.glob(discharge_*.csv), keylambda p: int(p.stem.split(_)[1])) for f in files: cycle int(f.stem.split(_)[1]) df pd.read_csv(f) # 容量取该循环放电安时的最大值等价于满放容量 cap df[Capacity].max() records.append({cycle: cycle, capacity: cap}) return pd.DataFrame(records) cap_df load_discharge_capacity(DATA_ROOT / CELL) # 以首循环容量为基准计算 SOH cap_df[SOH] cap_df[capacity] / cap_df[capacity].iloc[0] plt.plot(cap_df[cycle], cap_df[SOH], markero, ms3) plt.xlabel(Cycle) plt.ylabel(SOH) plt.title(f{CELL} capacity fade) plt.grid(True) plt.show()逻辑说明glob匹配放电文件int转换保证循环顺序正确这是很多人第一次读数据时踩的坑——直接按字符串排序会出现discharge_10排在discharge_2前面。Capacity列取max是因为放电过程中容量单调累积末值即该循环总放电量。参数上DATA_ROOT和CELL必须按实际解压结果改不同来源的字段名可能略有差异遇到KeyError先打印df.columns核对。3. 特征工程与 SOH 估计把原始曲线变成可训练样本3.1 从电压电流到健康特征原始数据是时间序列直接喂给模型维度高、噪声大。常见做法是每个循环提取一组标量特征构成「循环—特征—SOH」的表格。我一般会取这几类放电电压从 4.2V 降到 3.0V 所用的时间反映可用容量放电初期 10 秒内的电压降反映内阻恒流充电阶段电压从 3.8V 升到 4.0V 的时间反映极化温度曲线的峰值和均值反映热状态。这些特征和 SOH 的相关性通常比原始序列高得多。下面给出提取等压差时间的函数def extract_voltage_drop_time(df, v_high4.0, v_low3.8): 提取放电过程中电压从 v_high 降到 v_low 的耗时秒 # 假设存在 Time 列单位秒若无则用行号近似 if Time not in df.columns: df df.reset_index().rename(columns{index: Time}) mask (df[Voltage_measured] v_high) (df[Voltage_measured] v_low) seg df[mask] if len(seg) 2: return np.nan # 该循环未覆盖此区间标记缺失 return seg[Time].iloc[-1] - seg[Time].iloc[0]参数说明v_high和v_low要落在放电平台内取 4.0/3.8 是常见经验值但不同电芯截止电压不同B0018 的曲线整体偏低需要相应下调。返回NaN的循环在训练前要么剔除要么用前后循环插值直接填 0 会让模型误以为该循环瞬间完成放电。3.2 构建训练集与标签对齐把每颗电芯的特征表纵向拼接就得到监督学习数据集。标签是 SOH输入是特征向量。注意两点一是不同电芯首循环容量不同SOH 必须各自归一化不能全局归一二是训练集和测试集要按电芯划分而不是按循环随机划分否则同一颗电芯的相邻循环会同时出现在两边造成数据泄漏指标虚高。def build_dataset(root: Path, cells): frames [] for c in cells: cap_df load_discharge_capacity(root / c) feats [] for f in sorted((root / c).glob(discharge_*.csv), keylambda p: int(p.stem.split(_)[1])): df pd.read_csv(f) feats.append({ v_drop_time: extract_voltage_drop_time(df), temp_max: df[Temperature_measured].max(), cap: df[Capacity].max(), }) feat_df pd.DataFrame(feats) feat_df[SOH] feat_df[cap] / feat_df[cap].iloc[0] feat_df[cell] c frames.append(feat_df) return pd.concat(frames, ignore_indexTrue) data build_dataset(DATA_ROOT, [B0005, B0006, B0007]) # 按电芯划分B0005/B0006 训练B0007 测试 train data[data[cell] ! B0007] test data[data[cell] B0007]这样划分后测试集是完全没见过的电芯指标更接近真实部署场景。如果只追求论文里的漂亮数字按循环随机划分确实好看但上线就翻车这是血泪经验。3.3 一个最小可用的 SOH 回归基线特征有了先用线性回归或随机森林跑通流程确认数据管线没问题再上深度模型。下面用sklearn的随机森林做基线from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error feature_cols [v_drop_time, temp_max] X_train train[feature_cols].fillna(train[feature_cols].median()) y_train train[SOH] X_test test[feature_cols].fillna(train[feature_cols].median()) y_test test[SOH] model RandomForestRegressor(n_estimators200, max_depth6, random_state42) model.fit(X_train, y_train) pred model.predict(X_test) rmse mean_squared_error(y_test, pred, squaredFalse) print(fTest RMSE: {rmse:.4f})参数上n_estimators200是精度和速度的折中max_depth6防止过拟合小样本。填充用训练集中位数而非全局中位数避免测试信息泄漏。如果 RMSE 在 0.02 以内说明特征有效如果超过 0.05先检查 SOH 归一化是否按电芯做了再检查等压差时间是否大量为NaN。4. 避坑与排查这份数据集最容易翻车的五个地方4.1 现象容量曲线出现锯齿状跳变原因某些循环的放电文件不完整或者测试中途中断Capacity末值偏小。解决对容量序列做中值滤波或 3σ 异常检测把偏离前后循环超过 15% 的点标记为异常用相邻循环均值替换。不要直接删除否则循环序号不连续后续按序号对齐会错位。4.2 现象模型在验证集上 RMSE 很低换一颗电芯就崩原因按循环随机划分导致数据泄漏同一颗电芯的相邻循环高度相似。解决严格按电芯划分训练/验证/测试至少留一颗完整电芯做测试。如果电芯数量太少用留一法交叉验证每次留一颗。4.3 现象读取.mat文件时报NotImplementedError原因部分.mat是 MATLAB v7.3 格式scipy.io.loadmat不支持。解决改用h5py读取或者用mat73库。代码里加一层判断import h5py from scipy.io import loadmat def read_mat(path): try: return loadmat(path) except NotImplementedError: with h5py.File(path, r) as f: return {k: f[k][:] for k in f.keys()}4.4 现象温度特征和 SOH 几乎不相关原因温度受环境散热影响大不同电芯测试时的环境温度不一致原始温度绝对值不可比。解决改用温度相对变化量比如放电过程温升峰值减起始值或者对每颗电芯的温度做 z-score 标准化后再拼接。4.5 现象训练 loss 震荡不收敛原因特征量纲差异大等压差时间可能是几百秒温度只有几十度。解决用StandardScaler对特征标准化注意 scaler 只能在训练集上 fit再 transform 测试集。另外学习率调小到 1e-3 以下batch size 不要超过 32小样本下大 batch 会让梯度噪声不足。5. 进阶技巧用滑动窗口做 RUL 预测与结果验证SOH 估计是「当前健康度」RUL 预测是「还能用多久」后者更接近工程需求。做法是把 SOH 序列当成时间序列用前 N 个循环预测第 Nk 个循环的 SOH当预测值跌破失效阈值常见 0.7 或 0.8时对应循环数减去当前循环数就是 RUL。具体操作对每颗电芯的 SOH 序列做滑动窗口切分窗口长度取 30预测步长取 1构造(样本数, 30, 1)的输入。用 LSTM 或一维卷积都可以但小样本下 LSTM 容易过拟合我一般先用一维卷积加全局池化参数量少、训练稳。import numpy as np def make_windows(soh_series, window30): X, y [], [] for i in range(len(soh_series) - window): X.append(soh_series[i:iwindow]) y.append(soh_series[iwindow]) return np.array(X)[..., np.newaxis], np.array(y) # 假设 soh 是某颗电芯的 SOH 数组 soh cap_df[SOH].values X, y make_windows(soh, window30) print(X.shape, y.shape) # (n, 30, 1) (n,)验证方法上不要只看 RMSE还要看 RUL 误差。做法是对测试电芯从某个循环开始滚动预测记录预测 SOH 首次跌破阈值时的循环数和真实阈值循环数比较误差在 ±10 个循环以内算可用。这个指标比 RMSE 更贴近实际维护决策。还有一个容易忽略的点失效阈值的选择会显著影响 RUL 误差。阈值定在 0.7 时不同电芯的真实 RUL 差异大模型很难统一可以先在 0.8 上验证趋势再迁移到 0.7。从那以后我每次做 RUL 实验都强制把「按电芯划分 滚动预测 阈值误差」这三步走一遍不再只看单点 RMSE。希望帮到你。本文还有配套的精品资源点击获取