☰
NASA电池数据集全解:从SOH估计到RUL预测的建模实操
2026/10/10 18:58:43 网站建设 项目流程

简介:NASA锂电池老化实验数据集,面向电池寿命预测、SOC估计与健康管理(PHM)研究场景,适合从事电池退化建模、剩余使用寿命预测和充放电策略分析的研究者与工程师。数据源自NASA Ames预测卓越中心,完整记录了锂离子电池在不同温度下的充放电循环实验,并将阻抗作为电池老化的损伤判据。压缩包共35个文件,以33个MAT数据文件为主,辅以1个M脚本用于容量计算和1个TXT说明文件,总体积174.12MB,可直接在MATLAB中加载使用。目前已有4306人学习下载。借助这套数据,可提取电压、电流、容量和阻抗等多维特征,开展SOC估计、SOH评估及剩余寿命预测实验,也可作为电池管理算法验证和PHM方法研究的标准测试基准。 做电池健康管理、寿命预测方向的研究,一定会绕不开一份数据:NASA艾姆斯研究中心的电池实验数据集。我最早接触它是在做锂离子电池剩余寿命(RUL)预测的硕士课题时,当时在公开数据里翻了一圈,最后几乎所有论文的对比实验都用这份数据,因为它的工况定义清晰、老化轨迹完整,而且免费开放。后来做BMS算法评估、储能系统健康状态(SOH)估计,它也一直是我用来验证pipeline的首选数据集。

这篇博文我想把这份数据集的来龙去脉、文件结构、隐藏细节和建模实操完整讲一遍。不管你是刚开始接触电池数据挖掘的学生,还是已经在做电池管理系统算法开发的工程师,只要打算用NASA这份数据做SOH估计、RUL预测或者迁移学习实验,这篇文章都能帮你少踩不少坑。

1. 实验台背后的设计:四块电池与三个老化变量

1.1 四块18650电池与三种测试动作

NASA这个数据集来自艾姆斯研究中心的预测卓越中心(PCoE),用的实验对象是四块商用18650锂离子电池,编号分别是B0005、B0006、B0007和B0018。电池标称容量2Ah,标称电压3.6V左右。整个实验过程中,每块电池反复执行三种动作:充电、放电、阻抗测量。

充电采用的是标准的恒流恒压(CC-CV)策略:先用1.5A恒流把电池充到4.2V,然后转为4.2V恒压,直到充电电流降到20mA才停止。放电则是2A恒流放电,每块电池的截止电压不同,这是整个实验里最重要的变量:

电池编号放电截止电压实验定位
B00052.7V浅放对照组
B00062.5V中等放电深度
B00072.2V深放组
B00182.5V与B0006截止电压相同,可做重复性对照

每完成一次完整的充放电循环,实验系统会插入一次阻抗测量,用扫频的方式记录电池在不同频率下的交流阻抗响应。所以,每个循环的数据文件里其实包含了充电、放电、阻抗三部分记录,这三部分对应了电池老化过程中不同维度信息的快照。

1.2 为什么放电截止电压是核心实验变量

很多人第一次看这份数据,会把注意力放在充电策略上,但真正控制老化速度的是放电深度。放电截止电压越低,意味着每次循环里从正负极材料中脱嵌的锂离子越多,电极材料的体积应变越大,SEI膜的破裂和重构也越频繁,容量衰减自然更快。

实验里1.5A充、2A放的设计也很有意思。按2Ah标称容量算,2A放电正好是1C倍率,既不会因为倍率过高导致电池瞬间过热,又能把一次循环压缩在合理时间内。NASA选的这个工况介于常规使用和加速老化之间,所以数据既不像手机电池那种浅充浅放模式那么温和,也不像纯高温高倍率加速老化那样极端,非常适合用来验证寿命预测算法。

1.3 阻抗测量是穿插在循环里的“体检报告”

阻抗测量的物理意义值得多说两句。锂电池的老化不光是容量下降,内部电化学过程也在悄悄变化。通过电化学阻抗谱,可以分离出电解液电阻、SEI膜电阻、电荷转移电阻等不同环节的贡献。数据文件中对应的字段包括实部阻抗、虚部阻抗以及计算出的Re、Rct等参数。

但使用阻抗数据时要有清醒认识:它的采样频率很低,每个循环只在充放电间隙测一轮,时间分辨率远低于电压电流数据。它更适合作为描述电池内部状态缓慢演变的辅助特征,而不是用来做逐秒级别的动态预测。

2. 拆开MAT文件:B0005里每一层数据是什么

2.1 用Python加载嵌套的mat结构

NASA在官网上提供的是MAT格式文件,用MATLAB的load可以直接读。国内更多人用Python,scipy.io.loadmat也能读,但读出来的是嵌套的numpy结构数组,很多新手第一次接触会懵。

我先给出一个可以跑的加载代码:

import scipy.io import numpy as np mat = scipy.io.loadmat('B0005.mat') battery = mat['B0005'] # battery 是一个 1x1 的结构,通过 cycle 字段拿到循环记录 cycle = battery[0, 0]['cycle'] print(type(cycle), cycle.shape) # 遍历所有循环,统计不同类型记录的数量 type_counts = {} for i in range(cycle.shape[1]): t = cycle[0, i]['type'][0, 0] type_counts[t] = type_counts.get(t, 0) + 1 print(type_counts)

运行后你会发现,B0005里总共包含大概168个循环,其中大部分是完整的充放电循环,夹在中间的还有一些单独标记的阻抗测试。charge、discharge、impedance三种类型都可以在这里区分出来。

2.2 充放电状态混叠:按type分流是第一步

这份数据文件里,每个cycle节点下既有充电数据又有放电数据。如果你不去看type字段,直接把所有数据遍历并画图,或者直接塞给模型,结果肯定是灾难性的,因为充电的电压在上升、放电的电压在下降,电流方向也相反,混在一起做序列建模时模型会学到完全错误的规律。

所以拿到数据的第一步永远是分流。用上一节的type统计结果,把几类数据分别提取出来。放电数据中还有一个Capacity字段,代表这个循环放电阶段累计放出的容量,这个值就是后续计算SOH和RUL的最基础标签。

2.3 Capacity字段其实是重复值,别被坑了

这里有个小坑:放电数据中每一行采样点都带一个Capacity字段,但Capacity并不是该采样时刻的实时容量,而是整个循环结束后累计的容量值,被赋值到了该循环的每一行上。也就是说,你随便取放电阶段数据的任意一行,读到的Capacity都是一样的。

正确的用法是取第一个放电采样点的Capacity,或者直接取该循环记录里Capacity数组的第一个元素。如果用pandas把整个放电段读成DataFrame后,直接对Capacity求平均值倒也不会出错,但会白白浪费算力,而且如果你在做增量计算,很容易在后面的时序建模中引入重复值泄漏。

3. 三个容易忽略的数据细节,直接影响预测误差

3.1 采样间隔不齐:别把电池数据当成等间隔时序

NASA数据虽然记录频率看起来是固定的,但仔细检查会发现,充电阶段和放电阶段的采样间隔并不完全一致。充电记录通常更密一些,而且不同循环之间,由于充电时间随老化缩短,实际采到的数据点数也会变少。

这带来一个实际问题:如果你直接把原始电压序列按时间步喂给LSTM或Transformer,不同样本的序列长度可能不一致,需要padding或者截断;更麻烦的是,老化的信息恰恰体现在序列长度变短这个现象里,如果padding截断做得不好,等于把最核心的老化特征抹掉了一部分。

我的建议是:做特征提取时优先用循环编号作为序列索引,把每个循环内的原始曲线先压缩成标量特征,比如恒流充电时间、等压升时间差、容量、温度峰值等。这样建模时用的是固定长度特征向量,完全绕开采样间隔不齐的问题。

3.2 SOH口径不统一,你的结果和论文没法比

SOH的定义在不同文献里差异很大。有人用当前容量除以初始额定容量,有人用当前容量除以第一个完整循环的实测容量,还有人用内阻变化来定义。NASA电池的额定容量是2Ah,但B0005实测第一个完整循环的放电容量大约在1.85Ah到1.97Ah之间,和标称值差了约7%。

如果A论文用2Ah当分母,B论文用第一个循环实测容量当分母,同一个电池同一时刻的SOH数值会差出好幾個百分点,结论自然不可比。我的经验是:无论用哪个口径,都要在论文或实验报告里写明分母的具体值,并且建议用首个完整循环的实测容量作为基准,因为它更接近电池当下的真实可用容量。

3.3 温度数据是表面温度,不是内部温度

数据文件里的Temperature_measured字段来自贴在电池表面的热电偶,不是电池内部温度。这带来两个后果:第一,温度曲线相比内部电化学产热会有明显滞后,快速放电时表面温度上升比内部慢;第二,在循环的后半段,温度开始下降并不意味着电池不再产热,可能只是环境热平衡在起作用。

所以,如果你直接用温度数据做RUL预测的输入特征,要意识到它和容量衰减之间不是简单的因果关系,更像是一个相关指标。温度可以作为辅助特征,但不要指望它单独给出对老化机理的精确解释。

4. 从容量曲线到RUL:一个能直接跑的建模基线

4.1 先把RUL预测问题定义清楚

以B0005为例,我们可以把问题定为:已知前40个完整循环的充放电数据,预测电池容量首次低于1.4Ah的循环序号。1.4Ah对应标称容量的70%,这是一个比较常见的退役阈值。不同的电池阈值不同,比如B0007由于设计上就偏深放,容量衰减更快,同一个阈值对应的循环数会明显少于B0005。

按这个定义,RUL的标签是离散值,比如“第147个循环达到退役条件”。为了验证算法效果,通常用前40个循环的数据训练,然后预测后续所有循环的容量或RUL,再和真实曲线对比。

4.2 从恒流充电曲线提取等压升时间差特征

电池老化后,最直观的变化是恒流充电阶段电压上升更快,因为能容纳的锂离子变少了。为了把这个现象量化为特征,可以用“等压升时间差”方法:取恒流充电段的电压与时间序列,从3.0V开始,每隔0.1V记录一次对应的时间点,计算相邻电压档位之间的时间长度。这一系列时间差构成了一个特征向量。

这个特征的效果相当好,因为它是dQ/dV的间接体现,而dQ/dV曲线峰值的变化能直接反映电池容量衰减。我建议把整个恒流段的等压升时间差向量作为特征序列输入模型,而不是只用某个单一时间点。示例代码如下:

def extract_delta_t(voltage, time, v_start=3.0, v_end=4.2, v_step=0.1): levels = np.arange(v_start, v_end + 1e-6, v_step) t_at_level = [] for v in levels: idx = np.where(voltage >= v)[0] t_at_level.append(time[idx[0]] if len(idx) > 0 else np.nan) t_at_level = np.array(t_at_level) delta_t = np.diff(t_at_level) return delta_t, levels

4.3 高斯过程回归:小样本预测的稳妥起点

在只有几十个循环、特征维度又不高的情况下,复杂深度学习模型的收益其实很有限。高斯过程回归(GPR)是一个非常合适的基线:样本量小、非线性能拟合、还能给出预测的不确定性区间。

下面是一个基于scikit-learn的实现框架:

from sklearn.gaussian_process import GaussianProcessRegressor from sklearn.gaussian_process.kernels import ConstantKernel, RBF, WhiteKernel kernel = ConstantKernel(1.0) * RBF(length_scale=10.0) + WhiteKernel(noise_level=1.0) gpr = GaussianProcessRegressor(kernel=kernel, alpha=1e-6, normalize_y=True) gpr.fit(X_train, y_train) y_pred, y_std = gpr.predict(X_test, return_std=True)

输入X_train可以设计成前N个循环的等压升时间差特征,y_train是这些循环的容量值;训练完成后,用未来的时间点预测未来的容量,直到预测容量低于退役阈值,此时的循环序号就是RUL。评估指标推荐RMSE和MAPE,同时要画出预测曲线并带上置信区间。

这里我必须强调:单一电池上的表现好不叫好。一定要做跨电池验证,比如用B0006、B0007、B0018三块电池的数据训练,在B0005上测试。因为电池之间随机性很大,一个模型只在B0005上拟合出了衰减曲线形状,换一块电池可能就废了。跨电池的RUL预测,才是真正检验算法泛化能力的战场。

5. 跳出标准用法:四块电池的迁移学习与随机容量预测

5.1 随机容量预测:和RUL不同的一种任务设定

传统RUL预测要求模型按时间顺序外推,但实际BMS场景里,用户往往是在某个不确定的时刻询问:“这块电池现在还有多少容量?”这更像一个回归问题,而不是序列预测问题。

最近一些研究把这种设定叫做“随机容量预测”(Random Capacity Prediction)。具体做法:给定某个循环的充电曲线片段,不管它前面经历了多少个循环,直接回归预测这个循环的放电容量。这时候不需要建模完整的退化轨迹,只需要从充电曲线提取健康特征,然后做监督回归。

用NASA数据做这个任务时,可以把四块电池的所有循环混合在一起,每一行样本是“某个循环的等压升时间差特征 + 当前容量标签”。训练一个GPR或MLP,四块电池的数据一起用,效果往往比单块电池单独训练更好,因为模型见过了更多老化形态。

5.2 迁移学习:怎么划分源域和目标域

在四块电池构成的迁移学习实验里,有一个划分策略我比较推荐:用B0006、B0007、B0018作为源域,B0005作为目标域。原因是B0005的放电截止电压最高,退化最慢,数据分布和其他三块的差异最明显,能在目标域上做更严格的泛化检验。

迁移学习里有一个非常容易被忽视的细节:归一化参数只能用源域数据计算。很多人习惯把全部数据放在一起做标准化,再划分训练测试集,这在迁移场景里属于信息泄漏,会让指标虚高。正确做法是先从源域拟合归一化参数,再把这个参数应用在目标域上。

5.3 和CALCE、Oxford等其他公开数据集怎么配合

NASA数据集虽然经典,但四块电池的样本量远不足以支撑大规模深度学习实验,而且充放电策略比较单一,覆盖不了多倍率、多温度的实际工况。做研究时可以把CALCE、Oxford等高校发布的电池老化数据集一起纳入对比。不同数据集的循环策略、环境温度、电池型号都不一样,正好用来检验算法的工况泛化能力。

我个人的流程是:先在NASA数据上把特征提取、模型验证、指标评估这条pipeline跑通,再在自己的私有数据或补充数据集上做二次验证。这样调试成本最低,因为NASA数据社区资料多,你踩过的坑几乎都有前人踩过,排查起来方便。

最后分享一个我在实际项目中常用的习惯:拿到B0005.mat之后,先把充放电数据转成CSV或Parquet格式存一份,每一行是一个循环内的采样点,再加一列cycle标号。这样后续无论是用pandas分析还是分发给团队其他人,都比每次从嵌套mat里去取数方便得多。NASA这份数据集最大的价值不在于它有多大规模,而在于它把“电池老化”这个复杂过程用清晰、完整的方式记录下来了,配合正确的使用姿势,它足够支撑你完成从入门到进阶的绝大多数电池算法实验。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询