PyBaMM 自带 18 个参数集,大多数教程随手挑一个——通常是 Chen2020——却不说为什么。我用 PyBaMM 26.5.0 把同一组实验在每个参数集上都跑了一遍。会报错的那些不是问题,KeyError 会准确告诉你缺哪个参数。真正的问题是四种情况:参数集对你的研究是错的,却能一路跑完,一条警告都没有。
PyBaMM 电池建模系列 · 静默错误实测(第 1 / 7 篇):下一篇 PyBaMM Experiment 跑完了却是错的:五个实测陷阱 · 专题页:数据管线 4 篇 + 静默错误实测 7 篇 · RSS 订阅。
一、盒子里到底有什么
18 个里只有 11 个能直接放进标准的 pybamm.lithium_ion.DFN()。其余的需要特定模型——半电池、等效电路、铅酸、钠离子、复合电极和一个 MSMR 示例——把它们塞进普通 DFN 会直接报错,这是好事。
| 参数集 | 电芯 / 体系 | 电压窗口 (V) | 能否直接用 DFN |
|---|---|---|---|
| Marquis2019 | Kokam SLPB78205130H(默认参数集) | 3.105–4.1 | 能 |
| Chen2020 | LG M50,石墨 / NMC811 | 2.5–4.2 | 能 |
| OKane2022 | LG M50,基于 Chen2020,补齐了退化参数 | 2.5–4.2 | 能 |
| ORegan2022 | LG M50,带温度相关的热物性和电解液数据 | 2.5–4.4 | 能 |
| Ecker2015 | Kokam SLPB 75106100 | 2.5–4.2 | 能 |
| Mohtat2020 | 石墨 / NMC532 软包 | 2.8–4.2 | 能 |
| Ai2020 | Enertech 软包,钴酸锂 | 3.0–4.2 | 能 |
| NCA_Kim2011 | 石墨 / NCA “标称设计”软包 | 2.7–4.2 | 能 |
| Prada2013 | 磷酸铁锂 | 2.0–3.6 | 能 |
| Ramadass2004 | 石墨 / 钴酸锂,由多个来源拼凑 | 2.8–4.2 | 能 |
| Chayambuka2022 | 钠离子 | 2.0–4.2 | 能跑(见下文) |
| Chen2020_composite | 石墨 + 硅复合负极 | 2.5–4.2 | 不能,需要颗粒相选项 |
| MSMR_Example | 石墨 / NMC622,MSMR 热力学 | 2.8–4.2 | 不能,需要 MSMR 选项 |
| Ecker2015_graphite_halfcell、OKane2022_graphite_SiOx_halfcell、Xu2019 | 半电池 | — | 不能,需要半电池选项 |
| ECM_Example | 等效电路,仅作演示 | 3.2–4.2 | 不能,需要 ECM 模型 |
| Sulzer2019 | 铅酸 | 1.75–2.42 | 不能,需要铅酸模型 |
有两句话写在源码里,参数集列表上看不到。Ramadass2004 的文档字符串自称是”一个有点东拼西凑的参数集”,”应谨慎使用”。OKane2022 的则写着”本参数集不声称代表真实参数值”。这两句下文都会用到。
Chayambuka2022 是钠离子参数集,它能在 pybamm.lithium_ion.DFN() 里不报错地跑,因为多孔电极方程的形式相同。PyBaMM 另有 pybamm.sodium_ion 模块;如果研究的就是钠离子,用那个,别指望锂离子模型碰巧接受了这些数字。
二、静默错误之一:”1C” 不是一小时
PyBaMM 把倍率换算成电流,用的是 "Nominal cell capacity [A.h]"——参数集里手填的一个数。而电芯实际能放多少电,取决于完全不同的东西:电极载量和计量比窗口。没有任何机制保证两者一致。
我把每个参数集从满电放到它自己的下限电压,分别用 C/20(接近平衡)和 1C:
| 参数集 | 标称 (A·h) | C/20 实放 (A·h) | 偏差 | “1C” 用时 |
|---|---|---|---|---|
| Ramadass2004 | 1.000 | 1.775 | +77.5% | 106.0 分钟 |
| Marquis2019(默认) | 0.681 | 0.872 | +28.1% | 75.3 分钟 |
| NCA_Kim2011 | 0.430 | 0.483 | +12.3% | 66.4 分钟 |
| Ecker2015 | 0.156 | 0.171 | +9.4% | 65.3 分钟 |
| Ai2020 | 2.280 | 2.463 | +8.0% | 63.5 分钟 |
| Chen2020 | 5.000 | 5.144 | +2.9% | 59.9 分钟 |
| OKane2022 | 5.000 | 5.100 | +2.0% | 59.5 分钟 |
| ORegan2022 | 5.000 | 5.010 | +0.2% | 53.1 分钟 |
| Mohtat2020 | 5.000 | 4.961 | −0.8% | 58.0 分钟 |
| Prada2013 | 2.300 | 2.285 | −0.7% | 50.6 分钟 |
默认参数集——也就是 pybamm.lithium_ion.DFN().default_parameter_values 拿到的那个——实际能装的电比标称多 28%。用默认参数跑”1C”的人,实际跑的大约是 0.78C,一次”1C”放电要 75 分钟。倍率性能曲线、产热估算、任何按倍率归一化的结果都跟着偏了这个比例。
修法是测一次实际容量写回去,让倍率名副其实。对 Marquis2019,这样做之后 1C 放电从 75.3 分钟变成 58.5 分钟(剩下的差距是 1C 下的极化,正常):
pv = pybamm.ParameterValues("Marquis2019")
q_real = audit("Marquis2019")["actual_capacity_Ah"] # 0.8717,见第六节
pv.update({"Nominal cell capacity [A.h]": q_real})
或者干脆在实验里用安培指定电流,不用倍率——但慢速步骤一定要写明时长上限,比如 "for 60 hours or until 2.5 V"。不写的话,安培步骤会在 24 小时处被截断,而且不抛异常,详见 PyBaMM Experiment 跑完了却是错的。
三、静默错误之二:Chen2020 里温度几乎不起作用
Chen2020 是最常被选用的参数集,它描述的是 LG M50 电芯——和 OKane2022、ORegan2022 是同一颗。我在三者上跑同样的 1C 放电,分别在 25°C 和 −10°C:
| LG M50 参数集 | 25°C 1C | −10°C 1C | 变化 |
|---|---|---|---|
| Chen2020 | 4.992 A·h | 4.961 A·h | −0.6% |
| OKane2022 | 4.955 A·h | 3.191 A·h | −35.6% |
| ORegan2022 | 4.422 A·h | 1.922 A·h | −56.5% |
同一颗电芯、同样的温度、同样的电流:4.96、3.19、1.92 A·h。用 Chen2020 做低温研究,结论会是”低温影响不大”,而 PyBaMM 里没有任何东西会提醒你。
原因看得见:把每个能随温度变化的参数在 298.15 K 和 263.15 K 各求一次值,看谁变了:
| 参数 | Chen2020 | OKane2022 |
|---|---|---|
| 负极交换电流密度 | −84.7% | −84.7% |
| 正极交换电流密度 | −61.5% | −61.5% |
| 电解液扩散系数 | 不变 | −59.8% |
| 电解液电导率 | 不变 | −59.8% |
| 负极颗粒扩散系数 | 常数,不是函数 | −80.3% |
| 正极颗粒扩散系数 | 常数,不是函数 | −73.9% |
Chen2020 的电解液扩散系数和电导率函数,签名里接收了 T,函数体里却一次都没用。两个固相扩散系数干脆是常数(3.3e-14 和 4e-15)。只有反应动力学带阿伦尼乌斯项——而 1C 放电的容量受限于传输,不受限于动力学。唯一会变的那一项,恰好对这个测试最不重要。
Ai2020(−0.5%)和 Prada2013(−0.3%)也是这样。只要温度是研究变量,先查这一点;LG M50 的三个参数集里,真正带着温度依赖的是 OKane2022 和 ORegan2022。
电池自己发热时,同样的差距也会出现。打开集总热模型后,Chen2020 在 3C 放电中升温 58 K,容量只多 4%;同一颗电芯的 OKane2022 多出 114%。这一点和其他热模型陷阱的实测见 PyBaMM 热模型实测。
想靠”混搭参数集”来修,先看这个
ORegan2022 的电解液阳离子迁移数来自 Landesfeind & Gasteiger (2019) 的拟合式,它在低温下会变号。在 1 mol/L 时,25°C 是 0.221,10°C 附近过零,−10°C 时是 −0.383。Chen2020 和 OKane2022 用的是常数 0.2594。
在浓溶液理论里负迁移数并非不可能,所以这本身不能算错。为了看它对低温结果贡献多大,我在其他参数都保持低温的前提下单独动它:
| ORegan2022,−10°C | 1C 容量 | 相对 25°C 的损失 |
|---|---|---|
| 原样 | 1.922 A·h | 56.5% |
| 迁移数冻结为 25°C 的函数 | 2.665 A·h | 39.7% |
| 迁移数换成 Chen2020 的 0.2594 | 1.249 A·h | 71.7% |
迁移数的温度依赖解释了约 30% 的低温损失。但换成另一个参数集里”看起来合理”的常数,结果不是变好而是更糟——因为 ORegan2022 里的迁移数、热力学因子和电导率是一起拟合的。替换其中一个,就破坏了它们之间的一致性。Ramadass2004 自称”东拼西凑”时警告的,正是这件事。
四、静默错误之三:实验字符串会覆盖电芯自己的电压上下限
常见写法是写一套循环流程,然后在几个参数集上套用:
["Discharge at 1C until 2.5 V", "Rest for 1 hour",
"Charge at C/2 until 4.2 V", "Hold at 4.2 V until C/50"]
它在全部 11 个参数集上都跑完了。包括 Prada2013——一颗上限 3.6 V 的磷酸铁锂电芯——被充到了 4.2 V,以及下限 3.105 V 的 Marquis2019 被放到了 2.5 V。我捕获了这两次运行期间发出的全部警告:零条。
实验字符串里的电压是直接替换参数集的截止电压,而不是和它比较。LFP 过充时,正极颗粒表面计量比降到了 0.0002——电极被推到了开路电位曲线的最边缘。求解器没意见;物理上早就没有意义了。
让流程从参数集里读上下限,而不是手敲数字:
def cycle_within_window(pv, discharge="1C", charge="C/2"):
lo = pv["Lower voltage cut-off [V]"]
hi = pv["Upper voltage cut-off [V]"]
return pybamm.Experiment([
f"Discharge at {discharge} until {lo} V",
"Rest for 1 hour",
f"Charge at {charge} until {hi} V",
f"Hold at {hi} V until C/50",
])
这样同一个 Prada2013 的运行就保持在 2.000–3.600 V 之间。
五、静默错误之四:SEI 到处都能跑,但那不是你这颗电芯的 SEI
我在 11 个参数集上分别构建带常见退化和热模型选项的 DFN。缺参数时会抛出点名的 KeyError,这是好的那种失败:
| 参数集 | SEI(溶剂扩散) | SEI(EC 反应) | 析锂 | 颗粒开裂 | 应力驱动 LAM | 集总热模型 |
|---|---|---|---|---|---|---|
| OKane2022 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Ecker2015 | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ |
| Ai2020 | ✓ | ✓ | ✗ | ✓ | ✓ | ✓ |
| Chen2020 | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ |
| Marquis2019 | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ |
| Mohtat2020 | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ |
| NCA_Kim2011 | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ |
| Ramadass2004 | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
| ORegan2022 | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ |
| Prada2013 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Chayambuka2022 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
OKane2022 是唯一支持全部选项的参数集,这也是它常被当作退化研究起点的原因。缺的参数也都在意料之中:析锂缺 Exchange-current density for stripping [A.m-2],开裂缺 Negative electrode initial crack length [m],三个不支持 SEI 的参数集缺 Initial SEI thickness [m]。
安静的陷阱在 SEI 那一列。8 个参数集都能带 SEI 构建——但 Chen2020、Marquis2019、Mohtat2020 和 Ai2020 的文档字符串写的是同一句话:”SEI 参数是取自 Ramadass2004、Ploehn2004 等论文的 SEI 生长示例参数”。模型能跑,也能画出一条容量衰减曲线。那是一条用别的电芯借来的通用 SEI 参数算出的曲线,不是针对参数集里那颗电芯拟合的。如果你要拿衰减速率去和实验数据比,这个区别就是整个研究。
OKane2022 也是如此:它的 SEI 速率常数就是 Chen2020 的通用示例值,只有活化能和每个 SEI 分子对应的锂数不同。这对衰减曲线意味着什么,见 PyBaMM SEI 与析锂实测。
六、信任一个参数集之前可以跑的检查
下面覆盖了需要跑仿真才能发现的两种静默错误,每个参数集几秒钟:
import pybamm
def audit(name, T_cold=263.15):
pv = pybamm.ParameterValues(name)
q_nom = pv["Nominal cell capacity [A.h]"]
v_lo = pv["Lower voltage cut-off [V]"]
v_hi = pv["Upper voltage cut-off [V]"]
def capacity(rate, T=None):
p = pybamm.ParameterValues(name)
if T is not None:
p.update({"Ambient temperature [K]": T, "Initial temperature [K]": T})
sim = pybamm.Simulation(
pybamm.lithium_ion.DFN(),
parameter_values=p,
experiment=pybamm.Experiment([f"Discharge at {rate} until {v_lo} V"]),
)
return float(sim.solve(initial_soc=1.0)["Discharge capacity [A.h]"].entries[-1])
q_slow = capacity("C/20")
q_warm = capacity("1C")
q_cold = capacity("1C", T=T_cold)
return {
"nominal_vs_actual_%": round(100 * (q_slow / q_nom - 1), 1),
"capacity_change_at_T_cold_%": round(100 * (q_cold / q_warm - 1), 1),
"voltage_window_V": (v_lo, v_hi),
"actual_capacity_Ah": round(q_slow, 4),
}
Marquis2019 {'nominal_vs_actual_%': 28.1, 'capacity_change_at_T_cold_%': -26.6, 'voltage_window_V': (3.105, 4.1), ...}
Chen2020 {'nominal_vs_actual_%': 2.9, 'capacity_change_at_T_cold_%': -0.6, 'voltage_window_V': (2.5, 4.2), ...}
OKane2022 {'nominal_vs_actual_%': 2.0, 'capacity_change_at_T_cold_%': -35.6, 'voltage_window_V': (2.5, 4.2), ...}
把它当成三个问题读:标称容量和实际容量差在几个百分点以内,还是倍率需要重新标定?结果到底随不随温度变?你的实验字符串必须遵守什么电压窗口?
至于退化,先读参数集的文档字符串——help(pybamm.parameter_sets["Chen2020"])——再读衰减曲线。”示例参数”这几个字,就是结果和示意图之间的区别。
七、测量方式
- PyBaMM 26.5.0,Python 3.13,Apple M3。默认求解器(
IDAKLUSolver),除特别说明外为默认选项的pybamm.lithium_ion.DFN()。 - 每次放电都从
initial_soc=1.0开始,到参数集自己的Lower voltage cut-off [V]结束。”实际容量”取 C/20 放电容量。 - 低温运行把
Ambient temperature [K]和Initial temperature [K]都设为 263.15 K,模型为默认的等温模型。 - 选项兼容性指
Simulation.build()成功,不代表由此得到的退化速率在物理上经过校准。 - 每个参数集在独立进程里带超时运行,一个卡住不会污染其他结果。实际没有一个卡住。
References
- PyBaMM ParameterValues API
- PyBaMM:长时间实验仿真
- Chen et al. (2020), Development of experimental techniques for parameterization of multi-scale lithium-ion battery models, J. Electrochem. Soc.
- O’Kane et al. (2022), Lithium-ion battery degradation: how to model it, Phys. Chem. Chem. Phys.
- Landesfeind & Gasteiger (2019), Temperature and concentration dependence of the ionic transport properties of lithium-ion battery electrolytes, J. Electrochem. Soc.
相关阅读:PyBaMM 参数拟合与可辨识性——内置参数集不够用时该怎么办;PyBaMM 求解器收敛失败排查——参数集能跑但求解器不收敛时;PyBaMM 架构——SPM、SPMe 和 DFN 怎么选;PyBaMM 热模型实测——这些参数集带的热参数靠不靠得住。
