在 PyBaMM 里打开 SEI 生长和析锂只需要两个选项字符串,仿真也总会给出一条衰减曲线。决定这条曲线形状的,是一组从来不会报错的选择:流程要花多长时间,选哪个 SEI 模型,速率里用的是什么温度,允不允许孔隙被填满,以及析锂模型在静置时怎么表现。本文用 PyBaMM 26.5.0 逐一实测这些选择,主要用 OKane2022(LG M50)参数集——它是唯一一个同时带有 SEI、析锂、颗粒开裂和应力驱动的活性材料损失参数的内置全电池参数集,不过仍有四种 SEI 变体需要它没有的参数(第二节)。它的姊妹篇PyBaMM 的容量数字是什么意思讲的是怎么读结果。
PyBaMM 电池建模系列 · 静默错误实测(第 5 / 7 篇):上一篇 PyBaMM 的容量衰减到底在量什么:80% capacity、Capacity [A.h] 与 Loss of capacity 实测 · 下一篇 PyBaMM 求解器收敛失败:先分清数值问题还是物理问题 · 专题页:数据管线 4 篇 + 静默错误实测 7 篇 · RSS 订阅。
一、SEI 是一个时钟
O’Kane 等用的是溶剂扩散限制的 SEI 模型("SEI": "solvent-diffusion limited"),PyBaMM 的耦合退化示例给 OKane2022 配的也是这个选项。它的生长速率是 −D_sol · c_sol · F / L_sei 乘以一个 Arrhenius 因子(sei_growth.py,第 185–187 行和第 216–220 行):它只取决于 SEI 厚度和温度,与其他任何量都无关——与电流无关,与电极电位无关,与荷电状态也无关。由此有三个推论。第一个在 PyBaMM 的论坛上多次被当作疑似 bug 提出;另外两个出自同一个模型。
充电越快,每个循环的 SEI 越少
1C 放电、充电倍率各不相同的 100 个循环(SPM,只开 SEI):
| 充电倍率 | 仿真时长 | SEI 消耗的锂 |
|---|---|---|
| C/3 | 18.1 天 | 0.00926 A·h |
| 1C | 10.9 天 | 0.00656 A·h |
| 2C | 9.6 天 | 0.00598 A·h(−35%) |
每个循环的 SEI 量只是跟着循环耗时走。加上部分可逆析锂后趋势会反过来,不过在 25 °C 下很弱:在放电后读取,SPM 中 C/3 / 1C / 2C 的 LLI 分别是 0.200 / 0.202 / 0.215%(DFN 中是 0.198 / 0.204 / 0.232%),只开 SEI 时则是 0.122 / 0.086 / 0.079%,析锂占其中的 39–64%。在循环末尾(充电之后)读取,同样这几次运行报告的是 0.39–0.47%,因为其中约一半是可逆析出的锂——见姊妹篇的读取时刻一节。
静置改变的是能装下多少个循环,而不是电池何时寿终
DFN,只开 SEI(不开析锂),SEI 溶剂扩散系数 ×300,好让一次可行的运行能跑到寿命终点,孔隙堵塞打开,1C 放电 / C/3 恒流恒压:
| 每半个循环后的静置 | 实测 1C 容量降到自身第 2 个循环的 90% | 跌破同一个 4.376 A·h 的天数 |
|---|---|---|
| 无 | 第 382 个循环,第 64.9 天 | 64.9 |
| 10 小时 | 第 72 个循环,第 70.4 天 | 65.0 |
按同一个绝对阈值,两种安排在同一天跌破,它们的容量–时间曲线在 68 天里相差不到 0.001 A·h。(中间一列 5.5 天的差距是参照点造成的假象:有静置那次运行的第 2 个循环晚了将近一天,所以它的 90% 阈值更低。)静置安排让到寿命终点的循环数相差 5.3 倍,日历日期却完全不变。为了省算力而缩短或去掉静置的研究,改变的是它得出的循环数,而不只是运行时间。
储存时的荷电状态不可能有影响
速率里没有电位项,所以在 10%、50% 和 100% SOC 下储存 1000 小时,SPM 和 DFN(严格容差下)给出的 SEI 都是同样的 0.0158801 A·h,与闭式解 L² = L₀² + 2·V̄·D_sol·c_sol·t 在七位有效数字上一致。这是模型本身的恒等式,而不是关于电池的测量。如果需要随 SOC 变化的日历老化,或者充电倍率对 SEI 的影响,就需要一个依赖电位的模型——默认交换电流下的 “reaction limited” 在 100 小时里,100% SOC 长出的 SEI 是 10% SOC 的 149 倍——还需要两个或更多 SOC 下的数据来标定它(第二节)。
补充说明:一个静默吃掉日历时间的 start_time bug。要模拟”每天一个循环”,就给每个循环的第一步设一个 start_time,PyBaMM 会用静置把中间的空当补上。在 26.5 里,只要同一个步骤在实验中任何位置出现不止一次,这个机制就会失效。Experiment 按 repr 给步骤去重——repr 包括文本,以及可能带有的标签、描述和 start_time(experiment.py,第 79 行)——然后把每个步骤的时间安排写到这些共享对象上(第 262–276 行),于是每一次重复都继承它第一次出现时的安排,用来补空当的静置根本不会发生。每个循环有两个 "Rest for 5 minutes" 时,它静默失败:五个”每天一次”的循环首尾相接,21.7 小时就跑完了,而不是 100.3 小时,SEI 只有应有值的 1/3.8(0.00085 对 0.00320 A·h),日志里什么也没有。每个循环只有一个静置时,运行则在两个循环后停下,报出 ERROR “Step time must be >0″;第一种写法跑十个循环时,它提前结束,只留下一条有误导性的 “default duration was reached” 警告。给每个步骤打上按循环区分的标签,pybamm.step.string(text, tags=[f"c{i}s{j}"]),就能完全恢复时间安排;用同样的参数新建步骤对象则不行。PyBaMM 自己针对带 start_time 的重复步骤写的单元测试,用的恰恰是这种会失败的写法,而且能通过,因为它数的是步骤,而不是仿真时间。我们已于 2026 年 9 月 27 日向上游提交 issue #5809;修复已作为 PR #5817 提交,仍在审核中(截至 2026 年 10 月 4 日尚未合并)。
二、SEI 速率常数是占位值
OKane2022 的 SEI 速率常数——交换电流、溶剂扩散系数和溶剂浓度、电子电导率、间隙扩散系数、EC 速率常数和 EC 扩散系数——与 Chen2020 的通用示例值完全相同,也和其他大多数内置参数集相同。只有活化能(38 kJ/mol,而不是 0)和锂与 SEI 的比值(1,而不是 2)不一样。O’Kane 等的论文只用了溶剂扩散模型,把 D_sol = 2.5 × 10⁻²² m²/s 称为”PyBaMM 的默认值”,并把它从 2.5 × 10⁻²² 变到 1.25 × 10⁻²⁰ m²/s 作为敏感性研究,而没有拟合它。(参数集那篇对 Chen2020、Marquis2019、Mohtat2020 和 Ai2020 指出过同样的问题;它对 OKane2022 同样成立。)
所以切换 SEI 选项并不是在几个拟合过的模型之间切换,而是在几组大小毫不相干的通用常数之间切换。同一个电池、同一个流程,只改 "SEI" 选项(DFN,孔隙堵塞打开,1C / C/3 恒流恒压,25 °C;默认网格和容差,其中 “reaction limited” 和 “ec reaction limited” 两行也在更细的网格上核对过):
| SEI 选项 | 300 个循环后的 LLI |
|---|---|
| “reaction limited” | 2.99% |
| “solvent-diffusion limited”(O’Kane 的选择) | 0.25% |
| “electron-migration limited” | 0.13% |
| “interstitial-diffusion limited” | 0.0067% |
| “ec reaction limited” | 1C 容量在第 16 个循环降到 80% 以下(LLI 7.4%);之后的步骤被跳过,没有任何提示 |
| “constant” | 0——它的意思是厚度恒定,而不是速率恒定 |
能跑的几个选项之间相差约 450 倍,还有一个十六个循环就把电池弄死。孔隙堵塞关闭时(默认),SPM 里的 “ec reaction limited” 则报告 1000 个循环后 LLI 为 48%,这需要 3.9 µm 的 SEI,而孔隙在 0.65 µm 时就已经满了。另外四个选项——两个 “(asymmetric)” 变体、”tunnelling limited” 和 “VonKolzenberg2020″——会以 KeyError 停下,报出一个 OKane2022 没有定义的参数。这是好的那种失败。
标定并不能让这个选择消失
要让每个模型都在第 100 个循环给出同样的 1.00% LLI(SPM,已收敛的容差,孔隙堵塞打开),各自唯一的那个速率常数需要分别缩放 ×1.06(SEI 交换电流)、×38(溶剂扩散系数)、×108(电子电导率)、×3990(间隙扩散系数)、×3.6 × 10⁻⁴(EC 速率常数)或 ×2.9 × 10⁻³(EC 扩散系数)。这之后,各模型在第 100 个循环按构造是一致的,但到第 300 个循环会散开到 1.6 倍,到第 500 个循环是 1.9 倍:扩散类模型大致按 √t 增长,反应类模型大致线性增长。早期的一个数据点没法在它们之间做出选择。
DFN 还会带来 SPM 显示不出来的东西。标定后的反应限制模型放进 DFN 里跑,在第 526–527 个循环还能放出第 2 个循环容量的 88%,再过一个循环就只剩 4%,此时 LLI 只有 5.6%,原因是 SEI 在靠近隔膜处长得更快(局部 641–647 nm,平均 453–457 nm),先把那里的孔隙填满了。日志里什么也没有。同样参数的 SPM 一直跑到第 1000 个循环,报告 7.7% 的 LLI,但那时它的 SEI 已经填满了 96% 的孔隙,负极电解液浓度是初始的 26 倍(第七节):它描述的也不是一个电池。
三、温度:只有一个 Arrhenius 因子,而且它几乎处处为零
所有 SEI 模型共用同一个 Arrhenius 因子 exp(E_sei/R · (1/T_ref − 1/T)),而每个 SEI 速率常数都只是一个普通标量。"SEI growth activation energy [J.mol-1]" 在所有带 SEI 参数的内置参数集里都是 0,只有 OKane2022 例外(还有它的石墨/SiOx 半电池变体,两者都是 38 kJ/mol)。这意味着什么,取决于模型(SPM,100 个循环的 1C 放电和 C/2 恒流恒压,环境温度和初始温度都设了):
- 溶剂扩散 SEI 变得与温度无关:在相同的经过时间下,Chen2020、Marquis2019、Mohtat2020、Ai2020 和 Ecker2015 中 0、25 和 45 °C 的差别都小于 0.02%。
- 反应限制 SEI 越冷长得越快。0 °C 下 SEI 消耗的锂是 25 °C 值的 1.67 倍(Ai2020)、2.48 倍(Marquis2019)、2.70 倍(Mohtat2020)、4.44 倍(Chen2020)和 8.56 倍(Ecker2015),45 °C 下则是 0.47–0.71 倍。就第 2 个循环的单循环速率而言,指数里显式的 F/RT 在 0 °C 下让速率乘上 1.7–2.1,低温时更低的负极电位再乘上 1.0–6.4(Ecker2015 合计 13.5 倍;上面 100 个循环的比值比这些首循环因子小)。
- OKane2022 的 38 kJ/mol 让它的溶剂扩散 SEI 表现符合预期(0 °C 下 0.38 倍,45 °C 下 1.83 倍),但同样活化能下的反应限制 SEI 呈 U 形:0 °C 下 1.18 倍,45 °C 下 1.16 倍,所以在测试的三个温度里 25 °C 最低。
这就是用户报告的”电池越热、退化越少”的结果。用 Chen2020(活化能为 0)和反应限制 SEI,把 SPM 从 25 °C 等温切换到集总热模型(h = 10 W/m²·K,电池平均温度 28.8 °C),100 个循环的 SEI 锂降低 10%(67.9 → 60.9 mAh)。用 OKane2022 的 38 kJ/mol,同样的切换让反应限制 SEI 变化 +0.3%。
析锂动力学不理会温度
在 OKane2022(以及使用同一组函数的 Ecker2015)里,析锂和溶出(剥离)的交换电流分别是 F·k·c_e 和 F·k·c_Li。温度参数被接收,却从未被使用。于是低温析锂只来自 Butler–Volmer 指数里的 1/T,以及其他动力学和传输过程的变慢。在 0 °C 下加上活化能会有多大影响(等温 DFN,从放空状态进行一次 2C 恒流恒压充电):
| 析锂和溶出的活化能 | 析出锂的峰值 |
|---|---|
| 无(内置原样) | 173 mAh |
| 20 kJ/mol | 110 mAh |
| 35 kJ/mol | 79 mAh |
| 50 kJ/mol | 56 mAh |
在 0 °C 下以 2C 充电循环 20 次,35 kJ/mol 把不可逆锂损失从 19.2 降到 11.6 mAh(−39%)。这不是一律的减少:表中那一次 2C 充电之后再静置 1 小时,仍处于析出状态的锂从 5.7 升到 20.4 mAh,因为溶出也变慢了。这些活化能只是示意;OKane2022 一个都没带,在你选定一个之前,所有零下的析锂结果描述的都是一套不知道温度的动力学。
等温还是集总,是一种选择,而不是一种修正
OKane2022 DFN,带 SEI、部分可逆析锂和孔隙堵塞,环境温度 25 °C,1C 放电 / 2C 恒流恒压。集总模型里的电池在 h = 10 W/m²·K 时平均 37.8 °C(峰值 54.6 °C),在 h = 30 时平均 29.3 °C。不可逆锂损失(SEI + 死锂,放电后读取):
| 循环 | 等温 | 集总,h = 10 W/m²·K | 集总,h = 30 W/m²·K |
|---|---|---|---|
| 100 | 17.65 mAh | 12.33 mAh(等温 +43%) | 14.20 mAh(+24%) |
| 500 | 50.2 mAh | 33.5 mAh(+50%) | 39.8 mAh(+26%) |
相对差距趋于平稳(h = 10 时,第 100 个循环为 1.43 倍,第 500 个循环为 1.50 倍),而不是越滚越大,因为 OKane2022 的死锂生成速率按 L₀/L 缩放,会像 SEI 一样放慢。机理构成也不一样:第 500 个循环时,等温运行有 31.8 mAh 死锂和 18.4 mAh SEI;h = 10 的运行则分别是 8.5 和 25.0。OKane2022 的退化参数没有用老化数据拟合过,O’Kane 等也没有加入热模型,而是保持温度恒定。两种边界条件都没有针对这些参数验证过,所以这里量的是这个选择本身,而不是某个选项的错误。热模型那篇讲了为什么换热系数值得像任何退化参数一样认真对待。
四、孔隙堵塞、拐点与网格
选项文档把 "SEI porosity change" 和 "lithium plating porosity change" 列为两个开关。代码里只有一个:只要其中任何一个是 "true",PyBaMM 就装上同一个孔隙率模型,把 SEI、析出的锂和死锂以及裂纹上的 SEI 一并扣除(base_lithium_ion_model.py,第 457–472 行)。只开其中一个、只开另一个或者两个都开,运行结果逐位相同。
拐点是一种状态,而不是一个循环数
孔隙堵塞打开时,OKane2022 的 SEI + 析锂衰减会在 SEI 填满初始负极孔隙体积的约 80–83% 时崩塌:每次充电时,析出的锂把靠近隔膜处剩下的孔隙封死。按内置几何,这对应 0.49 A·h 的 SEI 锂,不论 SEI 溶剂扩散系数乘的是 1000 还是 10,000;把单位 SEI 体积容纳的锂翻倍(每个 SEI 分子两个锂而不是一个,于是同样的孔隙能容纳两倍的 SEI 锂),它就移到 0.99–1.02 A·h。按内置的 SEI 速率,1000 个循环里 SEI 只带来约 0.5% 的 LLI,远低于这个阈值;O’Kane 等报告的拐点只出现在他们开裂速率为 30–50 倍的算例里。在他们开裂速率 50 倍的算例中(1C 放电 / 0.3C 恒流恒压至 C/100),从 x_n = 20 一直到隔膜处 0.067 µm 网格单元的每一种网格上,1C 容量都在第 615 ± 2 个循环降到 80%;x_n = 10 晚了 2%。SEI 驱动的堵塞在 PyBaMM 默认网格上就已收敛,25 °C 下 SEI + 析锂的拐点也是一样(默认网格上是第 145 个循环,所有更细的网格上是第 142–143 个)。
低温析锂堵塞则不收敛
只看一个工况——DFN,OKane2022 及其与温度无关的析锂动力学,SEI + 部分可逆析锂,孔隙堵塞打开,−10 °C 等温,从放空状态 2C 恒流恒压充电,静置 1 小时,1C 放电:
| 隔膜处负极网格单元的宽度 | 第 1 次放电 | 第 5 次放电 |
|---|---|---|
| 4.26 µm(默认,20 个单元) | 3.12 A·h | 3.06 A·h |
| 1.07 µm(80 个单元) | 0.75 A·h | 3.09 A·h |
| 0.27 µm(320 个单元) | 0.62 A·h | 1.33 A·h |
| 0.067 µm(渐变网格) | 0.59 A·h | 1.22 A·h |
| 0.008 µm(渐变网格) | 0.59 A·h | 1.00 A·h |
| 孔隙堵塞关闭,任意网格 | 3.12–3.15 A·h | 3.07–3.09 A·h |
| 堵塞打开,析锂 Arrhenius 35 kJ/mol,20 对 640 个单元 | 3.154 对 3.178 A·h | — |
在 4.2 V 恒压阶段,可逆析出的锂填满紧挨隔膜的那个网格单元的孔隙;恒压电流在 9–12 分钟后就降到 C/20,而不是约 186 分钟,充电停在 1.2–1.4 A·h。这层阻塞层有多厚,取决于网格单元有多厚,所以只有当那个单元薄到 0.07 µm 或更薄——比颗粒半径小两个数量级——第一次放电才收敛,之后的循环则根本不收敛。把求解器容差收紧 100 倍,结果毫无变化。默认网格把第一次放电高估了 5.3 倍,没有警告,正常终止。关掉堵塞,或者给析锂动力学加上温度依赖(最后一行),问题就消失了。
网格建议:报告隔膜处负极网格单元的宽度,而不是单元个数。pybamm.Exponential1DSubMesh 取 side="right"、40 个或更多单元时,能在 0.7% 以内复现隔膜处单元相同的均匀网格(20 个单元的渐变网格偏差 2%),运行时间最多可缩短到 1/28。调整它的拉伸系数,或者增加点数,直到隔膜侧的单元薄到算例需要的程度:默认拉伸系数配 20 个点只能到 1.16 µm。永远不要把最小孔隙率当作一个数字引用:在我们跑过的任何算例里它都没有收敛。
堵塞的运行怎样结束
堵塞造成断崖之后,PyBaMM 可能在几个循环内停下,也可能静默地一直跑下去。在开裂速率 50 倍的算例里,视网格不同,它在断崖后一到五个循环停下,给出 ERROR 级别的 IDA_ERR_FAIL 或 IDA_BAD_K,或者一条 WARNING,说 “Zero negative electrode porosity cut-off” 被触发了。默认网格上的 SEI + 析锂拐点算例则一直跑到第 300 个循环,没有任何消息,而它的电解液浓度从第 163 个循环起就是负的(见姊妹篇)。即使它真的停下,也只是返回一个截断的解,不抛异常,所以要检查 sol.termination、日志和电解液浓度。另外,如果一个步骤的实验事件在它开始时就已经被违反,这个步骤会被替换成一个空解,没有任何消息,不管它的 skip_ok 怎么设(只有当一个循环的每一步都被跳过时才会去看 skip_ok;simulation.py,第 970–978 行和第 1081–1082 行)。上面那次 “ec reaction limited” 的运行就是这样在第 17 个循环之后还在”跑”的。
五、默认求解器容差让 SPM 产生偏差
PyBaMM 默认的 IDAKLUSolver 用 rtol = 10⁻⁴、atol = 10⁻⁶。每个循环的 SEI 增长只占 SEI 状态量极小的一部分,而在 SPM 里,积分器在一次充电中的步长可达 40 分钟。对于依赖电位的模型,速率在这样一步之内会变化几个数量级,这就表现为偏差:
| SPM,OKane2022 | 默认容差 | 收敛值(rtol 10⁻⁷–10⁻⁸) |
|---|---|---|
| “interstitial-diffusion limited”,1000 个循环后的 LLI | 0.037% | 0.018%(默认容差下翻倍) |
| “reaction limited”,200 个循环后的 LLI | 1.952% | 1.849%(+5.6%) |
| “reaction limited”,200 个循环后实测的 1C 衰减 | 默认容差下 +6.3% | |
| “solvent-diffusion limited”,1000 个循环后的 LLI | 0.489% | 0.489% |
(间隙扩散模型的默认容差值来自一次孔隙堵塞关闭的运行;这种 SEI 只占孔隙体积的 0.23%,所以这个开关没有影响。)DFN 因为别的原因步长小得多,在我们检查过的每个算例里,它与 rtol 10⁻⁶ 的结果相对偏差都在 10⁻⁵ 以内。修法:SPM 或 SPMe 配依赖电位的 SEI 模型时,传入 solver=pybamm.IDAKLUSolver(rtol=1e-6, atol=1e-8),这能让反应限制的 LLI 与收敛值相差不到 0.4%;如果间隙扩散模型的绝对值要紧,就用 rtol 10⁻⁷(在 10⁻⁶ 下它仍偏高 5.5%)。只收紧 atol 没有用。用 starting_solution 把长运行分段是安全的(见姊妹篇)。
六、”irreversible” 析锂在静置时也会沉积锂
PyBaMM 的 "lithium plating": "irreversible" 就是它的可逆 Butler–Volmer 析锂模型删掉溶出项(plating.py,第 94–97 行)。它在相对锂 0 V 处没有阈值。用 OKane2022 的交换电流(F·k·c_e = 0.0965 A/m²),只要石墨处于嵌锂状态,不管有没有电流,它都会沉积锂:
- 一个新的 DFN 电池(孔隙堵塞关闭)在 100% SOC、25 °C 下静置 24 小时,会把 0.761 A·h——颗粒中锂的 10%——记为死锂(堵塞打开时为 0.789 A·h),而析锂过电位始终不低于 +0.086 V:石墨离金属锂电位还差得远。在 PyBaMM 之外手工积分 Tafel 速率,得到 0.7612 A·h。
- 再以 C/3 完整充电之后,C/3 容量比不带析锂的同一电池低 16.4%(4.162 对 4.977 A·h)。
- 在普通的 25 °C C/3 循环中,负极从未降到 +0.037 V 以下,而一次放电、静置再充电就记下 0.131 A·h。
这是有意设计,而不是意外。这个模型的作者说过,在相对锂 0 V 以上析锂也会继续,只是更慢(discussion #2031);一位维护者称 “irreversible” 不现实,但因为它在文献中很常见而保留了它(discussion #3447)。PyBaMM 自己的析锂示例 notebook 在 −5 °C 充电后的一小时静置里展示了这个效应,并称那约 40 mAh “不现实”;在 26.5 里重跑,从 C/8 到 2C 的每个充电倍率都得到 39.0–39.8 mAh。这个选项的 API 文档对此只字未提,也不会发出任何警告。O’Kane 等 2020 年和 2022 年的论文都没有定义不可逆模型;2022 年论文引用的不可逆 Tafel 模型(Yang 等 2017)只在相对锂 0 V 以下才开始析锂,所用的交换电流也小到 1/96。
修法:用 "partially reversible",这也是 O’Kane 等用的。它有同样不设阈值的析锂项,但静置时析出的锂大部分会再溶出:同样静置 24 小时为 0.0093 A·h,对比 0.761 A·h。它也没有完全摆脱这个效应——issue #3605(仍未关闭)报告了 PyBaMM 耦合退化示例中零电流下的析锂损失,而那个示例用的正是它。如果需要不可逆模型,就自己写一个带阈值的。
七、SPM:还有两件事要知道
- 裂纹上的 SEI 会把锂漏回去。在 SPM 或 SPMe 里打开
"SEI on cracks"并使用默认的 surface form 时,裂纹上 SEI 所含的锂有 98% 从未离开颗粒(issue #5263,未关闭)。设"surface form": "algebraic"就能让这笔账对上。 - 孔隙堵塞打开时,SPM 会把电解液浓缩。它在每个电极里保持孔隙率 × 浓度不变,且不与隔膜交换,所以随着孔隙被填满,负极电解液浓度按 ε₀·c₀/ε 上升。”irreversible” 析锂静置 24 小时后,它达到 1,239 mol/m³,而 DFN 是 1,078,这让 SPM 的沉积量虚高约 11%(0.864 A·h,堵塞关闭时为 0.780 A·h);配内置的反应限制 SEI 时,随着 SEI 接近孔隙填满极限,浓度会走向物理上不可能的值。DFN 同样会把盐留在缩小的孔隙里(在我们的老化电池运行中,孔隙填充 30% 时为 1,139 mol/m³),但允许它扩散进隔膜和正极。而且由于 SPM 在整个电极上平均孔隙率,它根本无法表示靠近隔膜处的堵塞。
八、运行前的预检
下面这个函数接收一个尚未求解的 pybamm.Simulation,把上面那些能不报错跑完的设置标出来:
import pybamm
POTENTIAL_DEPENDENT = ("reaction limited", "ec reaction limited",
"interstitial-diffusion limited", "electron-migration limited",
"tunnelling limited", "VonKolzenberg2020")
def sei_preflight(sim):
"""Warnings for an unsolved degradation Simulation that will run but mislead."""
opts, pv = sim.model.options, sim.parameter_values
out = []
# options can be per-electrode tuples: (negative, positive)
sei, plating = (o[0] if isinstance(o, tuple) else o
for o in (opts["SEI"], opts["lithium plating"]))
if sei not in ("none", "constant"):
if pv["SEI growth activation energy [J.mol-1]"] == 0:
out.append("SEI activation energy is 0: SEI growth has no Arrhenius "
"temperature dependence")
if (opts["SEI porosity change"] == "false"
and opts["lithium plating porosity change"] == "false"):
out.append("pore clogging is off (both porosity flags 'false'): "
"SEI can grow past full pores")
if (sei.split(" (")[0] in POTENTIAL_DEPENDENT
and isinstance(sim.model, pybamm.lithium_ion.SPM)
and getattr(sim.solver, "rtol", 0) > 1e-6):
out.append(f"'{sei}' in an SPM/SPMe at rtol={sim.solver.rtol:g}: "
"use rtol<=1e-6, atol<=1e-8")
if plating != "none":
j0 = pv["Exchange-current density for plating [A.m-2]"]
cold, warm = (pv.evaluate(j0(pybamm.Scalar(1000.0), pybamm.Scalar(0.0),
pybamm.Scalar(T))) for T in (263.15, 298.15))
if cold == warm:
out.append("plating exchange current does not depend on temperature")
if plating == "irreversible":
out.append("'irreversible' plating deposits lithium at any electrode "
"potential, including at rest")
exp = getattr(sim, "experiment", None)
if exp is not None and exp.initial_start_time is not None:
if len({id(s) for s in exp.steps}) < len(exp.steps):
out.append("start_time with repeated identical steps: give every step "
"a unique tag, or the scheduled rests are skipped")
return out
在七种配置上的输出(在 PyBaMM 里 SPMe 是 SPM 的子类,所以容差检查对两者都适用):
P1 DFN, OKane2022, SEI + partially reversible plating
pore clogging is off (both porosity flags 'false'): SEI can grow past full pores
plating exchange current does not depend on temperature
P2 SPM, Chen2020, reaction-limited SEI, default solver
SEI activation energy is 0: SEI growth has no Arrhenius temperature dependence
pore clogging is off (both porosity flags 'false'): SEI can grow past full pores
'reaction limited' in an SPM/SPMe at rtol=0.0001: use rtol<=1e-6, atol<=1e-8
P3 DFN, OKane2022, irreversible plating, pore clogging on
plating exchange current does not depend on temperature
'irreversible' plating deposits lithium at any electrode potential, including at rest
P4 SPM, OKane2022, 'one cycle per day' with start_time
start_time with repeated identical steps: give every step a unique tag, or the scheduled rests are skipped
P4b same, every step tagged per cycle
(no warnings)
P5 DFN, OKane2022, SEI + partially reversible plating, clogging on, plating Arrhenius 35 kJ/mol
(no warnings)
P6 DFN, OKane2022, SEI + plating, only 'lithium plating porosity change' set
plating exchange current does not depend on temperature
它查不了的:SEI 速率常数是否针对你的电池拟合过(第二节),以及网格能否分辨析锂堵塞(第四节)。前者需要老化数据;后者要用更细的隔膜侧网格单元把算例重跑一遍再比较。检查通过也说明不了你读结果的方式对不对——那是姊妹篇里 fade_audit 的事。
九、测量方法
- PyBaMM 26.5.0,Python 3.13,Apple M3,
IDAKLUSolver。除非另有说明,参数集为 OKane2022,温度为 25 °C 等温;循环为 1C 放电到 2.5 V,再恒流恒压充电到 4.2 V,恒压阶段至 C/20。 - 加速运行都注明了被放大的参数。SEI 结果只在 SEI 还能装进负极孔隙时保留(OKane2022 为 651 nm 的生长量、0.612 A·h 的锂);超出这个范围的结果只作为标明的反例出现。锂损失和析锂都在放电步骤之后读取。
- 大多数主要数字都在更细的网格(x_n 取 40 和 80,以及向隔膜加密的渐变网格)和 rtol 10⁻⁶–10⁻⁷ 下核对过。例外是第二节 DFN 的溶剂扩散、电子迁移和间隙扩散三行,以及第一节 DFN 的 1C 充电值,它们只在 x_n = 20 和默认容差下跑过;另外还有各节中说明不收敛的算例。
- 这项工作分两轮进行——先是独立测量,再按固定标准(孔隙填满极限、读取时刻、容差、网格)做对抗式复核。第一轮的若干结果没能通过复核,本文没有报告。
References
- S. E. J. O’Kane 等, Lithium-ion battery degradation: how to model it, Phys. Chem. Chem. Phys. 24 (2022) 7909–7922.
- S. E. J. O’Kane, I. D. Campbell, M. W. J. Marzook, G. J. Offer, M. Marinescu, Physical origin of the differential voltage minimum associated with lithium plating in Li-ion batteries, J. Electrochem. Soc. 167 (2020) 090540.
- X.-G. Yang, Y. Leng, G. Zhang, S. Ge, C.-Y. Wang, Modeling of lithium plating induced aging of lithium-ion batteries: transition from linear to nonlinear aging, J. Power Sources 360 (2017) 28–40.
- PyBaMM 示例:析锂、耦合退化
- PyBaMM issue #3605(静置时析锂)、issue #5263(SPM 中裂纹上的 SEI)、discussion #2031 与 #3447(不可逆析锂)、#2992(SEI 与温度)
相关阅读:PyBaMM 的容量衰减到底在量什么;PyBaMM 热模型常见陷阱;PyBaMM Experiment 常见陷阱;PyBaMM 求解器收敛失败排查。
配套资源
下载配套脚本
电池建模与 AI / GUIDE
PyBaMM 静默错误检查脚本说明
固定 pybamm==26.5.0,验证日期 2026-09-26;说明每个文件的用途、两个测试脚本的运行方法,并链接两篇文章。
电池建模与 AI / CODE
sei_preflight.py:SEI 与析锂预检
求解前检查 Simulation:SEI 活化能为 0、孔隙堵塞关闭、SPM 中电位相关 SEI 的求解容差、析锂交换电流与温度无关、irreversible 析锂,以及 start_time 遇到重复步骤。
电池建模与 AI / CODE
test_preflight.py:sei_preflight 的配置用例
构造 SEI 一文中的七种 Simulation 配置(P1–P6 与 P4b),不求解模型,逐一打印 sei_preflight 的警告。
电池建模与 AI / CODE
fade_audit.py:容量读数审计
检查已求解的退化仿真:循环停在充电态、"% capacity" 终止比较的是 eSOH 容量、电解液浓度变负、孔隙堵塞关闭时 SEI 超过填满负极孔隙所需量的一半。
电池建模与 AI / CODE
test_audit.py:fade_audit 的四个用例
在 OKane2022 上按参数 T1–T4 运行四个退化场景,打印放电容量和 fade_audit 的警告。
