简介NASA锂电池充放电试验数据集包含B0045-B0048等编号电池的完整循环测试数据面向电池研究、BMS设计与机器学习应用场景可支持电池容量衰退分析、充放电策略优化及剩余寿命预测等任务。压缩包共65个文件约28.56MB以mat格式数据文件为核心同时包含README说明、Simulink模型slxc、tmw、C代码与头文件c/h、构建脚本rsp/bat/mk及xml等配套工程文件便于复现仿真与二次开发。目前已有515人学习下载。数据来自受控条件下的加速老化试验电压、电流、温度等参数随时间连续记录既适合新能源汽车与储能领域的科研人员建模分析也可用于高校电池管理课程的数据分析教学用户可直接载入MATLAB等工具进行特征提取与寿命预测实践还可为算法对比与模型验证提供标准数据基准。 做电池健康管理、寿命预测或者SOC/SOH估算的人迟早都会撞上NASA的锂电池试验数据集。这个数据集在圈子里几乎是“新手村必刷副本”网上搜“电池充放电数据集”十有八九会把它翻出来。但真正下载到手之后很多人会卡在第一步拿到一个zip压缩包不知道里面是什么结构不知道用什么工具解压解压出来的.mat文件也不知道怎么读更别提怎么把它处理成能喂给模型的数据集。这篇就把从zip到可训练数据集的完整链路拆开讲一遍。我这里的版本是常见的NASA PCoE锂电池试验数据压缩包里包含一组18650电芯在加速老化实验中的充放电记录。下面所有内容都是基于我自己实际跑过的流程包括踩过的坑。1. 拆开NASA锂电池数据集实验协议与文件结构1.1 这批电池到底做了什么实验NASA PCoEPrognostics Center of Excellence的这项实验最早由B. Saha和K. Goebel团队发布目的是为剩余使用寿命预测提供一个公开基准。实验对象是额定容量约2Ah的18650电芯没有用真实工况那种随机的充放电策略而是用一套简单但非常标准的循环协议做加速老化。每个循环分三段先以1.5A恒流充电到4.2V再转恒压充电直到电流降到20mA然后休息一段时间接着用不同的放电电流常见版本里主力放电电流是2A放到设定的截止电压放电结束之后插入一次电化学阻抗谱测量。这样一轮下来电池会经历完整的充电、放电、静置、阻抗测量四步。不同电池的放电截止电压有差异我记得B0005、B0006、B0007、B0018这批经典电池的截止电压设定就不完全一样下载的时候可以留意一下随包文档里的说明。反复跑这套循环直到电池容量衰减到额定容量的70%左右约1.4Ah才算实验结束。所以这个数据集本质上是“从新生到报废”的全生命周期记录。看到这里你应该意识到一个关键点这里面的电压、电流、温度、容量、阻抗都是带时间戳的连续序列不是汇总好的指标表。想直接当表格数据用也可以但会很亏。1.2 解压之后会看到什么文件压缩包解压后常见有两种形态一种是.mat文件每个文件对应一个电池B0005.mat、B0006.mat、B0018.mat等另一种是.txt文本文件每个文件同样对应一个电池列包括时间、电压、电流、温度、容量、阻抗等。两种形态内容基本等价文本版更容易快速用awk或者Python读一眼.mat版则保留了原始结构信息组织方式更接近MATLAB导出时的样子。需要提醒的是网上流传的NASA电池数据版本很多。Kaggle、Mendeley以及一些个人博客上都有镜像字段命名、电池数量、是否有扩展的充放电工况比如随机放电的B0029-B0056系列都有差异。我第一次下的时候没看说明结果文件名倒是都一样读出来的Capacity字段单位却跟预期不一致后面排查了半天才发现是版本问题。所以拿到压缩包后第一步不是急着写代码而是先解压、看文件列表、找readme。没有readme的话也要先打印mat文件的字段名再动手。2. zip下载与解压的实战问题2.1 下载阶段最隐蔽的坑文件损坏很多人一上来就用浏览器默认下载或者用迅雷这类多线程工具拉这个zip。文件不大还好一旦网络不稳定下回来的zip可能是个残缺品。解压时Windows的资源管理器可能直接弹“压缩文件已损坏”命令行则会报could not find eocd这种错。EOCD是ZIP格式中央目录结尾标记找不到这个标记基本可以断定文件没下完整。遇到这种情况我建议先不要怀疑压缩包密码或者工具问题第一步是校验文件完整性。先用ls -l看文件大小是否正确再去下载页面核对原始字节数。如果不一致直接重下。重下的时候用单线程下载工具会比较稳比如浏览器普通下载或wget这样能断点续传的方案。如果文件大小对得上但依然解压失败再用7-Zip打开压缩包试试——7-Zip对损坏zip的容错性比Windows自带解压要好有时候能直接拖出里面的文件。实测中我遇到过几次“资源管理器解不了7-Zip却能完整解出来”的情况值得优先尝试。2.2 解压时的编码与密码问题还有一类问题是文件名乱码。早期有些zip是用非UTF-8编码打包的Windows资源管理器解出来之后文件名全乱码比如“B0005.mat”变成一串问号或乱码字符。这种情况在Linux下用unzip解压基本不会遇到Windows下可以用7-Zip改一下文件名编码配置或者在解压前直接把zip重命名避免非ASCII路径干扰。包内文件名一般很简单乱码后手动改回来就行。要是遇到有密码的zip我的建议是直接回下载源找说明。公开数据集大部分不加密加密的基本是某些人二次打包加的密码通常会写在帖子或页面上。不要浪费时间在这种包上更不要折腾什么暴力破解工具公开数据集的授权协议本来就只覆盖研究用途破解别人加密包属于给自己找麻烦。2.3 解压后先做一次完整性检查解压完成后我习惯跑一遍python -c读所有.mat文件确认每个文件都能被正常load。这样能提前发现哪个电池文件在传输中损坏避免后面写训练代码到一半才发现某个文件读不了。具体做这步其实一行命令就够python -c import scipy.io as sio, glob; [sio.loadmat(f) for f in glob.glob(*.mat)]; print(all ok)如果输出all ok说明所有mat文件都能正常解析。此时压缩包的问题就彻底翻篇了接下来进入真正的“读数据”阶段。3. 读取.mat数据从结构体到可分析表格3.1 MATLAB结构体在Python里的样子用scipy.io的loadmat读NASA的.mat文件得到的不是DataFrame而是一层一层嵌套的numpy结构化数组。第一次接触的人很容易被绕晕。以B0005.mat为例loadmat之后拿到的是一个dict键是B0005对应的value是一个shape为(1,1)的ndarray取[0,0]之后里面才是这个电池的完整信息比如cycle字段。cycle本身也是个1xN的struct arrayN是总循环次数。每个元素有type字段取值是charge、discharge或impedance分别对应充电、放电、阻抗测量段还有一个data字段内部保存该阶段所有采样点。放电段里常见的字段包括Voltage_measured、Current_measured、Temperature_measured、Capacity、Time等。不同镜像版本字段名基本一致但有些会多个Current_load、Voltage_load之类的别名打印一下字段列表最靠谱。3.2 提取每条放电曲线的容量核心任务是提取每次放电循环的总容量用来画老化衰减曲线。容量这个字段在放电段的data里通常名字叫Capacity单位是Ah。我第一次跑的时候直接取data[Capacity][0][0]发现取出来的是一个数组的某个值位置需要自己确认。稳妥的做法是遍历整个data里的字段名打印后再定位。下面这个脚本是完整可用的遍历方式能按循环顺序打印出每一次放电的容量和采样点数import scipy.io as sio import numpy as np raw sio.loadmat(B0005.mat) battery raw[B0005][0, 0] cycles battery[cycle][0, 0] for i in range(cycles.shape[1]): c cycles[0, i] typ str(c[type][0]) if typ ! discharge: continue data c[data][0, 0] capacity data[Capacity][0][0] voltage data[Voltage_measured][0] current data[Current_measured][0] temp data[Temperature_measured][0] print(fcycle {i:03d} | capacity {capacity:.3f} Ah | fsamples {len(voltage)} | last V {voltage[-1]:.3f} V | favg T {temp.mean():.1f} C)跑完这一段你会看到容量从最初的接近2Ah逐步往下掉到最后只剩1.4Ah左右。这就是最直观的SOH标签来源。如果连这个脚本都报错那大概率是字段名不匹配把Capacity改成实际字段名即可。3.3 顺手把充放电曲线整理成DataFrame只拿总容量还不够训练模型时通常需要每条放电曲线的电压、电流、温度序列。建议一次性把结构体扁平化整理成“宽表”或者“长表”。宽表适合做SOC估计这类逐点建模任务长表适合做曲线级别的回归任务。下面是一个基础的长表转换逻辑import pandas as pd records [] for i in range(cycles.shape[1]): c cycles[0, i] typ str(c[type][0]) if typ ! discharge: continue data c[data][0, 0] n len(data[Voltage_measured][0]) for j in range(n): records.append({ battery: B0005, cycle: i, voltage: data[Voltage_measured][0][j], current: data[Current_measured][0][j], temperature: data[Temperature_measured][0][j], time: data[Time][0][j], }) df pd.DataFrame(records)注意这里直接取了原始采样的所有点没有做平滑和滤波。对于容量估计这类任务原始采样点一般够用但如果你要做电压差分分析最好先做一次中值滤波否则噪声会被放大。4. 构建训练集SOC、SOH、RUL三种建模思路与数据划分4.1 三种任务对应的标签构建方法很多人搜“yolov8训练自己的数据集”“nnunet训练自己的数据集”其实背后是一个通用问题拿到原始数据后怎么组织成模型能学的东西。电池数据不是图像数据不能直接套目标检测或分割的流程但思路是一样的——先定义清楚输入是什么、输出标签是什么。用NASA数据集可以构造三类常见任务SOC荷电状态估计输入是当前放电段的电压、电流、温度序列片段标签是当前时刻的SOC通常用容量比例近似即1 - 已放电容量/本次总放电容量。SOH健康状态预测输入可以是循环次数、内阻、某固定电压区间对应的放电时间等特征标签是当前循环的放电容量或容量保持率。RUL剩余寿命预测输入是前K次循环的容量序列或其他特征序列输出是距离寿命终止比如容量衰减到70%还剩下的循环次数。这三种任务的数据组织方式完全不同。SOC问题可以理解为序列回归通常把一个放电过程切成长度固定的窗口每个窗口给一个标签SOH问题更像表格回归一个循环一行样本RUL问题则是一个典型的时间序列预测必须按时间顺序切窗口不能随机打乱。4.2 数据划分最容易翻车的地方电池数据最大的坑是数据泄露。很多人在划分训练集和测试集时直接用train_test_split随机切结果模型在验证集上表现很好一到现场测试就崩。原因很简单同一个电池相邻循环的采样点高度相似随机切会导致训练集和验证集出现大量“近亲样本”模型学到的其实是记忆和插值不是泛化。正确做法是按电池分组划分或者至少按时间顺序划分。按电池分组是最稳的比如用B0005、B0006、B0018做训练留一部分完整电池做测试真实场景中模型遇到的“全新电池”才是它真正需要面对的情况。如果你只有一块电池的数据那也应该用前80%的循环做训练、后20%做测试让时间顺序模拟真实老化过程。下面这段是按电池分组划分的示例from sklearn.model_selection import GroupShuffleSplit X all_features y all_capacities groups battery_ids # 每条样本对应的电池编号 gss GroupShuffleSplit(n_splits1, test_size0.25, random_state42) train_idx, test_idx next(gss.split(X, y, groupsgroups)) X_train, X_test X.iloc[train_idx], X.iloc[test_idx] y_train, y_test y.iloc[train_idx], y.iloc[test_idx]另外做SOC估计时还要注意一个问题不要直接把整条放电曲线作为一条样本丢进去而是应该切窗口。切窗口时一定要防止窗口跨循环否则一个窗口里前半段在上一轮放电、后半段在下一轮充电标签就会错乱。我自己的习惯是先按cycle分好组再在组内滑动窗口。4.3 特征工程里值得保留的几个细节从原始数据到模型特征有几个特征几乎必用放电容量或容量保持率这是SOH任务最直接的标签也可以作为SOC任务里归一化的分母。恒流充电阶段的持续时间。电池老化后恒流充电阶段变短、恒压充电阶段变长这个特征是很好的老化指标。放电过程中的平均温度和温度峰值。锂离子电池内阻随老化增加相同放电电流下发热会更明显。放电末端电压下降速率。老电池在放电末期电压跌得更快这个斜率对RUL预测有一定帮助。我自己在跑NASA数据时还发现一个细节不同电池的初始容量不完全一致直接比较容量绝对值会有偏差。建议用容量保持率当前容量除以该电池首次放电容量代替绝对容量这样跨电池建模时特征尺度更统一。5. 自建电池充放电数据集的低成本方案5.1 没有NASA数据时可以自己搭一套采集设备公开数据集终究是别人做好的如果你想做特殊工况实验或者想验证算法对“自己电池”的适应性就得考虑自己采集数据。其实自建一套简单电池充放电数据采集平台没有想象中那么贵门槛主要在于实验周期和安全意识。最简单的方案是用可编程电子负载加上直流电源。充电用一台带恒流恒压模式的直流电源按CC-CV协议充到上限电压放电用可编程电子负载设置恒流放电和截止电压超过截止电压自动断开。温度采集用热电偶或NTC贴在电芯表面隔几秒记录一次。数据采集可以用Arduino加INA226这类电压电流监测模块也可以直接用带串口输出的电子负载和电源把数据用Python的pyserial实时写入文件。如果你只是想先跑通一个小实验验证流程可以再省一点用现成的充放电模块比如常见的锂电池充电保护板搭配一个固定阻值的功率电阻放电用万用表手动记录电压。但手动记录采样频率太低基本只适合做容量粗测想分析电压曲线细节还是得自动采集。5.2 自建实验必须注意的几个原则电池老化实验是慢速实验一块18650电芯连续循环天天跑也要几个星期才能看到明显衰减。时间成本高实验设计就更不能草率。同一批实验尽量用同一批次、同一型号的电池减少个体差异带来的噪声。每个实验都要写清楚环境温度、充电截止电流、放电截止电压、静置时间这些参数文本记录比记忆可靠得多。安全一定要放在第一位。18650电芯大电流放电会发热过放会损伤电池甚至引发安全隐患所有设备都必须有自动断电机制不要长时间无人值守。初次做实验建议从0.5C左右的小电流开始不要一上来就上2A。另外我想推荐一个互补方案公开数据集不要只盯NASA一家。CALCE马里兰大学先进寿命周期工程中心也有公开的电池老化数据工况设计和NASA不完全一样两边结合可以提高模型的泛化能力。自己做实验时也可以设计两组不同放电深度DOD的对照组这样采集到的数据能覆盖更宽的工况空间。5.3 我的个人建议回头来看处理NASA电池数据集最花时间的其实不是建模而是数据清洗和数据形态转换。很多人拿到zip后第一反应是找模型代码但我更建议先在数据上花一天时间画一画容量衰减曲线看看每个电池的温度特征手动检查几个循环的电压曲线是否健康。这些基本功比调参更能决定你最后模型的真实效果。另外实验记录这件事千万不要偷懒。NASA数据之所以成为行业基准一部分原因就是他们的记录足够完整——充放电协议写得清清楚楚连每个电池的终止条件都有说明。自己采集数据时也保持这种严谨数据才能被反复使用。本文还有配套的精品资源点击获取