锂电池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);
  }

容量学习的逻辑是:

  1. 充电学习:从某个SOC充到100%,记录充入电量ΔQ_chg,推算总容量
  2. 放电学习:从某个SOC放到0%,记录放出电量ΔQ_dhg,推算总容量
  3. 完整循环学习:从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 容量实测法的优势与局限

优势:

  1. 直接测量:不依赖模型假设,反映真实容量
  2. 自适应:能够跟踪电池的实际老化过程
  3. 可验证:可以通过离线容量测试验证准确性

局限:

  1. 数据收敛慢:需要多次完整循环才能得到稳定结果
  2. 使用场景受限:用户很少进行0-100%的完整循环
  3. 温度影响:低温下测得的容量偏小,但不代表真实老化
  4. 倍率影响:大电流放电容量低,需要倍率补偿

正是因为这些局限,工程中需要引入第二种方法。

三、方法二:循环计数线性衰减模型

3.1 电池老化的经验模型

大量实验数据表明,锂电池的容量衰减大致遵循以下规律:

  1. 循环老化:每完成一次充放电循环,容量衰减一定比例
  2. 日历老化:即使不使用,容量也会随时间缓慢衰减
  3. 非线性特征:初期衰减快,后期趋于平缓

在工程实践中,为了简化计算,常采用线性模型:

  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 循环计数法的优势与局限

优势:

  1. 实时性好:不需要等待完整循环,每次充放电都更新
  2. 计算简单:只需要累加器和除法运算
  3. 趋势稳定:不受单次测量误差影响

局限:

  1. 模型简化:线性模型无法反映实际的非线性衰减
  2. 忽略使用条件:高温、大倍率会加速老化,但模型未考虑
  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算法的准确性高度依赖于参数标定:

关键参数:

  1. 额定循环寿命(ratedCycle)
    - 需要通过循环寿命测试确定
    - 不同批次电池可能有差异
    - 建议:保守取值,留有余量
  2. EOL SOH阈值
    - 代码中硬编码为80%
    - 不同应用场景可能不同(车用vs储能)
    - 建议:可配置参数
  3. 融合阈值(5%)
    - 影响两种方法的切换逻辑
    - 需要根据实际数据调优
    - 建议:3-8%之间
  4. 变化率限制(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%)
原因:

  1. 大倍率放电导致容量测量偏低
  2. 循环计数模型参数不准确
    解决:
  3. 限制容量学习的倍率条件
  4. 重新标定额定循环寿命参数

问题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估算算法也在不断演进。从简单的线性模型,到复杂的机器学习模型;从单车独立计算,到云端大数据分析。但无论技术如何进步,对电池物理特性的深刻理解、对工程细节的精心打磨,始终是算法成功的基石。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐