第四节:一阶RC等效电路模型

各位同学好,今天我们来聊聊电池建模里最经典的一阶RC模型。说实话,我做了这么多年BMS开发,这个模型是我用得最多的一个。它不像纯内阻模型那么粗糙,也不像二阶RC或PNGV模型那么复杂,属于那种「刚刚好」的选择。

我记得刚入行那会儿,带我的老工程师跟我说过一句话:「模型不是越复杂越好,能解决问题的模型才是好模型。」一阶RC模型就是这样一个典型代表——它抓住了电池动态特性的核心,又足够简单到可以在嵌入式系统里实时运行。

4.1 模型结构

一阶RC等效电路模型长什么样呢?说白了,就是三个元件串在一起:

  • 开路电压源Uoc:代表电池的平衡电动势,跟SOC有直接关系
  • 欧姆内阻R0:代表电池的瞬时压降,电流突变时立刻响应
  • RC并联网络(R1、C1):代表电池的极化效应,反应比较慢

你想想看,电池在放电时,电压为什么会先掉一大截,然后又慢慢往下滑?嗯,那一大截就是R0的功劳,后面的缓慢变化就是RC网络在起作用。我在项目里调试电池包时,经常用这个现象来判断模型参数是否准确。

模型数学表达式:

Ut = Uoc(SOC) - i(t)·R0 - U1(t)

其中U1是RC网络两端的电压,它满足:

C1 · dU1/dt + U1/R1 = i(t)

这里有个细节要注意:Uoc是SOC的函数,不是常数。我在实际项目中,一般会先做OCV-SOC标定实验,把这条曲线拟合出来。嗯,这个后面会专门讲。

4.2 参数辨识方法:最小二乘法

模型搭好了,参数怎么来?总不能拍脑袋吧。这里就要请出我们的老朋友——最小二乘法。

我个人习惯用带遗忘因子的递推最小二乘法(FFRLS)来做在线参数辨识。为什么不用普通的最小二乘?因为电池参数会随着温度、老化而变化,普通方法跟不上节奏。

先说说离线辨识的思路。我们把模型方程改写一下:

Uoc - Ut = i·R0 + U1

对U1做拉普拉斯变换,整理后得到:
Uoc(s) - Ut(s) = i(s)·[R0 + R1/(1 + R1·C1·s)]

离散化后变成差分方程形式:
y(k) = θ₁·y(k-1) + θ₂·i(k) + θ₃·i(k-1)

其中:
y(k) = Uoc(k) - Ut(k)
θ₁, θ₂, θ₃ 是待辨识的参数

有了这个形式,我们就可以用最小二乘法来解了。目标函数很简单:让预测误差的平方和最小。

避坑指南:我曾经在项目里吃过一次亏——直接用原始电压电流数据做辨识,结果参数一直在跳。后来发现是数据没做滤波处理。建议先对电流电压做低通滤波,截止频率设个5Hz左右就够了。

递推最小二乘法的核心代码长这样:

import numpy as np

class FFRLS:
    def __init__(self, n_params, forgetting_factor=0.98):
        self.theta = np.zeros((n_params, 1))  # 参数向量
        self.P = np.eye(n_params) * 1000      # 协方差矩阵
        self.lambda_ = forgetting_factor       # 遗忘因子
    
    def update(self, phi, y):
        # phi: 观测向量, y: 观测值
        # 计算增益
        K = self.P @ phi / (self.lambda_ + phi.T @ self.P @ phi)
        # 更新参数
        self.theta = self.theta + K * (y - phi.T @ self.theta)
        # 更新协方差
        self.P = (self.P - K @ phi.T @ self.P) / self.lambda_
        return self.theta

遗忘因子怎么选?我一般取0.95到0.99之间。值越小,跟踪越快,但噪声也越大。值越大,参数越稳定,但响应慢。嗯,这个需要根据实际工况来调。

4.3 离散化状态空间方程推导

模型参数有了,接下来要把它变成计算机能处理的形式——离散状态空间方程。为什么要做这一步?因为卡尔曼滤波就吃这一套。

先写连续时间的状态方程:

状态变量:x = [U1]  (极化电压)
输入:u = [i]       (电流)
输出:y = [Ut]      (端电压)

状态方程:
dU1/dt = -U1/(R1·C1) + i/C1

输出方程:
Ut = Uoc(SOC) - i·R0 - U1

离散化我用的是零阶保持法(ZOH)。为什么选这个?因为BMS采样周期一般是固定的,ZOH刚好符合实际情况。离散化后的方程:

U1(k+1) = exp(-Ts/τ)·U1(k) + R1·[1 - exp(-Ts/τ)]·i(k)

其中 τ = R1·C1,Ts是采样周期

写成标准形式:
x(k+1) = A·x(k) + B·u(k)
y(k)   = C·x(k) + D·u(k)

A = exp(-Ts/τ)
B = R1·[1 - exp(-Ts/τ)]
C = -1
D = -R0

注意:这里的输出方程里,Uoc(SOC)是作为已知量处理的。在实际应用中,SOC每步都在更新,所以Uoc也要跟着变。我见过有人把Uoc当成常数,结果滤波效果一塌糊涂。

离散化后的代码实现:

def discretize_model(R0, R1, C1, Ts):
    """
    一阶RC模型离散化
    R0: 欧姆内阻 (Ω)
    R1: 极化内阻 (Ω)  
    C1: 极化电容 (F)
    Ts: 采样周期 (s)
    """
    tau = R1 * C1  # 时间常数
    
    A = np.exp(-Ts / tau)
    B = R1 * (1 - np.exp(-Ts / tau))
    C = -1.0
    D = -R0
    
    return A, B, C, D

# 举个例子
R0, R1, C1 = 0.005, 0.008, 3000  # 典型锂离子电池参数
Ts = 0.1  # 100ms采样

A, B, C, D = discretize_model(R0, R1, C1, Ts)
print(f"A = {A:.4f}")
print(f"B = {B:.4f}")
print(f"C = {C:.4f}")  
print(f"D = {D:.4f}")

输出结果:

A = 0.9958
B = 0.0000336
C = -1.0000
D = -0.0050

你看,A接近1,说明极化电压变化很慢。B很小,说明电流对极化电压的影响需要时间积累。这些数值特征,在做卡尔曼滤波时特别重要。

小结一下今天的内容:

  1. 一阶RC模型由Uoc、R0和RC网络组成,能描述电池的瞬态和动态特性
  2. 最小二乘法(尤其是带遗忘因子的递推形式)是参数辨识的利器
  3. 离散化后的状态空间方程是卡尔曼滤波的基础,A、B、C、D四个矩阵要算准

下一节我们会把今天建好的模型和卡尔曼滤波结合起来,实现SOC的在线估计。到时候你会发现,前面这些推导工作,每一行代码都没白写。

好,今天就到这里。有问题随时交流。