欢迎光临
我们一直在努力

动力电池二阶RC等效电路模型及EKF:原理、公式推导

文章目录

    • 文章摘要
    • 前言
    • 一、二阶RC等效电路拓扑与元件物理意义
      • 1. 电路拓扑图
      • 2. 各元件对应电池内部电化学机理
      • 3. 二阶模型对比一阶Thevenin核心优势
    • 二、连续时间域完整公式推导(基尔霍夫KVL/KCL)
      • 2.1 端电压观测方程(KVL电压回路)
      • 2.2 极化电压微分方程(KCL电流分流)
      • 2.3 SOC安时积分状态方程
      • 2.4 连续时间状态空间标准形式
    • 三、离散化差分方程(车载MCU实时计算必备)
      • 3.1 离散状态转移方程
      • 3.2 离散观测方程
    • 四、模型参数辨识方法(工程落地核心)
      • 4.1 HPPC脉冲实验离线辨识(标定阶段使用)
      • 4.2 在线递推辨识(车载实时修正)
    • 五、二阶RC模型-BMS高精度SOC估算
    • 六、二阶RC模型优缺点总结
      • 优势
      • 局限性
    • 七、标准卡尔曼滤波(KF)基础原理
      • 7.1.1 核心思想
      • 7.2 离散线性系统标准模型
        • (1)状态转移方程(系统模型)
        • (2)观测方程(测量模型)
      • 7.3 卡尔曼滤波5条核心公式(完整推导)
        • 步骤1:状态先验预测(时间更新)
        • 步骤2:计算卡尔曼增益

          K

          k

          K_k

          Kk​(权重平衡)

        • 步骤3:状态后验更新(观测修正)
        • 步骤4:更新后验协方差矩阵
      • 7.4 标准KF局限性(电池场景无法直接使用)
    • 八、扩展卡尔曼滤波EKF原理(适配电池非线性)
      • 8.1 核心思路
      • 8.2 非线性离散系统通用模型
      • 8.3 雅可比矩阵定义
      • 8.4 EKF完整迭代五公式
    • 九、二阶RC等效电路ECM与EKF完整结合(工程核心)
      • 9.1 二阶RC电路模型结构
      • 9.2 构建EKF状态向量
      • 9.3 连续微分方程离散化(核心状态转移

        f

        (

        x

        ,

        u

        )

        f(x,u)

        f(x,u))

      • 9.4 观测方程

        h

        (

        x

        )

        h(\\boldsymbol{x})

        h(x)(非线性)

      • 9.5 求解雅可比矩阵(代入EKF)
        • (1)状态转移雅可比

          F

          (

          3

          ×

          3

          )

          \\boldsymbol{F}(3\\times3)

          F(3×3)

        • (2)观测雅可比矩阵

          H

          (

          1

          ×

          3

          )

          \\boldsymbol{H}(1\\times3)

          H(1×3)

      • 9.6 ECM-EKF完整迭代工程流程
        • 步骤1:初始化参数
        • 步骤2:EKF预测步(对应代码`_ekf_predict`)
        • 步骤3:EKF更新步(对应代码`_ekf_update`)
        • 步骤4:循环迭代
    • 十、ECM+EKF工程优势与传统方案对比
    • 十一、工程调参关键点
    • 十二、SOC估算工程实现-python代码

文章摘要

本文全面解析了动力电池二阶RC等效电路模型,这是当前新能源汽车和储能系统BMS(电池管理系统)中最主流的建模方案。文章从电化学机理出发,详细阐述了二阶RC模型的电路拓扑、各元件物理意义,并完整推导了连续时间域的状态空间方程和离散化差分方程。重点介绍了模型参数辨识的两种工业方法(HPPC脉冲实验离线辨识和在线递推辨识),以及该模型在BMS高精度SOC估算、电池故障诊断、SOH健康状态评估、整车仿真和充电控制优化等五大工程场景中的全链路应用。最后总结了二阶RC模型的优势与局限性,并展望了行业优化方向。本文为动力电池算法工程师提供了从理论到实践的完整技术参考。

前言

锂电池内部包含复杂电化学反应、离子扩散、欧姆损耗,无法直接测量内部极化、锂离子浓度等微观状态。工程上采用等效电路模型(ECM),用电阻、电容、电压源等效复现电池外部电压-电流动态特性,是BMS电池状态估算、故障诊断、仿真分析的核心基础。

主流ECM分为零阶(理想电压源)、一阶Thevenin、二阶RC、PNGV、高阶电化学模型。二阶RC模型是车企、储能行业的最优平衡点:相比一阶模型可同时捕捉快慢双尺度极化,电压拟合误差降低50%以上;相比高阶电化学模型计算量小、参数易辨识、可实时嵌入车载MCU,广泛用于电动车、储能电站BMS算法开发。

一、二阶RC等效电路拓扑与元件物理意义

1. 电路拓扑图

二阶RC电路拓扑图

2. 各元件对应电池内部电化学机理

元件物理含义时间常数特性电化学本质

U

O

C

V

(

S

O

C

)

U_{OCV}(SOC)

UOCV​(SOC)

开路电压,SOC非线性函数 静态无时间特性 正负极电极平衡电势,仅由剩余电量决定

R

0

R_0

R0​

欧姆内阻 毫秒级瞬时响应 集流体、极耳、电解液、隔膜的电子/离子传导阻力;通电瞬间立刻产生压降

R

1

、

C

1

R_1、C_1

R1​、C1​

快极化RC支路

τ

1

=

R

1

C

1

\\tau_1=R_1C_1

τ1​=R1​C1​,0.1~10s

电化学活化极化:电极界面电荷转移反应阻力,脉冲电流下电压快速升降

R

2

、

C

2

R_2、C_2

R2​、C2​

慢极化RC支路

τ

2

=

R

2

C

2

\\tau_2=R_2C_2

τ2​=R2​C2​,10~100s

浓差扩散极化:锂离子在电解液、电极孔隙扩散形成浓度梯度,电压缓慢弛豫恢复

U

1

、

U

2

U_1、U_2

U1​、U2​

两支路RC电容两端极化电压 – 电流作用下积累的极化压降,断电后缓慢释放、电压回弹

3. 二阶模型对比一阶Thevenin核心优势

一阶仅单RC支路,只能拟合单一时间尺度极化;真实电池同时存在快速界面反应、慢速离子扩散两种动态过程,脉冲充放电、动态工况下电压拟合误差大。二阶双RC支路分离快慢极化,HPPC脉冲、城市道路动态工况下端电压拟合误差可控制在30~50mV内,满足车载SOC、压差故障预警精度要求。

二、连续时间域完整公式推导(基尔霍夫KVL/KCL)

2.1 端电压观测方程(KVL电压回路)

沿电路闭合回路电压求和:开路电压减去欧姆压降、两级极化压降等于外部输出端电压:

U

L

=

U

O

C

V

(

S

O

C

)

−

I

R

0

−

U

1

−

U

2

(1)

U_L = U_{OCV}(SOC) – I R_0 – U_1 – U_2 \\tag{1}

UL​=UOCV​(SOC)−IR0​−U1​−U2​(1)

  • U

    L

    U_L

    UL​:电池外部采集端电压(BMS可直接测量)

  • I

    I

    I:充放电电流,放电

    I

    >

    0

    I>0

    I>0,充电

    I

    <

    0

    I<0

    I<0

  • U

    1

    、

    U

    2

    U_1、U_2

    U1​、U2​:快、慢RC支路电容极化电压

2.2 极化电压微分方程(KCL电流分流)

对

R

1

C

1

R_1C_1

R1​C1​并联支路:总电流分为电阻支路电流、电容充放电电流:

I

=

U

1

R

1

+

C

1

d

U

1

d

t

I = \\frac{U_1}{R_1} + C_1 \\frac{dU_1}{dt}

I=R1​U1​​+C1​dtdU1​​ 移项整理得到一阶微分方程,描述极化电压随时间变化规律:

d

U

1

d

t

=

−

1

R

1

C

1

U

1

+

1

C

1

I

(2)

\\frac{dU_1}{dt} = -\\frac{1}{R_1 C_1} U_1 + \\frac{1}{C_1} I \\tag{2}

dtdU1​​=−R1​C1​1​U1​+C1​1​I(2) 同理,慢极化支路:

d

U

2

d

t

=

−

1

R

2

C

2

U

2

+

1

C

2

I

(3)

\\frac{dU_2}{dt} = -\\frac{1}{R_2 C_2} U_2 + \\frac{1}{C_2} I \\tag{3}

dtdU2​​=−R2​C2​1​U2​+C2​1​I(3) 时间常数定义:

τ

1

=

R

1

C

1

,

τ

2

=

R

2

C

2

\\tau_1=R_1C_1,\\tau_2=R_2C_2

τ1​=R1​C1​,τ2​=R2​C2​,代入简化:

d

U

1

d

t

=

−

1

τ

1

U

1

+

I

C

1

,

d

U

2

d

t

=

−

1

τ

2

U

2

+

I

C

2

\\frac{dU_1}{dt} = -\\frac{1}{\\tau_1} U_1 + \\frac{I}{C_1},\\quad \\frac{dU_2}{dt} = -\\frac{1}{\\tau_2} U_2 + \\frac{I}{C_2}

dtdU1​​=−τ1​1​U1​+C1​I​,dtdU2​​=−τ2​1​U2​+C2​I​

2.3 SOC安时积分状态方程

剩余电量SOC随充放电电流变化,额定容量

Q

n

Q_n

Qn​(单位A·s):

d

S

O

C

d

t

=

−

I

Q

n

(4)

\\frac{dSOC}{dt} = -\\frac{I}{Q_n} \\tag{4}

dtdSOC​=−Qn​I​(4) 放电时

I

>

0

I>0

I>0,SOC下降;充电

I

<

0

I<0

I<0,SOC上升,符合电量守恒。

2.4 连续时间状态空间标准形式

定义三维状态向量(系统内部不可直接观测状态):

x

=

[

S

O

C

U

1

U

2

]

\\boldsymbol{x} = \\begin{bmatrix} SOC \\\\ U_1 \\\\ U_2 \\end{bmatrix}

x=

​SOCU1​U2​​

​ 输入量:

u

=

I

u=I

u=I;观测输出:

y

=

U

L

y=U_L

y=UL​ 状态微分方程:

d

x

d

t

=

[

0

0

0

0

−

1

τ

1

0

0

0

−

1

τ

2

]

x

+

[

−

1

Q

n

1

C

1

1

C

2

]

u

\\frac{d\\boldsymbol{x}}{dt} = \\begin{bmatrix} 0 & 0 & 0 \\\\ 0 & -\\displaystyle\\frac{1}{\\tau_1} & 0 \\\\ 0 & 0 & -\\displaystyle\\frac{1}{\\tau_2} \\end{bmatrix} \\boldsymbol{x} + \\begin{bmatrix} -\\displaystyle\\frac{1}{Q_n} \\\\ \\displaystyle\\frac{1}{C_1} \\\\ \\displaystyle\\frac{1}{C_2} \\end{bmatrix} u

dtdx​=

​000​0−τ1​1​0​00−τ2​1​​

​x+

​−Qn​1​C1​1​C2​1​​

​u 观测方程(非线性,

U

O

C

V

U_{OCV}

UOCV​是SOC非线性函数):

y

=

U

O

C

V

(

x

1

)

−

R

0

⋅

u

−

x

2

−

x

3

y = U_{OCV}(x_1) – R_0 \\cdot u – x_2 – x_3

y=UOCV​(x1​)−R0​⋅u−x2​−x3​

三、离散化差分方程(车载MCU实时计算必备)

BMS芯片为数字离散系统,采样周期

Δ

t

\\Delta t

Δt(通常100ms/1s),采用零阶保持ZOH离散化,假设一个采样周期内电流

I

I

I恒定。

3.1 离散状态转移方程

{

S

O

C

k

=

S

O

C

k

−

1

−

Δ

t

Q

n

I

k

−

1

U

1

,

k

=

exp

⁡

(

−

Δ

t

τ

1

)

U

1

,

k

−

1

+

R

1

[

1

−

exp

⁡

(

−

Δ

t

τ

1

)

]

I

k

−

1

U

2

,

k

=

exp

⁡

(

−

Δ

t

τ

2

)

U

2

,

k

−

1

+

R

2

[

1

−

exp

⁡

(

−

Δ

t

τ

2

)

]

I

k

−

1

\\begin{cases} SOC_k = SOC_{k-1} – \\displaystyle\\frac{\\Delta t}{Q_n} I_{k-1} \\\\[4pt] U_{1,k} = \\exp\\left(-\\displaystyle\\frac{\\Delta t}{\\tau_1}\\right) U_{1,k-1} + R_1 \\left[1-\\exp\\left(-\\displaystyle\\frac{\\Delta t}{\\tau_1}\\right)\\right] I_{k-1} \\\\[4pt] U_{2,k} = \\exp\\left(-\\displaystyle\\frac{\\Delta t}{\\tau_2}\\right) U_{2,k-1} + R_2 \\left[1-\\exp\\left(-\\displaystyle\\frac{\\Delta t}{\\tau_2}\\right)\\right] I_{k-1} \\end{cases}

⎩

⎨

⎧​SOCk​=SOCk−1​−Qn​Δt​Ik−1​U1,k​=exp(−τ1​Δt​)U1,k−1​+R1​[1−exp(−τ1​Δt​)]Ik−1​U2,k​=exp(−τ2​Δt​)U2,k−1​+R2​[1−exp(−τ2​Δt​)]Ik−1​​

3.2 离散观测方程

U

L

,

k

=

U

O

C

V

(

S

O

C

k

)

−

I

k

R

0

−

U

1

,

k

−

U

2

,

k

U_{L,k} = U_{OCV}(SOC_k) – I_k R_0 – U_{1,k} – U_{2,k}

UL,k​=UOCV​(SOCk​)−Ik​R0​−U1,k​−U2,k​ 离散方程组是EKF/UKF SOC估计算法、在线参数辨识的底层代码数学基础,可直接写成C语言嵌入BMS。

四、模型参数辨识方法(工程落地核心)

模型共5个待辨识参数:

R

0

、

R

1

、

C

1

、

R

2

、

C

2

R_0、R_1、C_1、R_2、C_2

R0​、R1​、C1​、R2​、C2​,主流两类工业方案:

4.1 HPPC脉冲实验离线辨识(标定阶段使用)

HPPC混合脉冲功率特性测试标准流程:

  • 固定SOC点(0.05、0.1、0.2…0.95),静置30min以上,记录稳定

    U

    O

    C

    V

    U_{OCV}

    UOCV​;

  • 施加3C放电脉冲10s,采集瞬时电压跌落;
  • 静置40s,记录电压双指数回弹曲线; 参数提取逻辑:
  • 脉冲通电瞬间电压跳变

    Δ

    V

    0

    =

    I

    ⋅

    R

    0

    \\Delta V_0=I\\cdot R_0

    ΔV0​=I⋅R0​,直接计算欧姆内阻

    R

    0

    R_0

    R0​;

  • 电压快速回弹段(0~30s)拟合得到

    τ

    1

    、

    R

    1

    、

    C

    1

    \\tau_1、R_1、C_1

    τ1​、R1​、C1​;

  • 慢速回弹段(30~120s)拟合得到

    τ

    2

    、

    R

    2

    、

    C

    2

    \\tau_2、R_2、C_2

    τ2​、R2​、C2​; 使用双指数函数拟合静置恢复电压:

    U

    (

    t

    )

    =

    U

    O

    C

    V

    −

    A

    e

    −

    t

    /

    τ

    1

    −

    B

    e

    −

    t

    /

    τ

    2

    U(t) = U_{OCV} – A e^{-t/\\tau_1} – B e^{-t/\\tau_2}

    U(t)=UOCV​−Ae−t/τ1​−Be−t/τ2​

  • 4.2 在线递推辨识(车载实时修正)

    车辆运行过程中,电池老化、温度变化会改变全部参数,采用带遗忘因子递推最小二乘FFRLS、多新息辨识,实时更新

    R

    0

    、

    R

    1

    、

    C

    1

    、

    R

    2

    、

    C

    2

    R_0、R_1、C_1、R_2、C_2

    R0​、R1​、C1​、R2​、C2​,适配SOH衰减、高低温工况。

    五、二阶RC模型-BMS高精度SOC估算

    SOC无法直接硬件测量,依靠二阶RC模型+扩展卡尔曼滤波EKF实现闭环估算:

  • 状态变量:

    S

    O

    C

    、

    U

    1

    、

    U

    2

    SOC、U_1、U_2

    SOC、U1​、U2​;观测值:BMS采集端电压;

  • 利用离散状态方程做时间预测步,安时积分初步更新SOC、极化电压;
  • 利用观测电压残差做测量更新步,修正SOC误差,抑制安时积分累积漂移;
  • 二阶模型精准复现极化压降,消除动态工况下电压偏差,SOC稳态误差≤3%,远优于一阶模型5%~8%误差。 配套落地:电动车续航里程计算、充电截止控制、均衡策略触发。
  • 六、二阶RC模型优缺点总结

    优势

  • 物理意义清晰,每个元件对应真实电化学过程,参数可通过实验标定;
  • 精度与算力平衡,双RC支路完美拟合快慢极化,误差远低于一阶模型;
  • 离散化方程简单,无复杂微分运算,低成本MCU可实时运行;
  • 适配全场景:SOC、SOH、故障诊断、系统仿真全覆盖;
  • 参数可离线标定+在线实时修正,适配温度、老化变工况。
  • 局限性

  • 属于等效黑盒模型,无法描述内部锂离子浓度、SEI膜生长微观机理,极致精度不如P2D电化学模型;
  • 忽略滞回电压(充放电OCV不重合),高精度场景需叠加滞回修正项;
  • 超低温、超大倍率工况下RC参数非线性变强,需建立温度-SOC多维参数查表。
  • 七、标准卡尔曼滤波(KF)基础原理

    7.1.1 核心思想

    卡尔曼滤波是线性最小均方差递归估计器,仅保存上一时刻状态,无需存储历史数据,适合嵌入式实时迭代。 核心逻辑分为两步:时间预测(Predict)+观测更新(Update)

    • 预测:依靠系统状态转移方程,推算当前状态先验值;
    • 更新:利用传感器实测观测值,计算卡尔曼增益修正先验,输出最优后验状态。

    假设条件:系统线性、噪声零均值高斯白噪声、过程噪声

    w

    k

    w_k

    wk​、观测噪声

    v

    k

    v_k

    vk​互不相关。

    7.2 离散线性系统标准模型

    (1)状态转移方程(系统模型)

    x

    k

    =

    A

    x

    k

    −

    1

    +

    B

    u

    k

    −

    1

    +

    w

    k

    −

    1

    \\boldsymbol{x}_k = \\boldsymbol{A}\\boldsymbol{x}_{k-1} + \\boldsymbol{B}\\boldsymbol{u}_{k-1} + \\boldsymbol{w}_{k-1}

    xk​=Axk−1​+Buk−1​+wk−1​

    • x

      k

      \\boldsymbol{x}_k

      xk​:k时刻n维状态向量

    • A

      \\boldsymbol{A}

      A:状态转移矩阵;

      B

      \\boldsymbol{B}

      B:控制输入矩阵;

      u

      \\boldsymbol{u}

      u:系统输入(电池电流)

    • w

      k

      −

      1

      \\boldsymbol{w}_{k-1}

      wk−1​:过程噪声,

      w

      ∼

      N

      (

      0

      ,

      Q

      )

      w\\sim N(0,\\boldsymbol{Q})

      w∼N(0,Q),

      Q

      \\boldsymbol{Q}

      Q为过程噪声协方差矩阵

    (2)观测方程(测量模型)

    z

    k

    =

    H

    x

    k

    +

    v

    k

    \\boldsymbol{z}_k = \\boldsymbol{H}\\boldsymbol{x}_k + \\boldsymbol{v}_k

    zk​=Hxk​+vk​

    • z

      k

      \\boldsymbol{z}_k

      zk​:传感器实测观测值(电池端电压)

    • H

      \\boldsymbol{H}

      H:观测矩阵;

      v

      k

      \\boldsymbol{v}_k

      vk​:观测噪声,

      v

      ∼

      N

      (

      0

      ,

      R

      )

      v\\sim N(0,\\boldsymbol{R})

      v∼N(0,R),

      R

      \\boldsymbol{R}

      R观测噪声协方差

    7.3 卡尔曼滤波5条核心公式(完整推导)

    目标:最小化状态估计误差协方差

    P

    =

    E

    [

    (

    x

    ^

    −

    x

    )

    (

    x

    ^

    −

    x

    )

    T

    ]

    \\boldsymbol{P}=E[(\\hat{x}-x)(\\hat{x}-x)^T]

    P=E[(x^−x)(x^−x)T]

    步骤1:状态先验预测(时间更新)

    用上一时刻最优估计

    x

    ^

    k

    −

    1

    ∣

    k

    −

    1

    \\hat{x}_{k-1|k-1}

    x^k−1∣k−1​预测当前先验状态:

    x

    ^

    k

    ∣

    k

    −

    1

    =

    A

    x

    ^

    k

    −

    1

    ∣

    k

    −

    1

    +

    B

    u

    k

    −

    1

    \\hat{\\boldsymbol{x}}_{k|k-1} = \\boldsymbol{A}\\hat{\\boldsymbol{x}}_{k-1|k-1} + \\boldsymbol{B}\\boldsymbol{u}_{k-1}

    x^k∣k−1​=Ax^k−1∣k−1​+Buk−1​ 同步预测误差协方差:

    P

    k

    ∣

    k

    −

    1

    =

    A

    P

    k

    −

    1

    ∣

    k

    −

    1

    A

    T

    +

    Q

    \\boldsymbol{P}_{k|k-1} = \\boldsymbol{A}\\boldsymbol{P}_{k-1|k-1}\\boldsymbol{A}^T + \\boldsymbol{Q}

    Pk∣k−1​=APk−1∣k−1​AT+Q

    P

    k

    ∣

    k

    −

    1

    \\boldsymbol{P}_{k|k-1}

    Pk∣k−1​代表先验状态的不确定度,

    Q

    \\boldsymbol{Q}

    Q越大,模型可信度越低。

    步骤2:计算卡尔曼增益

    K

    k

    K_k

    Kk​(权重平衡)

    增益作用:平衡模型预测与传感器测量可信度

    K

    k

    =

    P

    k

    ∣

    k

    −

    1

    H

    T

    (

    H

    P

    k

    ∣

    k

    −

    1

    H

    T

    +

    R

    )

    −

    1

    \\boldsymbol{K}_k = \\boldsymbol{P}_{k|k-1}\\boldsymbol{H}^T \\left( \\boldsymbol{H}\\boldsymbol{P}_{k|k-1}\\boldsymbol{H}^T + \\boldsymbol{R} \\right)^{-1}

    Kk​=Pk∣k−1​HT(HPk∣k−1​HT+R)−1

    • R

      \\boldsymbol{R}

      R大:传感器噪声大,

      K

      k

      K_k

      Kk​变小,更信任模型预测;

    • Q

      \\boldsymbol{Q}

      Q大:模型误差大,

      K

      k

      K_k

      Kk​变大,更信任电压测量值。

    步骤3:状态后验更新(观测修正)

    残差(创新):实测电压与模型预测电压差值

    e

    k

    =

    z

    k

    −

    H

    x

    ^

    k

    ∣

    k

    −

    1

    e_k=\\boldsymbol{z}_k-\\boldsymbol{H}\\hat{\\boldsymbol{x}}_{k|k-1}

    ek​=zk​−Hx^k∣k−1​

    x

    ^

    k

    ∣

    k

    =

    x

    ^

    k

    ∣

    k

    −

    1

    +

    K

    k

    e

    k

    \\hat{\\boldsymbol{x}}_{k|k} = \\hat{\\boldsymbol{x}}_{k|k-1} + \\boldsymbol{K}_k e_k

    x^k∣k​=x^k∣k−1​+Kk​ek​

    步骤4:更新后验协方差矩阵

    P

    k

    ∣

    k

    =

    (

    I

    −

    K

    k

    H

    )

    P

    k

    ∣

    k

    −

    1

    \\boldsymbol{P}_{k|k} = \\left( \\boldsymbol{I} – \\boldsymbol{K}_k \\boldsymbol{H} \\right)\\boldsymbol{P}_{k|k-1}

    Pk∣k​=(I−Kk​H)Pk∣k−1​

    I

    \\boldsymbol{I}

    I为单位矩阵,迭代后协方差持续收敛,估计误差逐步降低。

    7.4 标准KF局限性(电池场景无法直接使用)

    锂电池系统是强非线性系统:

  • O

    C

    V

    =

    f

    (

    S

    O

    C

    )

    OCV=f(SOC)

    OCV=f(SOC)为高度非线性曲线;

  • 内阻

    R

    0

    、

    R

    1

    、

    R

    2

    R_0、R_1、R_2

    R0​、R1​、R2​随SOC、温度动态变化;

  • 观测方程

    U

    t

    =

    O

    C

    V

    (

    S

    O

    C

    )

    −

    R

    0

    I

    −

    U

    1

    −

    U

    2

    U_t=OCV(SOC)-R_0I-U_1-U_2

    Ut​=OCV(SOC)−R0​I−U1​−U2​非线性。 标准KF仅适用于线性系统,因此电池SOC必须使用扩展卡尔曼滤波EKF。

  • 八、扩展卡尔曼滤波EKF原理(适配电池非线性)

    8.1 核心思路

    对非线性状态函数

    f

    (

    ⋅

    )

    f(\\cdot)

    f(⋅)、观测函数

    h

    (

    ⋅

    )

    h(\\cdot)

    h(⋅)在当前先验状态

    x

    ^

    k

    ∣

    k

    −

    1

    \\hat{x}_{k|k-1}

    x^k∣k−1​处一阶泰勒展开局部线性化,用雅可比矩阵替代线性矩阵

    A

    、

    H

    \\boldsymbol{A}、\\boldsymbol{H}

    A、H,其余KF迭代框架完全不变。

    8.2 非线性离散系统通用模型

    {

    x

    k

    =

    f

    (

    x

    k

    −

    1

    ,

    u

    k

    −

    1

    )

    +

    w

    k

    −

    1

    z

    k

    =

    h

    (

    x

    k

    )

    +

    v

    k

    \\begin{cases} \\boldsymbol{x}_k = f(\\boldsymbol{x}_{k-1},\\boldsymbol{u}_{k-1}) + \\boldsymbol{w}_{k-1} \\\\ \\boldsymbol{z}_k = h(\\boldsymbol{x}_k) + \\boldsymbol{v}_k \\end{cases}

    {xk​=f(xk−1​,uk−1​)+wk−1​zk​=h(xk​)+vk​​

    8.3 雅可比矩阵定义

  • 状态转移雅可比矩阵

    F

    k

    \\boldsymbol{F}_k

    Fk​(替代

    A

    \\boldsymbol{A}

    A)

    F

    k

    =

    ∂

    f

    ∂

    x

    ∣

    x

    ^

    k

    −

    1

    ∣

    k

    −

    1

    \\boldsymbol{F}_k = \\left. \\frac{\\partial f}{\\partial \\boldsymbol{x}} \\right|_{\\hat{x}_{k-1|k-1}}

    Fk​=∂x∂f​

    ​x^k−1∣k−1​​

  • 观测雅可比矩阵

    H

    k

    \\boldsymbol{H}_k

    Hk​(替代

    H

    \\boldsymbol{H}

    H)

    H

    k

    =

    ∂

    h

    ∂

    x

    ∣

    x

    ^

    k

    ∣

    k

    −

    1

    \\boldsymbol{H}_k = \\left. \\frac{\\partial h}{\\partial \\boldsymbol{x}} \\right|_{\\hat{x}_{k|k-1}}

    Hk​=∂x∂h​

    ​x^k∣k−1​​

  • 8.4 EKF完整迭代五公式

  • 先验状态预测:

    x

    ^

    k

    ∣

    k

    −

    1

    =

    f

    (

    x

    ^

    k

    −

    1

    ∣

    k

    −

    1

    ,

    u

    k

    −

    1

    )

    \\hat{\\boldsymbol{x}}_{k|k-1} = f(\\hat{\\boldsymbol{x}}_{k-1|k-1},\\boldsymbol{u}_{k-1})

    x^k∣k−1​=f(x^k−1∣k−1​,uk−1​)

  • 先验协方差预测:

    P

    k

    ∣

    k

    −

    1

    =

    F

    k

    P

    k

    −

    1

    ∣

    k

    −

    1

    F

    k

    T

    +

    Q

    \\boldsymbol{P}_{k|k-1} = \\boldsymbol{F}_k \\boldsymbol{P}_{k-1|k-1} \\boldsymbol{F}_k^T + \\boldsymbol{Q}

    Pk∣k−1​=Fk​Pk−1∣k−1​FkT​+Q

  • 卡尔曼增益:

    K

    k

    =

    P

    k

    ∣

    k

    −

    1

    H

    k

    T

    (

    H

    k

    P

    k

    ∣

    k

    −

    1

    H

    k

    T

    +

    R

    )

    −

    1

    \\boldsymbol{K}_k = \\boldsymbol{P}_{k|k-1}\\boldsymbol{H}_k^T \\left( \\boldsymbol{H}_k\\boldsymbol{P}_{k|k-1}\\boldsymbol{H}_k^T + \\boldsymbol{R} \\right)^{-1}

    Kk​=Pk∣k−1​HkT​(Hk​Pk∣k−1​HkT​+R)−1

  • 状态更新:

    x

    ^

    k

    ∣

    k

    =

    x

    ^

    k

    ∣

    k

    −

    1

    +

    K

    k

    (

    z

    k

    −

    h

    (

    x

    ^

    k

    ∣

    k

    −

    1

    )

    )

    \\hat{\\boldsymbol{x}}_{k|k} = \\hat{\\boldsymbol{x}}_{k|k-1} + \\boldsymbol{K}_k \\left( \\boldsymbol{z}_k – h(\\hat{\\boldsymbol{x}}_{k|k-1}) \\right)

    x^k∣k​=x^k∣k−1​+Kk​(zk​−h(x^k∣k−1​))

  • 协方差更新:

    P

    k

    ∣

    k

    =

    (

    I

    −

    K

    k

    H

    k

    )

    P

    k

    ∣

    k

    −

    1

    \\boldsymbol{P}_{k|k} = \\left( \\boldsymbol{I} – \\boldsymbol{K}_k \\boldsymbol{H}_k \\right)\\boldsymbol{P}_{k|k-1}

    Pk∣k​=(I−Kk​Hk​)Pk∣k−1​

  • 九、二阶RC等效电路ECM与EKF完整结合(工程核心)

    9.1 二阶RC电路模型结构

    二阶RC精准模拟电池电化学极化

    R

    1

    C

    1

    R_1C_1

    R1​C1​、浓差极化

    R

    2

    C

    2

    R_2C_2

    R2​C2​,电路组成:

    • O

      C

      V

      (

      S

      O

      C

      )

      OCV(SOC)

      OCV(SOC):开路电压源,SOC非线性映射

    • R

      0

      R_0

      R0​:欧姆内阻;

      R

      1

      ,

      C

      1

      R_1,C_1

      R1​,C1​、

      R

      2

      ,

      C

      2

      R_2,C_2

      R2​,C2​两级RC极化支路

    • I

      I

      I:电流(放电正、充电负);

      U

      t

      U_t

      Ut​:模组端电压

    基尔霍夫电压方程:

    U

    t

    =

    O

    C

    V

    (

    S

    O

    C

    )

    −

    I

    R

    0

    −

    U

    1

    −

    U

    2

    U_t = OCV(SOC) – I R_0 – U_1 – U_2

    Ut​=OCV(SOC)−IR0​−U1​−U2​

    U

    1

    、

    U

    2

    U_1、U_2

    U1​、U2​分别为两级RC电容极化电压。

    9.2 构建EKF状态向量

    选取3维状态变量:

    x

    =

    [

    S

    O

    C

    U

    1

    U

    2

    ]

    \\boldsymbol{x} = \\begin{bmatrix} SOC \\\\ U_1 \\\\ U_2 \\end{bmatrix}

    x=

    ​SOCU1​U2​​

    ​ 输入控制量:

    u

    =

    I

    u=I

    u=I(充放电电流);观测值

    z

    =

    U

    t

    ,

    m

    e

    a

    s

    z=U_{t,meas}

    z=Ut,meas​(实测端电压)

    9.3 连续微分方程离散化(核心状态转移

    f

    (

    x

    ,

    u

    )

    f(x,u)

    f(x,u))

    采样周期

    Δ

    t

    \\Delta t

    Δt,时间常数

    τ

    1

    =

    R

    1

    C

    1

    ,

    τ

    2

    =

    R

    2

    C

    2

    \\tau_1=R_1C_1,\\tau_2=R_2C_2

    τ1​=R1​C1​,τ2​=R2​C2​

  • SOC离散递推(安时积分,

    η

    \\eta

    η库伦效率,

    Q

    n

    Q_n

    Qn​额定容量Ah)

    S

    O

    C

    k

    =

    S

    O

    C

    k

    −

    1

    −

    η

    ⋅

    I

    k

    −

    1

    ⋅

    Δ

    t

    3600

    ⋅

    Q

    n

    SOC_{k} = SOC_{k-1} – \\frac{\\eta \\cdot I_{k-1} \\cdot \\Delta t}{3600 \\cdot Q_n}

    SOCk​=SOCk−1​−3600⋅Qn​η⋅Ik−1​⋅Δt​

  • 极化电压离散递推

    {

    U

    1

    ,

    k

    =

    e

    −

    Δ

    t

    /

    τ

    1

    U

    1

    ,

    k

    −

    1

    +

    R

    1

    (

    1

    −

    e

    −

    Δ

    t

    /

    τ

    1

    )

    I

    k

    −

    1

    U

    2

    ,

    k

    =

    e

    −

    Δ

    t

    /

    τ

    2

    U

    2

    ,

    k

    −

    1

    +

    R

    2

    (

    1

    −

    e

    −

    Δ

    t

    /

    τ

    2

    )

    I

    k

    −

    1

    \\begin{cases} U_{1,k} = e^{-\\Delta t/\\tau_1} U_{1,k-1} + R_1(1-e^{-\\Delta t/\\tau_1})I_{k-1} \\\\ U_{2,k} = e^{-\\Delta t/\\tau_2} U_{2,k-1} + R_2(1-e^{-\\Delta t/\\tau_2})I_{k-1} \\end{cases}

    {U1,k​=e−Δt/τ1​U1,k−1​+R1​(1−e−Δt/τ1​)Ik−1​U2,k​=e−Δt/τ2​U2,k−1​+R2​(1−e−Δt/τ2​)Ik−1​​ 合并得到非线性状态转移函数

    f

    (

    x

    ,

    I

    )

    f(\\boldsymbol{x},I)

    f(x,I):

    f

    (

    x

    k

    −

    1

    ,

    I

    k

    −

    1

    )

    =

    [

    S

    O

    C

    k

    −

    1

    −

    η

    I

    k

    −

    1

    Δ

    t

    3600

    Q

    n

    e

    −

    Δ

    t

    /

    τ

    1

    U

    1

    ,

    k

    −

    1

    +

    R

    1

    (

    1

    −

    e

    −

    Δ

    t

    /

    τ

    1

    )

    I

    k

    −

    1

    e

    −

    Δ

    t

    /

    τ

    2

    U

    2

    ,

    k

    −

    1

    +

    R

    2

    (

    1

    −

    e

    −

    Δ

    t

    /

    τ

    2

    )

    I

    k

    −

    1

    ]

    f(\\boldsymbol{x}_{k-1},I_{k-1})= \\begin{bmatrix} SOC_{k-1} – \\displaystyle\\frac{\\eta I_{k-1}\\Delta t}{3600 Q_n} \\\\ e^{-\\Delta t/\\tau_1}U_{1,k-1} + R_1(1-e^{-\\Delta t/\\tau_1})I_{k-1} \\\\ e^{-\\Delta t/\\tau_2}U_{2,k-1} + R_2(1-e^{-\\Delta t/\\tau_2})I_{k-1} \\end{bmatrix}

    f(xk−1​,Ik−1​)=

    ​SOCk−1​−3600Qn​ηIk−1​Δt​e−Δt/τ1​U1,k−1​+R1​(1−e−Δt/τ1​)Ik−1​e−Δt/τ2​U2,k−1​+R2​(1−e−Δt/τ2​)Ik−1​​

    ​

  • 9.4 观测方程

    h

    (

    x

    )

    h(\\boldsymbol{x})

    h(x)(非线性)

    h

    (

    x

    k

    )

    =

    O

    C

    V

    (

    S

    O

    C

    k

    )

    −

    I

    k

    R

    0

    −

    U

    1

    ,

    k

    −

    U

    2

    ,

    k

    h(\\boldsymbol{x}_k) = OCV(SOC_k) – I_k R_0 – U_{1,k} – U_{2,k}

    h(xk​)=OCV(SOCk​)−Ik​R0​−U1,k​−U2,k​ 输出为模型预测端电压,与实测电压

    z

    k

    =

    U

    t

    ,

    m

    e

    a

    s

    z_k=U_{t,meas}

    zk​=Ut,meas​做残差修正。

    9.5 求解雅可比矩阵(代入EKF)

    (1)状态转移雅可比

    F

    (

    3

    ×

    3

    )

    \\boldsymbol{F}(3\\times3)

    F(3×3)

    对

    f

    f

    f分别求

    S

    O

    C

    、

    U

    1

    、

    U

    2

    SOC、U_1、U_2

    SOC、U1​、U2​偏导,输入电流

    I

    I

    I仅为外部控制量,无偏导:

    F

    =

    [

    1

    0

    0

    0

    e

    −

    Δ

    t

    /

    τ

    1

    0

    0

    0

    e

    −

    Δ

    t

    /

    τ

    2

    ]

    \\boldsymbol{F}= \\begin{bmatrix} 1 & 0 & 0 \\\\ 0 & e^{-\\Delta t/\\tau_1} & 0 \\\\ 0 & 0 & e^{-\\Delta t/\\tau_2} \\end{bmatrix}

    F=

    ​100​0e−Δt/τ1​0​00e−Δt/τ2​​

    ​

    (2)观测雅可比矩阵

    H

    (

    1

    ×

    3

    )

    \\boldsymbol{H}(1\\times3)

    H(1×3)

    对

    h

    (

    x

    )

    h(\\boldsymbol{x})

    h(x)求各状态偏导,

    d

    O

    C

    V

    d

    S

    O

    C

    \\displaystyle\\frac{dOCV}{dSOC}

    dSOCdOCV​为OCV-SOC曲线在当前SOC处斜率:

    H

    =

    [

    d

    O

    C

    V

    d

    S

    O

    C

    ,

     

    −

    1

    ,

     

    −

    1

    ]

    \\boldsymbol{H}= \\left[ \\frac{dOCV}{dSOC},\\ -1,\\ -1 \\right]

    H=[dSOCdOCV​, −1, −1]

    工程关键点:充电、放电OCV曲线存在滞回,必须分开插值、分开计算

    d

    O

    C

    V

    /

    d

    S

    O

    C

    dOCV/dSOC

    dOCV/dSOC,否则电压拟合误差超80mV。

    9.6 ECM-EKF完整迭代工程流程

    步骤1:初始化参数
  • 状态初始值

    x

    ^

    0

    =

    [

    S

    O

    C

    0

    ,

     

    0

    ,

     

    0

    ]

    \\hat{x}_0=[SOC_0,\\ 0,\\ 0]

    x^0​=[SOC0​, 0, 0],静置时SOC由OCV查表得到;

  • 误差协方差

    P

    0

    =

    d

    i

    a

    g

    (

    [

    0.01

    ,

     

    1

    e

    −

    3

    ,

     

    1

    e

    −

    3

    ]

    )

    \\boldsymbol{P}_0=\\mathrm{diag}([0.01,\\ 1e-3,\\ 1e-3])

    P0​=diag([0.01, 1e−3, 1e−3]);

  • 过程噪声

    Q

    =

    d

    i

    a

    g

    (

    [

    1

    e

    −

    6

    ,

     

    1

    e

    −

    3

    ,

     

    1

    e

    −

    3

    ]

    )

    \\boldsymbol{Q}=\\mathrm{diag}([1e-6,\\ 1e-3,\\ 1e-3])

    Q=diag([1e−6, 1e−3, 1e−3]);

  • 观测噪声

    R

    =

    1

    e

    −

    3

    R=1e-3

    R=1e−3(电压传感器噪声);

  • HPPC参数插值函数:

    R

    0

    (

    S

    O

    C

    )

    、

    R

    1

    (

    S

    O

    C

    )

    、

    R

    2

    (

    S

    O

    C

    )

    、

    τ

    1

    (

    S

    O

    C

    )

    、

    τ

    2

    (

    S

    O

    C

    )

    R_0(SOC)、R_1(SOC)、R_2(SOC)、\\tau_1(SOC)、\\tau_2(SOC)

    R0​(SOC)、R1​(SOC)、R2​(SOC)、τ1​(SOC)、τ2​(SOC),区分充放电两套参数;

  • OCV插值函数:

    O

    C

    V

    c

    h

    a

    r

    g

    e

    (

    S

    O

    C

    )

    、

    O

    C

    V

    d

    i

    s

    c

    h

    a

    r

    g

    e

    (

    S

    O

    C

    )

    OCV_{charge}(SOC)、OCV_{discharge}(SOC)

    OCVcharge​(SOC)、OCVdischarge​(SOC)。

  • 步骤2:EKF预测步(对应代码_ekf_predict)
  • 根据上一时刻

    x

    ^

    k

    −

    1

    \\hat{x}_{k-1}

    x^k−1​、当前电流

    I

    k

    I_k

    Ik​,代入二阶RC离散公式计算先验

    x

    ^

    k

    ∣

    k

    −

    1

    \\hat{x}_{k|k-1}

    x^k∣k−1​;

  • 实时插值当前SOC对应的

    R

    0

    、

    R

    1

    、

    R

    2

    、

    τ

    1

    、

    τ

    2

    R_0、R_1、R_2、\\tau_1、\\tau_2

    R0​、R1​、R2​、τ1​、τ2​;

  • 计算状态转移雅可比

    F

    \\boldsymbol{F}

    F;

  • 更新先验协方差

    P

    k

    ∣

    k

    −

    1

    =

    F

    P

    k

    −

    1

    F

    T

    +

    Q

    \\boldsymbol{P}_{k|k-1}=\\boldsymbol{F}\\boldsymbol{P}_{k-1}\\boldsymbol{F}^T+\\boldsymbol{Q}

    Pk∣k−1​=FPk−1​FT+Q。

  • 步骤3:EKF更新步(对应代码_ekf_update)
  • 判断充放电,调取对应OCV插值函数,计算预测端电压

    h

    (

    x

    ^

    k

    ∣

    k

    −

    1

    )

    h(\\hat{x}_{k|k-1})

    h(x^k∣k−1​);

  • 计算OCV曲线导数

    d

    O

    C

    V

    /

    d

    S

    O

    C

    dOCV/dSOC

    dOCV/dSOC,构造观测雅可比

    H

    \\boldsymbol{H}

    H;

  • 计算残差

    y

    =

    U

    m

    e

    a

    s

    −

    U

    p

    r

    e

    d

    y=U_{meas}-U_{pred}

    y=Umeas​−Upred​;

  • 求解卡尔曼增益

    K

    K

    K;

  • 修正状态

    x

    ^

    k

    ∣

    k

    =

    x

    ^

    k

    ∣

    k

    −

    1

    +

    K

    ⋅

    y

    \\hat{x}_{k|k} = \\hat{x}_{k|k-1} + K\\cdot y

    x^k∣k​=x^k∣k−1​+K⋅y;

  • 后验协方差更新

    P

    k

    ∣

    k

    =

    (

    I

    −

    K

    H

    )

    P

    k

    ∣

    k

    −

    1

    \\boldsymbol{P}_{k|k}=(I-KH)P_{k|k-1}

    Pk∣k​=(I−KH)Pk∣k−1​;

  • 钳位

    S

    O

    C

    ∈

    [

    0

    ,

    1

    ]

    SOC\\in[0,1]

    SOC∈[0,1]、极化电压

    U

    1

    /

    U

    2

    ∈

    [

    −

    1

    ,

    1

    ]

    U_1/U_2\\in[-1,1]

    U1​/U2​∈[−1,1]防止数值发散。

  • 步骤4:循环迭代

    读取下一帧电流、电压采样,重复预测-更新,逐帧输出最优SOC、极化电压、模型估算端电压。

    十、ECM+EKF工程优势与传统方案对比

    估算方案优势缺陷
    纯安时积分 计算简单、无电压依赖 电流噪声长期累积漂移,无自校准能力
    开路电压法 静态SOC精度高 动态工况失效,必须长时间静置
    一阶RC+EKF 计算量小 无法区分两级极化,动态电压误差大
    二阶RC+EKF 1. 两级极化精准拟合充放电动态2. EKF实时修正积分误差3. 抑制电流/电压传感器噪声4. 支持初始SOC自收敛校准5. 适配动态DST、FUDS车载工况 计算量略大,需预辨识HPPC参数

    十一、工程调参关键点

  • 噪声矩阵Q/R调试
    • R

      R

      R增大:信任模型,电压修正权重降低,适合噪声大的廉价电压采集芯片;

    • Q

      Q

      Q增大:信任传感器,SOC收敛速度更快,但易受电压毛刺扰动;

  • HPPC参数分离 充电、放电极化特性不对称,必须两套插值表,共用参数会导致端电压RMSE>70mV;
  • OCV滞回处理 充放电OCV曲线分开存储,分别计算雅可比导数,消除充放电切换时SOC跳变;
  • 数值限幅 SOC、极化电压强制上下限钳位,大电流工况避免矩阵奇异、数值溢出;
  • 十二、SOC估算工程实现-python代码

    用二阶RC等效电路模型估算的端电压
    不包含内短路的等效电路模型、SOC估算
    """
    import random
    import os
    import pandas as pd
    import time
    import matplotlib.pyplot as plt
    from Funcs import *
    import warnings
    import seaborn as sns
    plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文显示为黑体
    plt.rcParams['axes.unicode_minus'] = False # 正确显示负号
    # 全局设置字体大小
    plt.rcParams.update({'font.size': 24}) # 设置全局字体大小为 14
    warnings.filterwarnings('ignore')
    import plotly.graph_objects as go
    from matplotlib.ticker import MultipleLocator, MaxNLocator
    from openpyxl import load_workbook
    from openpyxl.drawing.image import Image
    import io # 内存缓存图片,避免生成临时文件
    from datetime import datetime
    import numpy as np
    from scipy.interpolate import interp1d

    class Record(object):
    def __init__(self, output_path, fig_title):
    super(Record, self).__init__()
    self.normal_cap = 50
    self.output_path = output_path
    self.fig_title = fig_title

    self.capacity = 50 # 额定容量 (Ah)
    self.coulomb_efficiency = 1 # 库伦效率

    def pipeline(self, df_raw, param_data, ocv_data_d, ocv_data_c, file_name, down_sample_flag):
    """
    :param df_raw: 原始测试的模组循环数据
    :param param_data: HPPC参数数据
    :param ocv_data_d: 放电的OCV
    :param ocv_data_c: 充电的OCV
    :param file_name: 模组文件名
    :param down_sample_flag: true则执行降采样,否则不降采样
    :return:
    """
    print('———————————-数据清洗、打标志位—————————–')
    df_clean = df_raw_cleaning(df_raw) # 数据清洗
    df_clean = raw_status_mark(df_clean)
    df_clean = interval_mark(df_clean)
    df_clean = self.del_index(df_clean)

    print('———————————-选择HPPC参数、OCV参数———————-')
    hppc_param_data_c = param_data[param_data['type'] == 'c'].reset_index(drop=True)
    hppc_param_data_d = param_data[param_data['type'] == 'd'].reset_index(drop=True)
    hppc_numbers = param_data['number'].unique().tolist() # 总共有几组HPPC参数数据
    ocv_d_numbers = ocv_data_d['number'].unique().tolist() # 放电OCV参数数据组数
    ocv_c_numbers = ocv_data_c['number'].unique().tolist() # 充电OCV参数数据组数
    ocv_data_d = ocv_data_d[ocv_data_d['number'] == 1].reset_index(drop=True)
    ocv_data_c = ocv_data_c[ocv_data_c['number'] == 1].reset_index(drop=True)

    df_clean_copy = df_clean.copy()
    if down_sample_flag: # true则执行,否则不降采样
    print('———————————-数据降采样————————-')
    drop_rows_c = random.randint(200, 300) # 0.2-0.4
    df_clean_copy = self.down_sampling(df_clean, drop_rows_c)

    estimation_df_all = pd.DataFrame()
    count = 1
    for hppc_number in hppc_numbers: # 3 * 7 * 3
    if hppc_number not in [1]:
    continue
    print('———————————–hppc_number:', hppc_number)
    param_data_c = hppc_param_data_c[hppc_param_data_c['number'] == hppc_number].reset_index(drop=True)
    param_data_d = hppc_param_data_d[hppc_param_data_d['number'] == hppc_number].reset_index(drop=True)

    # 存储模型参数并创建插值函数
    self.param_data_c = param_data_c.sort_values('SOC')
    self.param_data_d = param_data_d.sort_values('SOC')
    self.soc_values = self.param_data_c['SOC'].values

    # 创建各参数的SOC插值函数
    self.R0_func_c = interp1d(self.soc_values, self.param_data_c['R0'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R1_func_c = interp1d(self.soc_values, self.param_data_c['R1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R2_func_c = interp1d(self.soc_values, self.param_data_c['R2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau1_func_c = interp1d(self.soc_values, self.param_data_c['tau1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau2_func_c = interp1d(self.soc_values, self.param_data_c['tau2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    self.R0_func_d = interp1d(self.soc_values, self.param_data_d['R0'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R1_func_d = interp1d(self.soc_values, self.param_data_d['R1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R2_func_d = interp1d(self.soc_values, self.param_data_d['R2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau1_func_d = interp1d(self.soc_values, self.param_data_d['tau1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau2_func_d = interp1d(self.soc_values, self.param_data_d['tau2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    # 处理OCV-SOC映射关系
    self.ocv_soc_data_d = ocv_data_d.sort_values('SOC')
    self.ocv_func_d = interp1d(self.ocv_soc_data_d['SOC'].values, self.ocv_soc_data_d['OCV'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.soc_from_ocv_func_d = interp1d(self.ocv_soc_data_d['OCV'].values, self.ocv_soc_data_d['SOC'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    # 处理OCV-SOC映射关系
    self.ocv_soc_data_c = ocv_data_c.sort_values('SOC')
    self.ocv_func_c = interp1d(self.ocv_soc_data_c['SOC'].values, self.ocv_soc_data_c['OCV'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.soc_from_ocv_func_c = interp1d(self.ocv_soc_data_c['OCV'].values, self.ocv_soc_data_c['SOC'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    # ——————————————record数据生成——————————————
    estimation_df, true_df = self.process_data(df_clean_copy)
    estimation_df = estimation_df.iloc[10:, :].reset_index(drop=True) # 删除前面10行数据
    estimation_df = self.static_data_process(estimation_df) # 充电后静置几帧处理,放电后静置几帧处理
    estimation_df = self.run_key_info(estimation_df)
    final_cols = ['数据序号', '循环号', '工步号', '工步序号', '工步类型', '工步时间', '绝对时间', '总时间', '电压(V)', '电流(A)',
    '容量(Ah)', '充电容量(Ah)', '放电容量(Ah)', '功率(mW)', '能量(Wh)', '充电能量(Wh)', '放电能量(Wh)',
    'V1辅助通道电压(V)', 'V2辅助通道电压(V)', 'V3辅助通道电压(V)', 'V4辅助通道电压(V)', 'V5辅助通道电压(V)',
    'V6辅助通道电压(V)', 'V7辅助通道电压(V)', 'V8辅助通道电压(V)', 'V9辅助通道电压(V)', 'V10辅助通道电压(V)',
    'V11辅助通道电压(V)', 'V12辅助通道电压(V)', 'V13辅助通道电压(V)', 'V14辅助通道电压(V)', 'V15辅助通道电压(V)',
    'V16辅助通道电压(V)', 'V17辅助通道电压(V)', 'V18辅助通道电压(V)', 'V19辅助通道电压(V)', 'V20辅助通道电压(V)',
    'V21辅助通道电压(V)', 'V22辅助通道电压(V)', 'T1辅助通道温度(℃)', 'T2辅助通道温度(℃)',
    'T3辅助通道温度(℃)', 'T4辅助通道温度(℃)', 'T5辅助通道温度(℃)', 'T6辅助通道温度(℃)']
    estimation_df = estimation_df[final_cols]
    return df_clean, estimation_df_all

    def pipeline_cut(self, df_raw, param_data, ocv_data_d, ocv_data_c, file_name, down_sample_flag):
    """循环片段随机裁切,重组生成多样化仿真数据"""
    print('———————————-数据清洗、打标志位—————————–')
    df_clean = df_raw_cleaning(df_raw) # 数据清洗
    df_clean = raw_status_mark(df_clean)
    df_clean = interval_mark(df_clean)
    df_clean = self.del_index(df_clean) # 删除充电后3帧静置,放电后3帧静置

    print('———————————-选择HPPC参数、OCV参数———————-')
    hppc_param_data_c = param_data[param_data['type'] == 'c'].reset_index(drop=True)
    hppc_param_data_d = param_data[param_data['type'] == 'd'].reset_index(drop=True)
    hppc_numbers = param_data['number'].unique().tolist() # 总共有几组HPPC参数数据
    ocv_d_numbers = ocv_data_d['number'].unique().tolist() # 放电OCV参数数据组数
    ocv_c_numbers = ocv_data_c['number'].unique().tolist() # 充电OCV参数数据组数
    ocv_data_d = ocv_data_d[ocv_data_d['number'] == 1].reset_index(drop=True)
    ocv_data_c = ocv_data_c[ocv_data_c['number'] == 1].reset_index(drop=True)

    # 遍历每一个电芯
    estimation_df_all, true_df_all = pd.DataFrame(), pd.DataFrame()
    count = 1

    print('—————————循环数据截取组合————————–')
    groups = self.cut_cycle_dict()
    for group_key, group_value in groups.items():
    data_copy = df_clean[df_clean['循环号'].isin(list(group_value))].reset_index(drop=True)
    last_cycle = data_copy['循环号'].max()
    data_copy = pd.concat([data_copy[data_copy['循环号'] != last_cycle],
    data_copy[(data_copy['循环号'] == last_cycle) &
    (data_copy["容量(Ah)"] <= 15) &
    (data_copy["工步类型"].str.contains("充电"))]])
    if down_sample_flag: # true则执行,否则不降采样
    print('———————————-数据降采样————————-')
    drop_rows_c = random.randint(50, 100)
    data_copy = self.down_sampling(df_clean, drop_rows_c)

    hppc_number_ls = [1, 2, 3, 4, 5, 7, 8]
    hppc_number = random.choice(hppc_number_ls)
    print('———————————–hppc_number:', hppc_number)
    param_data_c = hppc_param_data_c[hppc_param_data_c['number'] == hppc_number].reset_index(drop=True)
    param_data_d = hppc_param_data_d[hppc_param_data_d['number'] == hppc_number].reset_index(drop=True)

    # 存储模型参数并创建插值函数
    self.param_data_c = param_data_c.sort_values('SOC')
    self.param_data_d = param_data_d.sort_values('SOC')
    self.soc_values = self.param_data_c['SOC'].values

    # 创建各参数的SOC插值函数
    self.R0_func_c = interp1d(self.soc_values, self.param_data_c['R0'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R1_func_c = interp1d(self.soc_values, self.param_data_c['R1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R2_func_c = interp1d(self.soc_values, self.param_data_c['R2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau1_func_c = interp1d(self.soc_values, self.param_data_c['tau1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau2_func_c = interp1d(self.soc_values, self.param_data_c['tau2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    self.R0_func_d = interp1d(self.soc_values, self.param_data_d['R0'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R1_func_d = interp1d(self.soc_values, self.param_data_d['R1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.R2_func_d = interp1d(self.soc_values, self.param_data_d['R2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau1_func_d = interp1d(self.soc_values, self.param_data_d['tau1'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.tau2_func_d = interp1d(self.soc_values, self.param_data_d['tau2'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    # 处理OCV-SOC映射关系
    self.ocv_soc_data_d = ocv_data_d.sort_values('SOC')
    self.ocv_func_d = interp1d(self.ocv_soc_data_d['SOC'].values, self.ocv_soc_data_d['OCV'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.soc_from_ocv_func_d = interp1d(self.ocv_soc_data_d['OCV'].values, self.ocv_soc_data_d['SOC'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    # 处理OCV-SOC映射关系
    self.ocv_soc_data_c = ocv_data_c.sort_values('SOC')
    self.ocv_func_c = interp1d(self.ocv_soc_data_c['SOC'].values, self.ocv_soc_data_c['OCV'].values, kind='linear', bounds_error=False, fill_value="extrapolate")
    self.soc_from_ocv_func_c = interp1d(self.ocv_soc_data_c['OCV'].values, self.ocv_soc_data_c['SOC'].values, kind='linear', bounds_error=False, fill_value="extrapolate")

    estimation_df, true_df = self.process_data(data_copy)
    estimation_df = estimation_df.iloc[10:, :].reset_index(drop=True) # 删除前面10行数据
    estimation_df = self.static_data_process(estimation_df) # 充电后静置几帧处理,放电后静置几帧处理

    estimation_df = self.run_key_info(estimation_df)
    final_cols = ['数据序号', '循环号', '工步号', '工步序号', '工步类型', '工步时间', '绝对时间', '总时间', '电压(V)', '电流(A)',
    '容量(Ah)', '充电容量(Ah)', '放电容量(Ah)', '功率(mW)', '能量(Wh)', '充电能量(Wh)', '放电能量(Wh)',
    'V1辅助通道电压(V)', 'V2辅助通道电压(V)', 'V3辅助通道电压(V)', 'V4辅助通道电压(V)', 'V5辅助通道电压(V)',
    'V6辅助通道电压(V)', 'V7辅助通道电压(V)', 'V8辅助通道电压(V)', 'V9辅助通道电压(V)', 'V10辅助通道电压(V)',
    'V11辅助通道电压(V)', 'V12辅助通道电压(V)', 'V13辅助通道电压(V)', 'V14辅助通道电压(V)', 'V15辅助通道电压(V)',
    'V16辅助通道电压(V)', 'V17辅助通道电压(V)', 'V18辅助通道电压(V)', 'V19辅助通道电压(V)', 'V20辅助通道电压(V)',
    'V21辅助通道电压(V)', 'V22辅助通道电压(V)', 'T1辅助通道温度(℃)', 'T2辅助通道温度(℃)',
    'T3辅助通道温度(℃)', 'T4辅助通道温度(℃)', 'T5辅助通道温度(℃)', 'T6辅助通道温度(℃)']
    estimation_df = estimation_df[final_cols]
    volt_col = ['V1辅助通道电压(V)', 'V2辅助通道电压(V)', 'V3辅助通道电压(V)', 'V4辅助通道电压(V)', 'V5辅助通道电压(V)',
    'V6辅助通道电压(V)', 'V7辅助通道电压(V)', 'V8辅助通道电压(V)', 'V9辅助通道电压(V)', 'V10辅助通道电压(V)',
    'V11辅助通道电压(V)', 'V12辅助通道电压(V)', 'V13辅助通道电压(V)', 'V14辅助通道电压(V)', 'V15辅助通道电压(V)',
    'V16辅助通道电压(V)', 'V17辅助通道电压(V)', 'V18辅助通道电压(V)', 'V19辅助通道电压(V)', 'V20辅助通道电压(V)',
    'V21辅助通道电压(V)', 'V22辅助通道电压(V)']
    estimation_df = estimation_df.reset_index(drop=True)

    def _get_parameters_c(self, soc):
    soc_clamped = np.clip(soc, 0, 1)
    return {
    'R0': float(self.R0_func_c(soc_clamped)),
    'R1': float(self.R1_func_c(soc_clamped)),
    'R2': float(self.R2_func_c(soc_clamped)),
    'tau1': float(self.tau1_func_c(soc_clamped)),
    'tau2': float(self.tau2_func_c(soc_clamped))
    }

    def _get_parameters_d(self, soc):
    soc_clamped = np.clip(soc, 0, 1)
    return {
    'R0': float(self.R0_func_d(soc_clamped)),
    'R1': float(self.R1_func_d(soc_clamped)),
    'R2': float(self.R2_func_d(soc_clamped)),
    'tau1': float(self.tau1_func_d(soc_clamped)),
    'tau2': float(self.tau2_func_d(soc_clamped))
    }

    def _ekf_predict(self, current, dt):
    """EKF预测步:二阶RC离散递推"""
    soc_prev, up1_prev, up2_prev = self.x
    soc_pred = soc_prev – (self.coulomb_efficiency * current * dt / 3600) / self.capacity
    soc_pred = np.clip(soc_pred, 0, 1)
    if current <= 0:
    params = self._get_parameters_c(soc_pred)
    else:
    params = self._get_parameters_d(soc_pred)
    alpha1 = np.exp(-dt / params['tau1']) if params['tau1'] > 0 else 0
    alpha2 = np.exp(-dt / params['tau2']) if params['tau2'] > 0 else 0
    up1_pred = alpha1 * up1_prev + params['R1'] * (1 – alpha1) * current
    up2_pred = alpha2 * up2_prev + params['R2'] * (1 – alpha2) * current
    up1_pred = np.clip(up1_pred, -1, 1)
    up2_pred = np.clip(up2_pred, -1, 1)
    self.x_pred = np.array([soc_pred, up1_pred, up2_pred])
    A = np.array([
    [1, 0, 0],
    [0, alpha1, 0],
    [0, 0, alpha2]
    ])
    self.P_pred = A @ self.P @ A.T + self.Q

    def _ekf_update(self, voltage_meas, current):
    """EKF更新步:端电压残差修正状态"""
    soc_pred, up1_pred, up2_pred = self.x_pred
    if current <= 0:
    params = self._get_parameters_c(soc_pred)
    ocv_pred = self.ocv_func_c(soc_pred)
    self.voltage_pred = ocv_pred – current * params['R0'] – up1_pred – up2_pred
    y = voltage_meas – self.voltage_pred
    soc_idx = np.searchsorted(self.ocv_soc_data_c['SOC'].values, soc_pred)
    if soc_idx <= 0 or soc_idx >= len(self.ocv_soc_data_c) – 1:
    d_ocv_d_soc = 0
    else:
    d_ocv_d_soc = (self.ocv_soc_data_c['OCV'].iloc[soc_idx] – self.ocv_soc_data_c['OCV'].iloc[soc_idx – 1]) / (self.ocv_soc_data_c['SOC'].iloc[soc_idx] – self.ocv_soc_data_c['SOC'].iloc[soc_idx – 1])
    else:
    params = self._get_parameters_d(soc_pred)
    ocv_pred = self.ocv_func_d(soc_pred)
    self.voltage_pred = ocv_pred – current * params['R0'] – up1_pred – up2_pred
    y = voltage_meas – self.voltage_pred
    soc_idx = np.searchsorted(self.ocv_soc_data_d['SOC'].values, soc_pred)
    if soc_idx <= 0 or soc_idx >= len(self.ocv_soc_data_d) – 1:
    d_ocv_d_soc = 0
    else:
    d_ocv_d_soc = (self.ocv_soc_data_d['OCV'].iloc[soc_idx] – self.ocv_soc_data_d['OCV'].iloc[soc_idx – 1]) / (self.ocv_soc_data_d['SOC'].iloc[soc_idx] – self.ocv_soc_data_d['SOC'].iloc[soc_idx – 1])
    H = np.array([d_ocv_d_soc, -1, -1])
    S = H @ self.P_pred @ H.T + self.R
    K = self.P_pred @ H.T / S
    self.x = self.x_pred + K * y
    self.x[0] = np.clip(self.x[0], 0, 1)
    self.x[1] = np.clip(self.x[1], -1, 1)
    self.x[2] = np.clip(self.x[2], -1, 1)
    self.P = (np.eye(3) – np.outer(K, H)) @ self.P_pred

    def estimate(self, current, voltage, dt, true_soc=None):
    """单次EKF估算,返回估计SOC"""
    self._ekf_predict(current, dt)
    self._ekf_update(voltage, current)
    estimated_soc = self.x[0]
    return estimated_soc

    def process_data(self, data):
    """二阶RC-EKF批量生成电芯估算电压"""
    volt_cols = ['V1辅助通道电压(V)', 'V2辅助通道电压(V)', 'V3辅助通道电压(V)', 'V4辅助通道电压(V)', 'V5辅助通道电压(V)',
    'V6辅助通道电压(V)', 'V7辅助通道电压(V)', 'V8辅助通道电压(V)', 'V9辅助通道电压(V)', 'V10辅助通道电压(V)',
    'V11辅助通道电压(V)', 'V12辅助通道电压(V)', 'V13辅助通道电压(V)', 'V14辅助通道电压(V)', 'V15辅助通道电压(V)',
    'V16辅助通道电压(V)', 'V17辅助通道电压(V)', 'V18辅助通道电压(V)', 'V19辅助通道电压(V)', 'V20辅助通道电压(V)',
    'V21辅助通道电压(V)', 'V22辅助通道电压(V)']
    initial_voltages = data.loc[0, volt_cols].tolist()
    init_soc = []
    for volt in initial_voltages:
    soc = self.soc_from_ocv_func_d(volt)
    init_soc.append(np.clip(soc, 0, 1))
    data['time_diff'] = data['time_diff'].replace(0, 0.1)
    data['time_diff'] = data['time_diff'].clip(upper=30)
    data['绝对时间'] = pd.to_datetime(data['绝对时间'])
    data.loc[:, 'current'] = -1 * data['电流(A)']
    data = data.rename(columns={'容量(Ah)': 'cap', 'time_stamp': 'time'})
    R_values = [1e-5, 1e-6]
    a = random.choice(R_values)
    b = random.choice(R_values)
    c = random.choice(R_values)
    estimation_df, true_df = pd.DataFrame(), pd.DataFrame()
    cell_number = 0
    for col in volt_cols:
    self.x = np.array([init_soc[cell_number], 0.0, 0.0])
    self.P = np.diag([0.01, 1e-3, 1e-3])
    self.Q = np.diag([1e-6, a, b])
    self.R = c
    cell_number += 1
    self.results_true = {
    'volt_V' + str(cell_number): [],
    }
    self.results_simulation = {
    f'V{cell_number}辅助通道电压(V)': [],
    }
    for _, row in data.iterrows():
    dt = row['time_diff']
    estimated_soc = self.estimate(row['current'], row[col], dt)
    self.results_true['volt_V' + str(cell_number)].append(row[col])
    self.results_simulation[f'V{cell_number}辅助通道电压(V)'].append(round(self.voltage_pred, 6))
    df_cell_simulation = pd.DataFrame(self.results_simulation)
    estimation_df = pd.concat([estimation_df, df_cell_simulation], axis=1)
    df_cell_true = pd.DataFrame(self.results_true)
    true_df = pd.concat([true_df, df_cell_true], axis=1)
    true_df["delta_volt"] = true_df[true_df.columns.tolist()].max(axis=1) – true_df[true_df.columns.tolist()].min(axis=1)
    estimation_df["delta_volt"] = estimation_df[estimation_df.columns.tolist()].max(axis=1) – estimation_df[estimation_df.columns.tolist()].min(axis=1)
    estimation_df['电流(A)'] = data['current'].tolist()
    estimation_df['charge_status'] = data['charge_status'].tolist()
    return estimation_df, true_df

    赞(0)
    未经允许不得转载:171主机测评 » 动力电池二阶RC等效电路模型及EKF:原理、公式推导
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址