电池还剩多少寿命?五个时间特征 + 高斯过程回归的 SOH 与 RUL 预测
用 NASA 的 B0005 电池数据,把充放电曲线里"耗掉的时间"变成五个特征,再交给 GPR。测试集 R² 0.995,预测起点后第 7 个循环跌破 70% 失效线。
先看结果。
NASA 的 B0005 电池,清洗后剩 166 个有效循环。前 116 个做训练,后 50 个做测试。GPR 在测试集上的 R² 是 0.99545,RMSE 是 0.00131。
SOH 用 0 到 1 的小数表示,这个 RMSE 换算成百分比是 0.13 个百分点。
按 70% 的失效阈值算,预测起点之后第 7 个循环跌破阈值。翻回真实值,第 7 个点也确实跌破了。
模型不新,数据也是公开的。有意思的地方在于输入:不是容量,也不是整条充放电曲线,而是五个"时间段"。
这些时间段,BMS 和充电桩本来就在记。

01 研究背景:容量测不到,时间一直在记
SOH 衡量电池还剩多少健康度,工程上通常定义为实际可用容量与额定容量的比值。RUL 是剩下还能用多久。
麻烦在于容量。要测准容量,得把电池充满再放空,或者做一次完整的放电积分。车在跑、储能在并网,没人会为了估健康度专门做一次满充满放。
在线 BMS 手里真正有的,是电压、电流、温度、时间这些过程量。
电池老了,这些过程量的形状会变。恒流充电段变短,恒压充电段变长,放电时电压掉得更快。
把"某段电压区间花了多久"抽出来,就得到一组可在线测量的健康特征。
这也是这套代码的起点。
02 主要功能:四个脚本,一条流水线
| 脚本 | 作用 | 主要产物 |
|---|---|---|
main01_Split_data.m |
读原始 B0005.mat,剔除 6 个重复或异常循环段,把 charge 与 discharge 拆开,用放电积分算 SOH 和 SOC |
B0005_charge_data.mat、B0005_discharge_data.mat |
main02_SOH.m |
批量读取 B0005、B0006、B0007、B0018,画四块电池的 SOH 衰减对比 | 四电池趋势图 |
main03_Feature.m |
画电压、电流、IC 曲线,提取五个时间特征,算 Pearson 相关系数,存特征矩阵 | B5_HF.mat,图 1 到图 8 |
main04_GPR.m |
归一化、按时间切分训练测试、训练 GPR、算七项指标、定位 RUL、画雷达图和罗盘图 | 指标表,图 9 到图 11 |
主数据是 NASA PCoE 的 18650 电池。额定容量 2 Ah,充电先 1.5 A 恒流到 4.2 V,再恒压到电流降到 20 mA,放电是 2 A 恒流到 2.7 V。
四块电池里,B0005 被拿来做完整的特征提取和建模,另外三块只用来看衰减趋势的差异。
03 技术路线:从原始 .mat 到一条寿命曲线
整条链路可以压成一行:
原始循环数据 → 拆充放电段 → 容量积分得 SOH → 提五个时间特征 → 归一化 → GPR 训练与预测 → 指标与 RUL
具体到每一步:
| 阶段 | 输入 | 关键操作 | 输出 |
|---|---|---|---|
| 数据清洗 | B0005.mat 的 cycle 结构体 |
去掉 6 个异常段,只保留采样点大于 100 的充电段 | 166 个充电循环、166 个放电循环 |
| 标签构造 | 放电段电压、电流、时间 | 找到首次低于 2.7 V 的位置,对电流积分 | 每个循环的 SOH |
| 特征构造 | 充电段、放电段的时间序列 | 按电压、电流阈值截取区间,算时间差 | 5 维特征矩阵 |
| 数据划分 | 166 行特征矩阵 | 前 70% 训练,后 30% 测试,不打乱 | 116 行训练、50 行测试 |
| 回归建模 | 归一化后的 5 维输入 | ARD 平方指数核,L-BFGS 优化超参 | SOH 预测值与方差 |
| 寿命判定 | 测试段预测序列 | 找第一个低于 0.7 的点 | RUL |
训练集和测试集按时间顺序切,不随机打乱。电池老化是时间序列,随机打乱会让相邻循环同时出现在训练和测试里,指标会虚高。
这一点比模型本身更重要。
04 公式与特征
4.1 SOH 怎么算
放电过程可以看成容量在往外倒。对电流积分,再除以额定容量:
SOH=QdisQnom×100%,Qdis=13600∫0tcut∣I(t)∣dt SOH=\frac{Q_{\text{dis}}}{Q_{\text{nom}}}\times 100\%,\qquad Q_{\text{dis}}=\frac{1}{3600}\int_{0}^{t_{\text{cut}}}\left|I(t)\right|\mathrm{d}t SOH=QnomQdis×100%,Qdis=36001∫0tcut∣I(t)∣dt
tcutt_{\text{cut}}tcut 是电压首次低于 2.7 V 的时刻,Qnom=2Q_{\text{nom}}=2Qnom=2 Ah。
B0005 的首循环 SOH 是 0.9232,最低到 0.6437,最后几个循环又回升到 0.6625。这里的 100% 指 2 Ah 额定容量,不是首循环容量,所以曲线从 0.92 起步,不是从 1 起步。
曲线不单调,末端还有容量回升。GPR 能跟上这种局部波动,靠的是同一循环内的五个特征在同步变化。
这个细节会影响阈值。0.7 的失效线对应 1.4 Ah,而不是"首循环容量的 70%"。
4.2 IC 曲线:用来看,不用来喂模型
代码里还画了增量容量曲线。先对电流积分得到电量,再对电压求差分:
Q(t)=13600∫0tI(τ) dτ,dQdV≈Qk+1−QkVk+1−Vk Q(t)=\frac{1}{3600}\int_0^t I(\tau)\,\mathrm{d}\tau,\qquad \frac{\mathrm{d}Q}{\mathrm{d}V}\approx\frac{Q_{k+1}-Q_k}{V_{k+1}-V_k} Q(t)=36001∫0tI(τ)dτ,dVdQ≈Vk+1−VkQk+1−Qk
电压按 0.01 V 重采样,差分步长取 1 个点。原始差分噪声大,后面接了一维卡尔曼滤波:
x^k−=x^k−1,Pk−=Pk−1+q,Kk=Pk−Pk−+r \hat{x}k^-=\hat{x}{k-1},\quad P_k^-=P_{k-1}+q,\quad K_k=\frac{P_k^-}{P_k^-+r} x^k−=x^k−1,Pk−=Pk−1+q,Kk=Pk−+rPk−
x^k=x^k−+Kk(zk−x^k−),Pk=(1−Kk)Pk− \hat{x}_k=\hat{x}_k^-+K_k\left(z_k-\hat{x}_k^-\right),\quad P_k=(1-K_k)P_k^- x^k=x^k−+Kk(zk−x^k−),Pk=(1−Kk)Pk−
过程噪声 q=0.01q=0.01q=0.01,测量噪声 r=0.05r=0.05r=0.05,初始协方差 P0=0.001P_0=0.001P0=0.001。

IC 曲线能看出峰位的移动和峰高的衰减,这是老化在电化学层面的表现。但它只用于观察和佐证,真正的模型输入还是五个时间特征。
4.3 五个时间特征
| 特征 | 代码里的定义 | 物理含义 |
|---|---|---|
| CCCT | 充电开始到电压首次超过 4.2 V 的时间 | 恒流充电段长度 |
| CCDT | 放电段中,电流低于 -1.9 A 的持续时间 | 恒流放电窗口长度 |
| CVCT | 电压超过 4.2 V 到充电结束的时间 | 恒压充电段长度 |
| CVRT | 充电时电压从 3.8 V 升到 4.1 V 的时间 | 充电中段电压上升速度 |
| CVDT | 放电时电压从 4.0 V 降到 3.6 V 的时间 | 放电中段电压下降速度 |
五个特征随循环的变化趋势很一致。CCCT 从 3242 s 降到 1582 s,CVRT 从 2354 s 降到 1018 s。CVCT 反向,从 7274 s 升到 8630 s,中间最高到过 9240 s。
原因不复杂。活性物质少了,恒流段更快到达截止电压;内阻大了,恒压段要花更长时间才能把电充满。


4.4 相关性:谁最像 SOH
用 Pearson 系数衡量线性相关:
r=∑i=1n(xi−xˉ)(yi−yˉ)∑i=1n(xi−xˉ)2∑i=1n(yi−yˉ)2 r=\frac{\sum_{i=1}^{n}(x_i-\bar{x})(y_i-\bar{y})} {\sqrt{\sum_{i=1}^{n}(x_i-\bar{x})^2}\sqrt{\sum_{i=1}^{n}(y_i-\bar{y})^2}} r=∑i=1n(xi−xˉ)2 ∑i=1n(yi−yˉ)2 ∑i=1n(xi−xˉ)(yi−yˉ)
B0005 上的结果:
| 特征 | 与 SOH 的 Pearson 系数 |
|---|---|
| CCCT | 0.99798 |
| CCDT | 0.99999 |
| CVCT | -0.91354 |
| CVRT | 0.99712 |
| CVDT | 0.99889 |
CVCT 的符号是负的,因为它随老化变长,而 SOH 随老化变短。其余四个都跟 SOH 同向。
CCDT 的 0.99999 需要单独说一句。恒流放电时,时间乘上 2 A 再除 3600,基本就是放电容量。它和 SOH 的高相关有算术上的必然性,不算模型的功劳。
真正有信息量的是充电侧那三个特征。它们和容量不是同一个量,却依然能跟踪老化。
4.5 共线性
五个特征彼此也高度相关。

对 GPR 来说,共线性不会让它失效,核矩阵里有噪声项兜底,通常仍可求逆。但 ARD 给每个维度单独的长度尺度,特征高度相关时,这些长度尺度会变得难以解释。
别把 ARD 的长度尺度直接当成特征重要性。它更像是一组让边际似然最大化的数值,不是因果解释。
05 GPR 原理与算法步骤
高斯过程回归做的事,是把函数本身当成随机变量:
f(x)∼GP(m(x),k(x,x′)) f(\mathbf{x})\sim\mathcal{GP}\left(m(\mathbf{x}),k(\mathbf{x},\mathbf{x}')\right) f(x)∼GP(m(x),k(x,x′))
代码用的是 ARD 平方指数核:
k(x,x′)=σf2exp(−12∑d=15(xd−xd′)2ℓd2) k(\mathbf{x},\mathbf{x}')=\sigma_f^2 \exp\left(-\frac{1}{2}\sum_{d=1}^{5}\frac{(x_d-x_d')^2}{\ell_d^2}\right) k(x,x′)=σf2exp(−21d=1∑5ℓd2(xd−xd′)2)
五个输入维度各有自己的长度尺度 ℓd\ell_dℓd。观测带噪声:
y=f(x)+ε,ε∼N(0,σn2) y=f(\mathbf{x})+\varepsilon,\qquad \varepsilon\sim\mathcal{N}(0,\sigma_n^2) y=f(x)+ε,ε∼N(0,σn2)
给定训练集后,新样本的预测均值和方差是:
μ∗=k∗⊤(K+σn2I)−1y \mu_*=\mathbf{k}_*^{\top}\left(\mathbf{K}+\sigma_n^2\mathbf{I}\right)^{-1}\mathbf{y} μ∗=k∗⊤(K+σn2I)−1y
σ∗2=k(x∗,x∗)−k∗⊤(K+σn2I)−1k∗ \sigma_*^2=k(\mathbf{x}*,\mathbf{x}*)- \mathbf{k}*^{\top}\left(\mathbf{K}+\sigma_n^2\mathbf{I}\right)^{-1}\mathbf{k}* σ∗2=k(x∗,x∗)−k∗⊤(K+σn2I)−1k∗
超参数不靠交叉验证网格搜,而是最大化对数边际似然:
logp(y∣X,θ)=−12y⊤(K+σn2I)−1y−12log∣K+σn2I∣−n2log2π \log p(\mathbf{y}\mid\mathbf{X},\theta)= -\frac{1}{2}\mathbf{y}^{\top}\left(\mathbf{K}+\sigma_n^2\mathbf{I}\right)^{-1}\mathbf{y} -\frac{1}{2}\log\left|\mathbf{K}+\sigma_n^2\mathbf{I}\right| -\frac{n}{2}\log 2\pi logp(y∣X,θ)=−21y⊤(K+σn2I)−1y−21log K+σn2I −2nlog2π
代码里的算法步骤是:
- 用训练集的 min 和 max 把输入和输出都压到 0,1,测试集复用同一组参数。
- 选
ardsquaredexponential核,初始长度尺度 0.6,初始信号标准差 0.7,初始噪声标准差 30。 - 用 L-BFGS 最大化对数边际似然,同时估计核参数与噪声。
- 对训练集和测试集分别求后验均值,再反归一化回 SOH。
- 在测试段预测序列里找第一个低于 0.7 的位置,作为 RUL。
为什么用 GPR,而不是神经网络。训练样本只有 116 个,深度模型很难喂饱;GPR 在小样本上更稳,而且天然给出每个预测点的方差。
准确值告诉你"大概是多少",方差告诉你"这句话有多可信"。
06 参数设定
| 项目 | 取值 | 说明 |
|---|---|---|
| 数据 | NASA PCoE B0005 | 18650,额定 2 Ah |
| 有效样本 | 166 | 剔除异常段后的充放电循环数 |
| 训练/测试 | 116 / 50 | 按时间顺序 70% / 30% 切分 |
| 归一化 | mapminmax 到 0,1 | 测试集复用训练集的 min、max |
| 输入维度 | 5 | CCCT、CCDT、CVCT、CVRT、CVDT |
| 输出 | SOH | 范围 0.6437 到 0.9259 |
| 核函数 | ardsquaredexponential |
每维独立长度尺度 |
| 优化器 | L-BFGS | 最大化对数边际似然 |
| 核参数初值 | σl=0.6\sigma_l=0.6σl=0.6(5 维),σf=0.7\sigma_f=0.7σf=0.7 | 调参后的优化起点 |
| 噪声初值 | σn=30\sigma_n=30σn=30 | 只是起点,最终值由优化器估计 |
| 失效阈值 | 0.7 | 对应 1.4 Ah |
| IC 重采样 | 0.01 V | 电压等间隔,便于差分 |
| IC 差分步长 | 1 个点 | 兼顾平滑与峰形 |
| 卡尔曼参数 | q=0.01q=0.01q=0.01,r=0.05r=0.05r=0.05,P0=0.001P_0=0.001P0=0.001 | 一维去噪 |
| 随机种子 | rng(0) |
固定随机性 |
有两点容易误读。
噪声初值 30 看起来大得离谱。归一化后的 SOH 残差尺度只有 0.1 左右,30 只是个宽松的起点。从训练集 RMSE 3.7×10⁻⁴ 看,优化器最后把噪声压得很低。
fitrgp 默认还会对输入做标准化,手写的 mapminmax 有部分重复。但统一到 0,1 后,核参数初值更好设,训练也更稳,多这一步不亏。
07 结果











| 指标 | 训练集 | 测试集 |
|---|---|---|
| MAE | 2.41×10⁻⁴ | 1.16×10⁻³ |
| MBE | 3.11×10⁻¹³ | 1.16×10⁻³ |
| MSE | 1.38×10⁻⁷ | 1.73×10⁻⁶ |
| RMSE | 3.72×10⁻⁴ | 1.31×10⁻³ |
| R² | 0.99997 | 0.99545 |
| RPD | 190.09 | 31.28 |
| MAPE | 2.76×10⁻⁴ | 1.75×10⁻³ |
RMSE 0.00131 换成百分比是 0.131 个百分点。MAPE 0.175%。RPD 31.28,远高于工程上常用的 3 这个门槛。
测试集的 MBE 和 MAE 数值完全相等,都是 0.00116。说明测试段的残差全是同号,模型整体略微高估。训练集 MBE 接近 0,偏差只出现在测试段。
外推带来的小偏置,在这类时序切分里很常见。
RUL 的算法很直接:
RUL=min{k≥1∣y^test(k)<0.7} RUL=\min\left\{k\ge 1 \mid \hat{y}_{\text{test}}(k)<0.7\right\} RUL=min{k≥1∣y^test(k)<0.7}
测试段从第 117 个循环开始,起点 SOH 是 0.7038。预测序列第 7 个点跌破 0.7,于是输出 7 个循环。
真实值也在第 7 个点跌破,数值 0.69835。这一次,预测与真实完全对齐。
08 这些数字该怎么读
指标很漂亮,但有几件事必须说清楚,否则容易把结论用错地方。
第一,这是单块电池、同一条老化轨迹上的切分。 训练和测试来自 B0005 的同一段衰减过程,模型更像在做"内插加短外推"。换一块电池、换一种充电策略,R² 大概率会掉。代码里另外三块电池只画了趋势,没有参与跨电池验证。
第二,五个特征和 SOH 绑得太紧。 CCDT 几乎是容量的另一种写法,CCCT、CVRT 也都是强代理。模型学到的更多是"这条曲线长什么样",而不是"老化机理是什么"。想验证特征本身的价值,得做消融,比如只留充电侧三个特征,看精度掉多少。
第三,RUL 等于 7 的说服力有限。 预测起点已经贴着 0.7,SOH 只有 0.7038,本来就没剩几个循环。而且测试窗口已经被观测,这是一次"阈值穿越定位",不是从早期循环往后递推的多步预测。真正难的场景,是在第 20 个循环就预测还剩多少寿命。
第四,时间特征依赖充电协议。 CVCT 尤其敏感,它取决于恒压截止电流。充电桩提前结束,或者换了快充策略,这个特征会失真。
第五,温度没进模型。 NASA 数据里有温度,但五个特征全是时间量。低温下充电变慢,时间特征会整体漂移。跨季节、跨地域部署时,这是一个明显的缺口。
第六,MAPE 是相对误差,SOH 基数在 0.7 附近时,百分比看起来会比绝对误差更小。 报告精度时,优先说"误差 0.13 个百分点",别只甩一个百分比。
09 运行环境
- MATLAB R2021a 及以上。
exportgraphics需要 R2020a,tiledlayout需要 R2019b,双引号字符串需要 R2017a。 - Statistics and Machine Learning Toolbox,用于
fitrgp、plotregression、ploterrhist。 - 雷达图依赖本地的
radarChart.m,不需要额外工具箱。 - Windows、macOS、Linux 都可以跑。
- 数据放在
data/,图片输出到figures/,脚本按main01 → main02 → main03 → main04的顺序执行。 - 计算量很小。166 个样本的精确 GPR,普通笔记本几秒到十几秒就能跑完,不需要 GPU。
10 应用场景
车端与云端 BMS。 充电时记录恒流段、恒压段的时间,配合历史数据估 SOH,不需要额外做满充满放。
二手车与质保。 SOH 曲线加上 GPR 的置信区间,比一个孤立的"健康度 92%"更能支撑残值评估。
储能电站。 成组电池的一致性分析,先看单体的时间特征有没有异常漂移,再决定是否检修。
换电与梯次利用。 分选时用它快速判断电池还能不能进下一梯队,避免只凭电压判断。
充电桩。 每次充电顺手完成一次健康体检,把结果回传给车主或运营方。
无人值守场景。 卫星、基站备电这类不方便人工检测的设备,时间特征可以在线取,GPR 的方差还能给出报警阈值。
结尾
这套流程真正值钱的地方,不是把 R² 刷到 0.995。
是 GPR 本来就有能力给每个预测点配一个方差。
这套代码目前只取了后验均值,方差还没画出来。工程上,这一块恰恰不能省。一个只会给点预测的模型,很难被信任;一个知道自己哪里不确定的模型,至少能在该报警的时候报警。
下一步可以做三件事。拿 B0006、B0007、B0018 做跨电池验证,看看换一块电池后精度掉多少;把温度加进特征,观察时间特征的漂移;把预测值递回模型,做真正的多步 RUL,而不是在测试段里找阈值穿越点。
再往前走一步,就是把 predict 的第二个输出取出来,把 95% 置信区间画到 SOH 曲线上。
SOH 估计解决的是"现在怎么样",RUL 解决的是"还能撑多久"。前者靠特征,后者靠外推。
外推这部分,才是真正难的地方。
数据来源:NASA Ames Prognostics Center of Excellence 电池数据集。本文的 MATLAB 实现与图表均来自本地复现,指标可在同一数据与同一随机种子下复现。