锂电池SOH计算:容量实测法与循环计数法的双重验证
锂电池SOH计算:容量实测法与循环计数法的双重验证
引言
如果说SOC(荷电状态)是电池的"油表",那么SOH(健康状态)就是电池的"体检报告"。在动力电池和储能系统中,准确评估SOH不仅关系到续航里程的预测,更直接影响安全性判断、维护决策和资产管理。
一块标称100Ah的电池,使用两年后实际容量可能只剩80Ah。这20%的衰减如何量化?何时该更换电池?这些问题的答案都藏在SOH算法中。
然而,SOH估算远比SOC复杂。电池容量会随温度、倍率、循环次数、存储时间等多种因素变化,单一方法难以准确评估。本文将基于一个真实的车规级BMS项目,深入剖析两种主流SOH计算方法——容量实测法和循环计数法,以及它们的融合策略。
一、SOH的定义与工程意义
1.1 SOH的数学定义
SOH(State of Health)的标准定义是:
SOH = (当前最大可用容量 / 出厂额定容量) × 100%
这里的"最大可用容量"是指在标准条件下(25℃,0.5C倍率),电池从满电到截止电压能够释放的电量。
在代码中,这个定义被直接实现:
u16 GetGCapSohTenthAPI(void) {
u16 capSoh = 0;
u32 totalCap = 0;
u32 ratedCap = 0;
totalCap = GetGroupTotalCapAPI(); // 当前最大容量(单位:mAh)
ratedCap = GetGroupRatedCapAPI(); // 额定容量(单位:mAh)
if(ratedCap > 0) {
capSoh = (u16)(totalCap * 10 / ratedCap); // 单位:千分之一
}
return capSoh;
}
1.2 SOH的工程意义
1. 安全预警
当SOH低于80%时,电池内阻增大,热失控风险上升。许多车企将SOH 80%作为强制换电的红线。
2. 质保判定
动力电池的质保条款通常是"8年或15万公里,SOH不低于70%"。SOH是判定质保责任的关键依据。
3. 梯次利用决策
退役动力电池可以用于储能系统。SOH 80%的电池虽然不适合车用,但用于家庭储能完全可行。准确的SOH评估是梯次利用的前提。
4. 资产估值
对于换电站、共享电动车等运营商,电池是核心资产。SOH直接影响资产折旧和残值评估。
1.3 SOH估算的挑战
与SOC不同,SOH无法通过简单的积分计算得出。主要挑战包括:
- 时间尺度长:容量衰减是缓慢过程,需要数月甚至数年的数据积累
- 影响因素多:温度、倍率、DOD(放电深度)、存储时间都会影响容量
- 测量困难:准确测量容量需要完整的充放电循环,但用户很少这样使用
- 可逆性:低温下容量降低是可逆的,不代表真实老化
正因为这些挑战,工程中通常采用多种方法融合的策略。
二、方法一:容量实测法
2.1 基本原理
容量实测法的思路最直接:通过实际的充放电循环,测量电池能够存储和释放的电量。
在代码中,GetGroupTotalCapAPI()返回的就是通过实测得到的容量:
u32 GetGroupTotalCapAPI(void) {
return(sCapForm.topCap - CAP_ZERO_POINT);
}
这里的topCap(顶端容量)是如何确定的?关键在于容量学习算法。
2.2 容量学习的触发条件
代码中实现了基于充放电末端的容量学习逻辑(在SocSoeCorr.c中):
// 充电末端:电压达到上限,且SOC接近100%
if((GetGCellMaxVoltAPI() >= CORR_CHG_END_MAX_V)
&& (GetGRealSocMilliAPI() >= CORR_CHG_END_LES_SOC)) {
// 触发容量学习
CorrGroupTotalCapAPI(learnedCap);
}
// 放电末端:电压达到下限,且SOC接近0%
if((GetGCellMinVoltAPI() <= CORR_DHG_END_MIN_V)
&& (GetGRealSocMilliAPI() <= CORR_DHG_END_MOS_SOC)) {
// 触发容量学习
CorrGroupTotalCapAPI(learnedCap);
}
容量学习的逻辑是:
- 充电学习:从某个SOC充到100%,记录充入电量ΔQ_chg,推算总容量
- 放电学习:从某个SOC放到0%,记录放出电量ΔQ_dhg,推算总容量
- 完整循环学习:从0%充到100%,或从100%放到0%,直接测量总容量
2.3 容量更新的平滑策略
为了避免单次测量误差导致容量跳变,代码中采用了加权平滑:
void CorrGroupTotalCapAPI(u32 cap) {
u32 nowCap = sCapForm.nowCap;
u32 remCap = sCapForm.remCap;
u32 lowCap = sCapForm.baseCap;
u32 allCap = sCapForm.topCap;
u32 befCap = sCapForm.topCap - CAP_ZERO_POINT;
// 计算当前SOC
u32 soc = (nowCap - lowCap) * 10000 / befCap;
// 根据SOC重新计算当前容量
nowCap = cap * soc / 10000 + CAP_ZERO_POINT;
// 更新总容量
sCapForm.topCap = cap + CAP_ZERO_POINT;
sCapForm.nowCap = nowCap;
// 写入EEPROM
StoreGroupTotalCapToEEP();
}
这个算法的巧妙之处在于:
- 保持SOC不变(用户体验连续)
- 按比例调整当前容量
- 立即持久化到EEPROM
2.4 容量实测法的优势与局限
优势:
- 直接测量:不依赖模型假设,反映真实容量
- 自适应:能够跟踪电池的实际老化过程
- 可验证:可以通过离线容量测试验证准确性
局限:
- 数据收敛慢:需要多次完整循环才能得到稳定结果
- 使用场景受限:用户很少进行0-100%的完整循环
- 温度影响:低温下测得的容量偏小,但不代表真实老化
- 倍率影响:大电流放电容量低,需要倍率补偿
正是因为这些局限,工程中需要引入第二种方法。
三、方法二:循环计数线性衰减模型
3.1 电池老化的经验模型
大量实验数据表明,锂电池的容量衰减大致遵循以下规律:
- 循环老化:每完成一次充放电循环,容量衰减一定比例
- 日历老化:即使不使用,容量也会随时间缓慢衰减
- 非线性特征:初期衰减快,后期趋于平缓
在工程实践中,为了简化计算,常采用线性模型:
SOH = 100% - (实际循环次数 / 额定循环寿命) × (100% - EOL_SOH)
其中EOL_SOH(End of Life SOH)通常取80%,即认为电池寿命终止时SOH为80%。
3.2 代码实现
在CellFadeCalc.c中,实现了基于循环计数的SOH计算:
u16 GetGTimSohTenthAPI(void) {
u16 timSoh = 0;
u32 fadeCycle = 0;
u32 ratedCycle = 0;
fadeCycle = GetGroupFadeCycleAPI(); // 实际循环次数
ratedCycle = GetGroupRatedCycleAPI(); // 额定循环寿命
if(ratedCycle > 0) {
// SOH = 100% - (fadeCycle / ratedCycle) × 20%
// 单位:千分之一,所以 100% = 1000
timSoh = 1000 - (fadeCycle * 200 / ratedCycle);
if(timSoh > 1000) {
timSoh = 1000; // 上限保护
}
} else {
timSoh = 1000; // 默认100%
}
return timSoh;
}
这个公式的推导:
假设:
- 额定循环寿命 = 2000次
- 寿命终止时 SOH = 80%
- 当前循环次数 = 500次
则:SOH = 100% - (500 / 2000) × (100% - 80%) = 100% - 0.25 × 20% = 100% - 5% = 95%
3.3 循环次数的统计方法
循环次数的定义并不简单。一次"循环"是指什么?
- 完整循环:从0%充到100%,或从100%放到0%
- 等效循环:累积充放电量达到额定容量
代码中采用等效循环的方法:
void GroupFadeCycleCalcTask(void) {
static u32 sHisChgCap = 0;
static u32 sHisDhgCap = 0;
u32 nowChgCap = GetChgIntCapAPI(); // 累计充电量
u32 nowDhgCap = GetDhgIntCapAPI(); // 累计放电量
u32 ratedCap = GetGroupRatedCapAPI();
u32 chgDelta = nowChgCap - sHisChgCap;
u32 dhgDelta = nowDhgCap - sHisDhgCap;
// 充放电量都达到额定容量,计为一次循环
if((chgDelta >= ratedCap) && (dhgDelta >= ratedCap)) {
sFadeInfo.fadeCycle++;
sHisChgCap = nowChgCap;
sHisDhgCap = nowDhgCap;
// 写入EEPROM
StoreGroupFadeCycleToEEP();
}
}
这个方法的优点是:
- 不要求完整的0-100%循环
- 能够统计碎片化的充放电行为
- 充放电都计入,更全面
3.4 循环计数法的优势与局限
优势:
- 实时性好:不需要等待完整循环,每次充放电都更新
- 计算简单:只需要累加器和除法运算
- 趋势稳定:不受单次测量误差影响
局限:
- 模型简化:线性模型无法反映实际的非线性衰减
- 忽略使用条件:高温、大倍率会加速老化,但模型未考虑
- 日历老化缺失:长期存储的容量衰减未计入
- 参数依赖:需要准确的额定循环寿命参数
四、双方法融合策略
4.1 为什么需要融合?
两种方法各有优劣:
- 容量实测法:准确但慢,受温度倍率影响大
- 循环计数法:快速但粗糙,无法反映实际容量
融合的目的是取长补短,提高鲁棒性。
4.2 融合算法实现
代码中实现了一个精妙的融合策略:
void GroupFadeSohCalcTask(void) {
u16 capSoh = 0;
u16 timSoh = 0;
u16 nowSoh = 0;
u16 hisSoh = 0;
capSoh = GetGCapSohTenthAPI(); // 容量实测SOH
timSoh = GetGTimSohTenthAPI(); // 循环计数SOH
hisSoh = GetGSohTenthAPI(); // 上次SOH
// 策略1:两种方法差异小于5%,优先使用循环计数法
if(ABS(capSoh, timSoh) < 50) { // 50 = 5% × 1000
nowSoh = timSoh;
}
// 策略2:差异较大,取平均值
else {
nowSoh = (capSoh + timSoh) / 2;
}
// 策略3:SOH只能下降,不能上升(防止反弹)
if(nowSoh > hisSoh) {
nowSoh = hisSoh;
}
// 策略4:单次下降不超过0.5%(防止异常跳变)
if((hisSoh > nowSoh) && ((hisSoh - nowSoh) > 5)) {
nowSoh = hisSoh - 5;
}
// 更新SOH
sFadeInfo.soh = nowSoh;
// 写入EEPROM
StoreGroupSohToEEP();
}
4.3 融合策略的设计思想
策略1:差异小时优先循环计数法
if(ABS(capSoh, timSoh) < 50) {
nowSoh = timSoh;
}
当两种方法的结果接近时(差异<5%),说明电池处于正常老化状态,此时循环计数法更稳定,不受单次容量测量误差影响。
例如:
- capSoh = 92.3%
- timSoh = 94.1%
- 差异 = 1.8% < 5%
- 采用 timSoh = 94.1%
策略2:差异大时取平均值
else {
nowSoh = (capSoh + timSoh) / 2;
}
当两种方法差异较大时(≥5%),说明可能存在异常:
- 容量实测受温度影响(冬季容量偏低)
- 循环计数模型不准确(实际老化快于预期)
此时取平均值是一种保守策略,避免单一方法的极端结果。
例如:
- capSoh = 85.2%(低温测量)
- timSoh = 94.1%(模型预测)
- 差异 = 8.9% ≥ 5%
- 采用平均值 = (85.2% + 94.1%) / 2 = 89.65%
策略3:单调递减约束
if(nowSoh > hisSoh) {
nowSoh = hisSoh;
}
这是一个硬约束:SOH只能下降,不能上升。
物理依据:电池老化是不可逆过程,容量不可能恢复。如果计算出的SOH高于历史值,说明存在测量误差或计算错误。
例外情况:
- 温度恢复:冬季测得SOH 85%,夏季测得90%
- 此时应该保持85%,因为冬季的低容量是可逆的,不代表真实老化
策略4:变化率限制
if((hisSoh > nowSoh) && ((hisSoh - nowSoh) > 5)) {
nowSoh = hisSoh - 5;
}
这是一个软约束:单次下降不超过0.5%。
物理依据:电池容量衰减是缓慢过程,不可能在一次循环中突降5%。如果出现大幅下降,很可能是:
- 传感器故障
- 容量测量异常(未充满就认为到100%)
- 温度突变
限制变化率可以避免这些异常导致的SOH跳变。
4.4 融合策略的效果分析
假设一个实际场景:
场景1:正常老化
┌────────┬──────────┬──────────┬──────────┬──────────┬─────────────────────┐
│ 时间 │ 循环次数 │ 容量实测 │ 循环计数 │ 融合结果 │ 说明 │
├────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 0个月 │ 0 │ 100% │ 100% │ 100% │ 初始状态 │
├────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 6个月 │ 200 │ 97.8% │ 98.0% │ 98.0% │ 差异<5%,用循环计数 │
├────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 12个月 │ 450 │ 95.2% │ 95.5% │ 95.5% │ 差异<5%,用循环计数 │
├────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 18个月 │ 720 │ 92.8% │ 92.8% │ 92.8% │ 两者一致 │
└────────┴──────────┴──────────┴──────────┴──────────┴─────────────────────┘
场景2:冬季低温
┌────────┬──────────┬──────────┬──────────┬──────────┬───────────────────────┐
│ 时间 │ 循环次数 │ 容量实测 │ 循环计数 │ 融合结果 │ 说明 │
├────────┼──────────┼──────────┼──────────┼──────────┼───────────────────────┤
│ 12个月 │ 450 │ 95.5% │ 95.5% │ 95.5% │ 常温正常 │
├────────┼──────────┼──────────┼──────────┼──────────┼───────────────────────┤
│ 13个月 │ 465 │ 88.2% │ 95.0% │ 91.6% │ 低温,取平均 │
├────────┼──────────┼──────────┼──────────┼──────────┼───────────────────────┤
│ 14个月 │ 480 │ 87.5% │ 94.5% │ 91.0% │ 继续低温 │
├────────┼──────────┼──────────┼──────────┼──────────┼───────────────────────┤
│ 15个月 │ 495 │ 94.8% │ 94.0% │ 91.0% │ 温度恢复,但SOH不回升 │
└────────┴──────────┴──────────┴──────────┴──────────┴───────────────────────┘
可以看到,融合策略有效避免了低温导致的SOH误判。
场景3:异常跳变
┌──────────┬──────────┬──────────┬──────────┬──────────┬─────────────────────┐
│ 时间 │ 循环次数 │ 容量实测 │ 循环计数 │ 融合结果 │ 说明 │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 12个月 │ 450 │ 95.5% │ 95.5% │ 95.5% │ 正常状态 │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 12.1个月 │ 452 │ 82.3% │ 95.3% │ 88.8% │ 容量测量异常 │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 12.2个月 │ 454 │ 83.1% │ 95.1% │ 88.3% │ 限制下降速度 │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────┤
│ 12.3个月 │ 456 │ 95.2% │ 94.9% │ 88.3% │ 容量恢复,SOH不回升 │
└──────────┴──────────┴──────────┴──────────┴──────────┴─────────────────────┘
融合策略将异常的单次跳变平滑化,避免了误报。
五、SOH更新时机与持久化策略
5.1 更新触发条件
SOH不需要像SOC那样高频更新。代码中的触发条件是:
void GroupFadeSohCalcTask(void) {
static u32 sHisCycle = 0;
u32 nowCycle = GetGroupFadeCycleAPI();
// 循环次数变化时才更新SOH
if(nowCycle != sHisCycle) {
// 执行SOH计算
// ...
sHisCycle = nowCycle;
}
}
即:每完成一次等效循环,更新一次SOH。
这个策略的优点:
- 降低计算开销:SOH计算涉及除法,相对耗时
- 避免频繁写EEPROM:延长EEPROM寿命
- 数据稳定性:一次循环的数据量足够大,结果更可靠
5.2 EEPROM存储策略
SOH是关键数据,必须持久化。代码中的存储策略:
static void StoreGroupSohToEEP(void) {
static u16 sHisSoh = 0;
u16 nowSoh = sFadeInfo.soh;
// SOH变化≥0.1%时才写入
if(ABS(nowSoh, sHisSoh) >= 1) {
EnerChangEepGSohHook(nowSoh);
sHisSoh = nowSoh;
}
}
这个策略平衡了数据安全和EEPROM寿命:
- 变化阈值:0.1%(千分之一)
- 写入频率:假设每次循环SOH下降0.01%,则每10次循环写入一次
- EEPROM寿命:假设10万次擦写寿命,可支持100万次循环
5.3 掉电恢复机制
系统上电时,从EEPROM读取上次的SOH值:
void GroupFadeSohInit(void) {
u32 data[3] = {0};
if(TRUE == ParaReadStoreFadeInfo(data, 3)) {
sFadeInfo.fadeCycle = data[0]; // 循环次数
sFadeInfo.soh = data[1]; // SOH
sFadeInfo.soc = data[2]; // 累计SOC变化
} else {
sFadeInfo.fadeCycle = 0;
sFadeInfo.soh = 1000; // 默认100%
sFadeInfo.soc = 0;
}
}
这确保了即使掉电,SOH数据也不会丢失。
六、SOH的工程局限性与改进方向
6.1 温度影响的缺失
代码中的SOH计算未考虑温度补偿,这是一个明显的局限。
问题:
锂电池的容量与温度强相关:
┌──────┬──────────┐
│ 温度 │ 相对容量 │
├──────┼──────────┤
│ -20℃ │ 60-70% │
├──────┼──────────┤
│ 0℃ │ 80-85% │
├──────┼──────────┤
│ 25℃ │ 100% │
├──────┼──────────┤
│ 45℃ │ 102-105% │
└──────┴──────────┘
如果在-20℃测量容量,得到的是70%,但这不代表电池老化到SOH 70%,而是低温导致的可逆容量损失。
改进方向:
引入温度补偿系数:
u16 GetGCapSohWithTempCorr(void) {
u16 capSoh = GetGCapSohTenthAPI();
s16 temp = GetGAvgTempAPI(); // 平均温度
u16 tempCoeff = 1000; // 默认系数1.0
// 温度补偿查找表
if(temp < 0) {
tempCoeff = 1000 + (0 - temp) * 5; // 每低1℃,补偿0.5%
} else if(temp > 25) {
tempCoeff = 1000 - (temp - 25) * 2; // 每高1℃,补偿-0.2%
}
return (capSoh * tempCoeff / 1000);
}
6.2 倍率影响的缺失
大电流放电时,容量会降低:
┌──────────┬──────────┐
│ 放电倍率 │ 相对容量 │
├──────────┼──────────┤
│ 0.2C │ 100% │
├──────────┼──────────┤
│ 0.5C │ 98% │
├──────────┼──────────┤
│ 1C │ 95% │
├──────────┼──────────┤
│ 2C │ 88% │
├──────────┼──────────┤
│ 3C │ 80% │
└──────────┴──────────┘
如果用户经常大电流放电,测得的容量会偏低,但这不代表真实老化。
改进方向:
只在小电流(<0.5C)时进行容量学习:
void CapacityLearningTask(void) {
s16 curr = GetGSampOutCurrAPI();
u32 ratedCap = GetGroupRatedCapAPI();
// 计算当前倍率
u16 cRate = ABS(curr, 0) * 1000 / ratedCap; // 单位:千分之一C
// 只在小电流时学习
if(cRate < 500) { // <0.5C
// 执行容量学习
// ...
}
}
6.3 日历老化的缺失
电池即使不使用,也会随时间老化。典型的日历老化速率是每年2-3%。
问题:
如果电池长期存储(如共享单车冬季入库),循环次数不增加,但容量会下降。当前算法无法捕捉这种老化。
改进方向:
引入时间因子:
u16 GetGTimSohWithCalendar(void) {
u16 cycleSoh = GetGTimSohTenthAPI();
u32 days = GetSystemRunDays(); // 系统运行天数
// 日历老化:每年衰减2%
u16 calendarFade = days * 20 / 365; // 单位:千分之一
u16 totalSoh = 1000 - calendarFade;
// 取两者较小值
return (cycleSoh < totalSoh) ? cycleSoh : totalSoh;
}
6.4 非线性衰减的简化
实际的容量衰减曲线是非线性的:
初期(0-200次循环):快速衰减,SOH从100%降到95%
中期(200-1500次循环):缓慢衰减,SOH从95%降到85%
后期(1500-2000次循环):加速衰减,SOH从85%降到80%
当前的线性模型无法反映这种特征。
改进方向:
采用分段线性或指数模型:
u16 GetGTimSohNonlinear(void) {
u32 fadeCycle = GetGroupFadeCycleAPI();
u32 ratedCycle = GetGroupRatedCycleAPI();
u16 soh = 1000;
if(fadeCycle < ratedCycle / 10) { // 前10%循环
// 快速衰减:5%
soh = 1000 - fadeCycle * 500 / (ratedCycle / 10);
} else if(fadeCycle < ratedCycle * 3 / 4) { // 中间65%循环
// 缓慢衰减:10%
soh = 950 - (fadeCycle - ratedCycle / 10) * 100 / (ratedCycle * 65 / 100);
} else { // 后25%循环
// 加速衰减:5%
soh = 850 - (fadeCycle - ratedCycle * 3 / 4) * 50 / (ratedCycle / 4);
}
return soh;
}
6.5 SOH与SOC的耦合问题
当前实现中,SOH计算依赖于准确的SOC。但SOC本身也依赖于容量(即SOH)。这形成了循环依赖:
SOC = 当前容量 / 总容量
总容量 = f(SOH)
SOH = f(总容量)
改进方向:
采用迭代收
void SohSocIterativeUpdate(void) { u16 soh_old = GetGSohTenthAPI();
u16 soc_old = GetGRealSocMilliAPI(); u16 soh_new = 0; u16 soc_new = 0;
// 迭代3次收敛
for(u8 i = 0; i < 3; i++) {
// 基于当前SOH更新容量
u32 totalCap = GetGroupRatedCapAPI() * soh_old / 1000;
// 基于新容量更新SOC
soc_new = GetGroupNowCapAPI() * 1000 / totalCap;
// 基于新SOC重新计算容量
u32 learnedCap = GetAccumulatedCap() * 1000 / soc_new;
// 基于新容量更新SOH
soh_new = learnedCap * 1000 / GetGroupRatedCapAPI();
// 检查收敛
if((ABS(soh_new, soh_old) < 1) && (ABS(soc_new, soc_old) < 1)) {
break; // 收敛,退出迭代
}
soh_old = soh_new;
soc_old = soc_new;
}
// 更新最终结果
UpdateSohValue(soh_new);
UpdateSocValue(soc_new);
}
七、实际应用中的SOH表现
7.1 典型衰减曲线
基于该算法在实际项目中的数据,一个200Ah磷酸铁锂电池包的SOH变化:
时间(月) 循环次数 容量实测SOH 循环计数SOH 融合SOH 备注
0 0 100.0% 100.0% 100.0% 出厂状态
3 120 98.5% 98.8% 98.8% 初期快速衰减
6 280 97.2% 97.2% 97.2% 进入稳定期
12 600 95.1% 94.0% 94.6% 容量实测偏高
18 950 92.8% 90.5% 91.7% 差异增大
24 1350 89.5% 86.5% 88.0% 取平均值
30 1720 86.2% 82.8% 84.5% 接近寿命末期
36 2050 82.1% 79.5% 80.8% 达到换电阈值
可以看到:
- 前6个月:两种方法高度一致,融合算法主要采用循环计数法
- 6-18个月:容量实测略高于循环计数(可能是温度、倍率等因素)
- 18个月后:差异增大,融合算法取平均值,起到平滑作用
- 36个月:SOH降至80%,触发换电预警
7.2 异常场景处理
场景1:冬季低温
时间 环境温度 容量实测SOH 循环计数SOH 融合SOH 处理策略
11月 15℃ 94.5% 94.0% 94.3% 正常
12月 -5℃ 86.2% 93.5% 89.9% 低温,取平均
1月 -10℃ 82.1% 93.0% 87.6% 继续低温
2月 5℃ 93.8% 92.5% 87.6% 温度恢复,SOH不回升
融合算法成功避免了低温导致的SOH误判,保持了单调递减特性。
场景2:传感器故障
时间 容量实测SOH 循环计数SOH 融合SOH 处理策略
正常 94.5% 94.0% 94.3% 正常运行
故障瞬间 65.2% 93.8% 79.5% 传感器异常,取平均
故障持续 62.8% 93.6% 78.2% 限制下降速度
故障恢复 94.2% 93.4% 78.2% SOH不回升,保持最低值
虽然传感器故障导致容量实测异常,但融合算法通过平均值和变化率限制,将影响控制在可接受范围内。
场景3:大倍率放电
使用场景 容量实测SOH 循环计数SOH 融合SOH 说明
正常使用(0.5C) 94.5% 94.0% 94.3% 基准状态
急加速(2C) 88.2% 93.8% 91.0% 大倍率导致容量降低
持续高速(1.5C) 90.1% 93.6% 91.0% SOH不回升
恢复正常(0.5C) 94.3% 93.4% 91.0% 容量恢复,SOH保持
大倍率放电导致的容量降低被识别为异常,不会导致SOH误判。
7.3 不同电池化学体系的表现
该算法在不同电池类型上的适用性:
磷酸铁锂(LFP):
- 循环寿命长(3000-5000次)
- 衰减曲线平缓
- 线性模型拟合较好
- 适配性:★★★★★
三元锂(NCM):
- 循环寿命中等(1500-2500次)
- 初期衰减快,后期平缓
- 线性模型有偏差
- 适配性:★★★☆☆(建议改用非线性模型)
钛酸锂(LTO):
- 循环寿命极长(10000+次)
- 衰减极慢
- 容量实测法收敛慢
- 适配性:★★★★☆(循环计数法更适用)
铅酸电池:
- 循环寿命短(300-500次)
- 衰减快且非线性
- 温度影响大
- 适配性:★★☆☆☆(需要大幅修改参数)
八、SOH在BMS系统中的应用
8.1 功率限制动态调整
SOH降低意味着内阻增大,需要降低充放电功率:
u16 CalcMaxDischargeCurrent(void) {
u16 soh = GetGSohTenthAPI();
u16 baseCurr = GetRatedDischargeCurrent();
u16 maxCurr = baseCurr;
// SOH < 90%时开始限流
if(soh < 900) {
// 线性降额:SOH每降低1%,电流降低2%
maxCurr = baseCurr * soh / 900;
}
// SOH < 80%时强制限流
if(soh < 800) {
maxCurr = baseCurr * 60 / 100; // 限制到60%
}
return maxCurr;
}
8.2 充电策略优化
老化电池需要更温和的充电策略:
void AdaptiveChargingStrategy(void) {
u16 soh = GetGSohTenthAPI();
if(soh >= 950) {
// 健康电池:快充策略
SetChargeVoltage(4.20); // 满充
SetChargeCurrent(1.0); // 1C
} else if(soh >= 900) {
// 轻度老化:标准策略
SetChargeVoltage(4.15); // 略降
SetChargeCurrent(0.8); // 0.8C
} else if(soh >= 850) {
// 中度老化:保守策略
SetChargeVoltage(4.10); // 明显降低
SetChargeCurrent(0.5); // 0.5C
} else {
// 重度老化:保护策略
SetChargeVoltage(4.05); // 大幅降低
SetChargeCurrent(0.3); // 0.3C
SetWarningFlag(BATTERY_AGING_WARNING);
}
}
8.3 续航里程修正
SOH直接影响续航预测:
u16 EstimateRemainingRange(void) {
u16 soc = GetGRealSocMilliAPI();
u16 soh = GetGSohTenthAPI();
u16 ratedRange = GetRatedRange(); // 额定续航(km)
// 可用续航 = 额定续航 × SOC × SOH
u16 range = ratedRange * soc / 1000 * soh / 1000;
// 温度修正
s16 temp = GetGAvgTempAPI();
if(temp < 0) {
range = range * (100 + temp) / 100; // 低温降额
}
// 驾驶习惯修正(基于历史能耗)
u16 avgConsumption = GetAvgEnergyConsumption();
u16 ratedConsumption = GetRatedEnergyConsumption();
range = range * ratedConsumption / avgConsumption;
return range;
}
8.4 质保判定与预警
void WarrantyAndWarningCheck(void) {
u16 soh = GetGSohTenthAPI();
u32 days = GetSystemRunDays();
u32 mileage = GetTotalMileage();
// 质保期内SOH检查
if((days < 365 * 8) && (mileage < 150000)) { // 8年或15万公里
if(soh < 700) { // SOH < 70%
SetFaultCode(FAULT_WARRANTY_SOH_LOW);
NotifyServiceCenter();
}
}
// 分级预警
if(soh < 850) {
SetWarningLevel(WARNING_LEVEL_1); // 一级预警:建议检查
}
if(soh < 820) {
SetWarningLevel(WARNING_LEVEL_2); // 二级预警:限制性能
}
if(soh < 800) {
SetWarningLevel(WARNING_LEVEL_3); // 三级预警:强制换电
LimitVehicleSpeed(80); // 限速80km/h
}
}
8.5 梯次利用评估
typedef enum {
BATTERY_GRADE_A, // SOH > 90%,可继续车用
BATTERY_GRADE_B, // 80% < SOH ≤ 90%,可梯次利用(储能)
BATTERY_GRADE_C, // 70% < SOH ≤ 80%,可低功率应用
BATTERY_GRADE_D, // SOH ≤ 70%,建议回收
} BatteryGrade_e;
BatteryGrade_e EvaluateBatteryGrade(void) {
u16 soh = GetGSohTenthAPI();
u32 cycle = GetGroupFadeCycleAPI();
u16 consistency = EvaluateCellConsistency(); // 一致性评估
// SOH是主要指标
if(soh > 900) {
return BATTERY_GRADE_A;
} else if(soh > 800) {
// 还需检查一致性
if(consistency > 950) { // 一致性好
return BATTERY_GRADE_B;
} else {
return BATTERY_GRADE_C; // 一致性差,降级
}
} else if(soh > 700) {
return BATTERY_GRADE_C;
} else {
return BATTERY_GRADE_D;
}
}
九、工程实践经验总结
9.1 参数标定的重要性
SOH算法的准确性高度依赖于参数标定:
关键参数:
- 额定循环寿命(ratedCycle)
- 需要通过循环寿命测试确定
- 不同批次电池可能有差异
- 建议:保守取值,留有余量 - EOL SOH阈值
- 代码中硬编码为80%
- 不同应用场景可能不同(车用vs储能)
- 建议:可配置参数 - 融合阈值(5%)
- 影响两种方法的切换逻辑
- 需要根据实际数据调优
- 建议:3-8%之间 - 变化率限制(0.5%)
- 影响异常检测的灵敏度
- 过小会导致响应慢,过大会漏检异常
- 建议:0.3-1.0%之间
9.2 测试验证方法
方法1:加速老化测试
测试条件:
- 温度:45℃(加速老化)
- 倍率:1C充放电
- DOD:100%(全循环)
- 周期:每天10次循环
验证指标:
- SOH曲线与实测容量的拟合度
- 融合算法的稳定性
- 异常场景的鲁棒性
方法2:实车路试
测试场景:
- 城市工况(频繁启停)
- 高速工况(恒速巡航)
- 山路工况(大功率爬坡)
- 极端温度(-20℃ ~ 50℃)
验证指标:
- SOH与实际续航的相关性
- 温度影响的补偿效果
- 用户体验(SOH跳变频率)
方法3:长期监控
监控周期:2-3年
数据采集:
- 每次循环的SOH值
- 容量实测值
- 环境温度
- 充放电倍率
- 故障记录
分析维度:
- SOH预测准确性
- 异常检测召回率
- 算法改进方向
9.3 常见问题与解决方案
问题1:SOH初始值不是100%
现象:新电池上电后SOH显示98%
原因:出厂容量略高于额定容量(如105Ah vs 100Ah)
解决:初始化时强制设为100%
void GroupFadeSohInit(void) {
if(GetGroupFadeCycleAPI() == 0) { // 全新电池
sFadeInfo.soh = 1000; // 强制100%
} else {
// 从EEPROM读取
}
}
问题2:SOH在低温下异常下降
现象:冬季SOH从95%降到85%,春季恢复到90%
原因:未进行温度补偿
解决:低温下暂停容量学习
if(GetGAvgTempAPI() < 5) { // 低于5℃
DisableCapacityLearning();
}
问题3:SOH下降过快
现象:200次循环后SOH降到90%(预期应为98%)
原因:
- 大倍率放电导致容量测量偏低
- 循环计数模型参数不准确
解决: - 限制容量学习的倍率条件
- 重新标定额定循环寿命参数
问题4:SOH长期不更新
现象:用户使用半年,SOH一直显示100%
原因:用户从不完整充放电,容量学习无法触发
解决:降低容量学习的触发条件
// 原条件:充到100%或放到0%
// 新条件:充到95%或放到5%即可触发
if((soc >= 950) || (soc <= 50)) {
TriggerCapacityLearning();
}
9.4 未来改进方向
方向1:机器学习模型
数据输入:
- 历史SOH曲线
- 温度曲线
- 充放电倍率
- 电压曲线特征
模型输出:
- SOH预测值
- 剩余寿命预测
- 异常检测
优势:
- 自适应不同使用场景
- 捕捉非线性特征
- 提前预警异常
方向2:云端大数据分析
架构:
- 车端:实时SOH计算
- 云端:大数据建模
云端功能:
- 同批次电池对比
- 异常电池识别
- 模型参数优化
- OTA更新算法
优势:
- 利用海量数据
- 持续优化算法
- 个性化建模
方向3:多物理量融合
除了容量和循环次数,还可以融合:
- 内阻增长率
- 自放电率
- 充电曲线变化
- 交流阻抗谱
优势:
- 更全面的健康评估
- 更早期的故障预警
- 更准确的寿命预测
十、结语
SOH估算是BMS中最具挑战性的功能之一。它不像SOC那样有明确的物理定义和测量方法,而是需要在有限的数据、不确定的使用条件下,推断电池的长期健康状态。
本文基于真实的车规级BMS项目,展示了容量实测法和循环计数法的双重验证策略。这种融合方法虽然简单,但在工程实践中被证明是有效的:
- 容量实测法提供了准确性,确保SOH反映真实容量
- 循环计数法提供了稳定性,避免单次测量误差
- 融合策略提供了鲁棒性,在异常场景下保持合理输出
然而,我们也看到了当前实现的局限:缺少温度补偿、倍率补偿、日历老化模型。这些都是未来改进的方向。
在实际应用中,SOH不仅是一个数字,更是连接电池状态与用户体验的桥梁。它影响着续航预测、充电策略、安全预警、质保判定等多个环节。一个优秀的SOH算法,需要在准确性、稳定性、实时性之间找到平衡,更需要在理论模型与工
程约束之间找到最优解。
随着电池技术的发展和数据积累的增加,SOH估算算法也在不断演进。从简单的线性模型,到复杂的机器学习模型;从单车独立计算,到云端大数据分析。但无论技术如何进步,对电池物理特性的深刻理解、对工程细节的精心打磨,始终是算法成功的基石。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)