☰
Simulink电池充放电仿真:二阶RC、EKF与CC-CV策略验证
2026/11/5 2:27:33 网站建设 项目流程

简介:面向微电网与电动汽车充放电研究者的MATLAB/Simulink示例工程,聚焦EV充放电策略建模、充电站负荷分配与优化调度问题,适合具备一定MATLAB基础、希望复现调度流程或开展课程设计与课题验证的读者。压缩包共5个文件,约15KB,以3个m脚本为主,包含主程序、分组与随机辅助函数以及基于CVX的调度代码,另附1个txt信息数据和1个md说明文档,便于快速定位运行入口、理解参数与数据组织方式,目录规模精简,适合快速浏览与按需改造。已有2385人学习,反映出该主题在电动汽车与微电网仿真方向具有一定关注度。读者可从中参考其充放电调度的建模思路、CVX求解流程、EV信息读取与分组处理方式,并借助说明文档完成代码梳理与二次开发,为后续扩展Simulink模型、对比不同调度策略提供可操作的基础样本。

1. 先看清这块 75 kWh 的电池包:模型能跑什么、跑不了什么

接手一个电池管理策略的联调任务时,最头疼的不是写代码,而是台架上只有一块电池包,想验证一次低温大倍率充电得排到半夜,改一个截止电流参数又要重新等一轮。电动汽车电池充放电 Simulink 仿真模型解决的正是这类问题:把电芯的等效电路、充放电控制、工况注入和 SOC 观测搬进 Simulink,一轮 0.5C 恒流转恒压的完整充电过程几十秒就能跑完,参数改完立刻看曲线。

这套模型走的是等效电路路线,不是电化学路线,精度靠 HPPC 之类的脉冲试验标定出来,够做策略验证和能量流分析,不适合拿来研究析锂或者 SEI 膜增长。它适合三类人:做 BMS 充放电策略验证的、做整车能量管理前期方案对比的、以及学完 Simulink 基础想找一个能跑通的完整工程练手的。

2. 工程架构拆解:三层信号流如何把一条电流走成端电压

拆一个仿真模型,我习惯先看它把什么放在模型里、什么放在脚本里。放错的典型症状是:改一个内阻要从二十个模块里翻出来,扫一组温度得手动改十几次参数,最后没人记得当前这版模型对应的到底是哪份数据。这个工程的分法比较清爽,参数、模型、脚本三条线各管各的,模型里基本看不到硬编码的数字。

2.1 工程目录:五个文件夹划清边界

拿到手先看目录,边界清楚说明作者是想让别人接着改的,而不是交个一次性作业。

路径职责说明
model/ev_battery_charge.slx顶层模型只放子系统引用和信号路由,不放具体算法
model/lib_battery.slx电池库等效电路、OCV 查表、EKF 观测器封装成库元件
scripts/battery_param.m参数脚本电芯参数、OCV-SOC 表、仿真配置全在这里
scripts/init_model.m初始化回调模型 PreLoadFcn 自动调用,加载参数并配求解器
data/*.mat工况数据电流/功率时间序列,用from file或From Workspace读入
out/仿真产物批量跑时落地的.mat,不进版本库

把电池模型做成库元件这一步值得单独说。顶层模型里一个Battery Pack模块,双击进去才是二阶 RC 和观测器,好处是同一个电池库能被充电模型、放电模型、整车能量流模型同时引用,改一处三处生效。代价是首次打开顶层模型时库链接会提示未解析,得先把model/加进路径,这一点后面排查章节会再提。

2.2 顶层信号流:一条电流从工况走到端电压

整个模型的信号链其实只有一条主线,顺着走一遍就全通了:工况源给出目标电流 → CC-CV 状态机给出参考电流 → 1 ms 电流环算出占空比 → 双向 DC/DC 把占空比变成实际电流 → 电池等效电路把电流积分成 SOC 和极化电压,再叠上 OCV 得到端电压 → 端电压和 SOC 一路回灌给状态机和 EKF 观测器,形成闭环。

回路里存在两个明显不同的时间尺度,混在一起是新手最容易踩的坑。电流环和 DC/DC 开关动作需要毫秒级,而 SOC 积分、温升、容量衰减这些是秒级甚至分钟级。工程上常见的做法是在Model Configuration里把求解器设成变步长ode23t,同时给电力电子子系统单独配Sample Time = 1e-3,用 Rate Transition 模块隔开两个速率。这样既不会因为快环拖慢整体仿真,也不会让慢环的采样点被快环挤爆。

% init_model.m —— 挂在模型 PreLoadFcn 上,打开模型自动执行 run('scripts/battery_param.m'); % 先把参数灌进 base 工作区 % 变步长 ode23t 对含开关的刚性系统比较稳,比 ode45 少很多震荡 set_param('ev_battery_charge', 'Solver', 'ode23t', ... 'RelTol', '1e-4', 'MaxStep', '0.01', ... 'StopTime', num2str(sim.t_end)); % 批量扫参数时打开 Fast Restart,省掉每次重新编译的时间 set_param('ev_battery_charge', 'FastRestart', 'on');

这段初始化里MaxStep是重点。默认的auto在开关瞬间会自己缩步长,仿真时间直接翻几倍;把它限死在 0.01 s,配合RelTol=1e-4,一般的充放电曲线误差能压在千分之几,跑一轮两小时的充电大概二十秒出结果。FastRestart打开之后,同一模型反复sim不会重新编译,扫一组温度参数能省掉一半以上的等待。

提示:FastRestart打开时不能改模型结构,只能改变量值。扫参数没问题,想临时加个 Scope 探针记得先关掉。

2.3 参数脚本化:别把数字写进模块

参数集中管理这件事,说的时候都认同,做的时候都偷懒。我的血泪经验是:只要有一个内阻值被手敲进了模块的增益框,三个月后接手的人就得靠猜。这个工程的做法是全部参数落在一个结构体里,模块只引用p.R0_pack这样的变量名。

% battery_param.m —— 电池包与仿真参数,全部挂在 p 结构体下 % 电池包规格:75 kWh / 350 V / 96 串 12 并,单体 3.65 V 18.5 Ah p.cell_cap_Ah = 18.5; % 单体外额定容量,Ah p.cell_R0 = 0.0021; % 欧姆内阻,Ω,25℃、50% SOC 实测 p.cell_R1 = 0.0016; % 一阶极化电阻(电化学极化) p.cell_C1 = 2200; % 一阶极化电容,F p.cell_R2 = 0.0009; % 二阶极化电阻(浓差扩散) p.cell_C2 = 31000; % 二阶极化电容,F p.Ns = 96; % 串联节数 p.Np = 12; % 并联支路数 % 包级换算:容量按并联翻倍,内阻按串并比折算 p.cap_Ah = p.cell_cap_Ah * p.Np; % ≈ 222 Ah p.R0 = p.cell_R0 * p.Ns / p.Np; p.R1 = p.cell_R1 * p.Ns / p.Np; p.R2 = p.cell_R2 * p.Ns / p.Np; p.C1 = p.cell_C1 * p.Np / p.Ns; % 电容串并规律与电阻相反 p.C2 = p.cell_C2 * p.Np / p.Ns; % OCV-SOC 曲线:静置 2 h 后逐点实测,11 个断点 p.soc_bp = [0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]; p.ocv_v = [3.05 3.45 3.58 3.64 3.68 3.72 3.78 3.86 3.95 4.05 4.18]; % 仿真配置 sim.Ts = 1; % 慢环采样 1 s sim.Ts_fast = 1e-3; % 快环采样 1 ms sim.t_end = 7200;

注意电容那两行的折算方向和电阻是反的:串联增加耐压不增加容量,所以包级电容是单体电容乘并联数除串联数。这一处写反的后果不轻,极化电压的收敛速度会差几十倍,曲线看起来只是“有点慢”,很难第一时间反应过来。

在更正式的工程里,p里每个字段还会包一层Simulink.Parameter对象,配上StorageClass和单位标注,方便和标定工具对接。个人项目用结构体加注释就够,但单位一定要写在注释里,A 和 mA、Ω 和 mΩ 混用是另一个常见坑。

3. 核心模块实现:二阶 RC 等效电路与 EKF 观测器的落地细节

电池模型这部分是整个工程真正的核心,也是最容易被简化过头的地方。一阶 RC 跑恒流工况看不出问题,一旦上脉冲工况或者低温大倍率,端电压的瞬时跌落和恢复拖尾就全对不上了。这个工程用二阶 RC,一个环管电化学极化,一个环管浓差扩散,两个时间常数差一个数量级,脉冲工况下的曲线形状能对上。

3.1 二阶 RC 等效电路:连续方程怎么离散成模块

先把方程摆出来。以放电为正方向,状态量是两个极化电压 $V_1$、$V_2$,端电压由 OCV 减去内阻压降和两个极化压降:

$$V_t = OCV(SOC) - I R_0 - V_1 - V_2$$

每个 RC 环的动态是一阶惯性环节,$\dot V_i = -V_i/(R_i C_i) + I/C_i$。Simulink 里可以用 Transfer Fcn 模块搭,也可以直接用 MATLAB Function 做零阶保持离散化。后者更可控,也不会因为求解器步长变化导致两个环的时间常数漂移,我一般选后者。

function [Vt, SOC_new, V1_new, V2_new] = batt_step(I, SOC, V1, V2, p, Ts) % batt_step 二阶 RC 等效电路单步推进,放在 MATLAB Function 块内 % 输入 I:包级电流,A,放电为正、充电为负 % 输入 SOC/V1/V2:上一时刻状态;Ts:本块采样周期,s % 输出 Vt:端电压 V a1 = exp(-Ts / (p.R1 * p.C1)); % 一阶环离散系数,恒小于 1 a2 = exp(-Ts / (p.R2 * p.C2)); % 二阶环系数,比 a1 更接近 1 % 极化电压递推:零阶保持离散化,形式上等价于一阶低通滤波 V1_new = a1 * V1 + p.R1 * (1 - a1) * I; V2_new = a2 * V2 + p.R2 * (1 - a2) * I; % 安时积分:放电 SOC 下降,3600 把秒换算成小时 SOC_new = SOC - I * Ts / (3600 * p.cap_Ah); SOC_new = min(max(SOC_new, 0), 1); % 物理限幅,防止数值越界 % 端电压合成:OCV 查表 + 内阻压降 + 两个极化压降 ocv = interp1(p.soc_bp, p.ocv_v, SOC_new, 'linear'); Vt = ocv - I * p.R0 - V1_new - V2_new; end

参数里最值得注意的是Ts。这个模块被放在 1 s 的慢环里,Ts=1,此时a1 = exp(-1/(R1*C1)),若R1*C1只有 3.5 s,系数约 0.75,一秒钟就把极化电压放掉了大半;而R2*C2有 28 s,系数约 0.965,拖尾能延续一分多钟。这就是二阶模型比一阶强的地方——脉冲结束后端电压不会立刻弹回 OCV,而是先快后慢地爬回去,和实测对得上。

顺带说一个精度上的取舍:离散化用的是零阶保持,Ts越大误差越大。如果把Ts改成 10 s 做长时间尺度仿真,a1会小到 0.06,一阶环几乎瞬间衰减,曲线形状就废了。真要做小时级仿真,正确做法是保持Ts不变、外面套一层加速,而不是把采样周期放大。

3.2 OCV-SOC 查表和库仑计数的三个细节

库仑计数本身只是一行积分,翻车点全在细节上。

第一,符号约定必须全模型统一。这个工程定的是放电为正、充电为负,那么安时积分里就是减号,端电压里也是减号,电流环的参考值在充电时是负数。听着简单,但只要有一处按“充电为正”写,结果就是 SOC 越充越少,而且曲线平滑得看不出任何异常,属于典型的黑匣子故障。

第二,查表断点必须严格覆盖 [0, 1] 且单调递增。interp1遇到越界默认是外插,SOC 稍微冲过 1,OCV 能给你算出 4.3 V 甚至更高,端电压跟着飞,看着像模型发散,实际是外插。稳妥做法是查表前先钳位。

function ocv = ocv_from_soc(soc, p) % ocv_from_soc 带钳位与端点保护的 OCV 查表 soc = min(max(soc, 0), 1); % 先钳位,杜绝外插 ocv = interp1(p.soc_bp, p.ocv_v, soc, 'linear'); % 线性插值,断点足够密时够用 end
% 用静置端电压反查初始 SOC,避免每次手动填初值 function soc0 = init_soc_from_ocv(Vt_rest, p) Vt_rest = min(max(Vt_rest, min(p.ocv_v)), max(p.ocv_v)); soc0 = interp1(p.ocv_v, p.soc_bp, Vt_rest, 'linear'); % 注意断点和值的位置对调 soc0 = min(max(soc0, 0), 1); end

第三,初始 SOC 别手填。手动填一个 0.6 结果曲线和实测对不上,排查半天以为是模型参数问题,其实是初始值偏了 5%。用静置端电压反查,虽然 OCV 曲线中段平坦、反查精度有限,但比拍脑袋填强得多,而且换一组数据时能自动适配。

3.3 EKF:用一个 MATLAB Function 把 SOC 拽回来

纯安时积分的问题在于误差只增不减,电流传感器零点偏 10 mA,跑两小时就偏掉 2% SOC。EKF 的作用是用端电压这个可测量去修正积分漂移,把状态从“只能往前推”变成“推完还能拉回来”。

状态量取三维:x = [SOC; V1; V2],量测量是端电压。状态方程就是上一节的离散化,量测方程就是端电压合成公式,雅可比矩阵手推一下也不复杂。

function [x_new, P_new] = ekf_soc_step(I, Vt, x, P, Q, R, p, Ts) % ekf_soc_step 单步扩展卡尔曼滤波,状态 x=[SOC;V1;V2] % I 放电为正(A),Vt 实测端电压(V),Q/R 过程与量测噪声协方差(3x3 / 1x1) a1 = exp(-Ts / (p.R1 * p.C1)); a2 = exp(-Ts / (p.R2 * p.C2)); % 状态转移矩阵与输入矩阵,由离散化方程直接读出 A = [1, 0, 0; 0, a1, 0; 0, 0, a2]; B = [-Ts/(3600*p.cap_Ah); p.R1*(1-a1); p.R2*(1-a2)]; % 1) 时间更新:先按模型往前推一步 x_p = A * x + B * I; x_p(1) = min(max(x_p(1), 0), 1); P_p = A * P * A' + Q; % 2) 量测更新:用端电压残差修正 ocv = interp1(p.soc_bp, p.ocv_v, x_p(1), 'linear'); % OCV 对 SOC 的偏导用中心差分,步长 1e-3 足够,比解析求导省事 dVdSOC = (interp1(p.soc_bp, p.ocv_v, min(x_p(1)+1e-3, 1)) - ... interp1(p.soc_bp, p.ocv_v, max(x_p(1)-1e-3, 0))) / 2e-3; C = [dVdSOC, -1, -1]; K = P_p * C' / (C * P_p * C' + R); % 卡尔曼增益,标量除法更快也更稳 x_new = x_p + K * (Vt - (ocv - I*p.R0 - x_p(2) - x_p(3))); x_new(1) = min(max(x_new(1), 0), 1); P_new = (eye(3) - K * C) * P_p; end

几个调参经验:Q的对角元里 SOC 那一项别给太大,给到1e-8量级就够,给大了滤波器会去“追”端电压的测量噪声,SOC 曲线变得毛刺;R按电压传感器的实际噪声取,一般1e-4(对应 10 mV 标准差)比较合适。另外dVdSOC在 OCV 平台区(SOC 30%~70% 那一段)非常小,增益自然就低,这时候滤波器基本不修正,属于正常现象,不用怀疑代码写错了。

注意:EKF 发散最常见的两个原因,一是初始协方差P0给得太小(比如全填 1e-6),滤波器一开始就“过度自信”不肯修正;二是Q和R的比例失调。先把P0的对角元设成[0.01, 0.01, 0.01]跑起来看。

4. 充放电控制链路:CC-CV 状态机与 1 ms 电流环怎么配合

电池模型决定“像不像”,控制链路决定“跑不跑得通”。这一段如果只搭个理想电流源顶上去,充电曲线永远是对的,但一旦换成真实的 DC/DC,恒压段就会来回振荡,截止判据也永远触发不了。

4.1 双向 DC/DC 与 1 ms 电流环

电力电子部分常见的简化建模方式是平均值模型:忽略开关纹波,用占空比直接控制输出电压,再串一个 LC 滤波器和一个小延时。这样做的好处是Ts可以放到 1 ms 而不用 1 μs,仿真速度快两个数量级,对充放电策略验证完全够用。如果确实要看开关纹波和器件应力,再换成详细开关模型,代价是仿真时间。

电流环用增量式 PI,输出占空比限在 [0, 1],重点是抗积分饱和。饱和这件事在恒流段末尾最容易出事:电压顶到上限、占空比已经 1,积分项还在往里加,等切换到恒压段时积分项早已跑飞,电流要好几秒才拉得回来,表现为一段莫名其妙的电流尖峰。

function [duty, integ] = curr_pi(I_ref, I_meas, integ, Ts) % curr_pi 1 ms 电流环,输出占空比 [0,1] % I_ref 参考电流(A),I_meas 实测电流(A),integ 上一拍积分项 Kp = 0.02; Ki = 1.5; err = I_ref - I_meas; integ_new = integ + Ki * err * Ts; % 先算积分,再做饱和判断 duty = Kp * err + integ_new; if duty > 1 % 上饱和:占空比钳位,积分停走 duty = 1; integ_new = integ; elseif duty < 0 % 下饱和:同样处理,双向都能充电放电 duty = 0; integ_new = integ; end integ = integ_new; end

Kp=0.02、Ki=1.5这组值是按 222 Ah 的包、1 ms 采样试出来的。包级容量越大,同样的电流误差对应的 SOC 变化越慢,增益可以给得激进一些;换成小容量包(比如 50 Ah)时,Ki要往下降到 0.8 左右,否则电流环会有一个明显的过冲。

4.2 CC-CV 切换:阈值、回差与终止条件

恒流转恒压的判据听着简单——电压到了就切,实际跑起来最常见的问题是“切了又弹回去”。原因是端电压里包含了内阻压降和极化压降,恒流段末尾Vt已经摸到 4.15 V × 96,可一旦电流降下来,I*R0那部分压降消失,Vt立刻掉回阈值以下,状态机就来回跳。

解决办法有两个,我一般两个都用:一是判据改用“去掉内阻压降后的开路电压估计”,二是给切换加回差,比如进入恒压用Vt >= V_cv,退出要等到Vt <= V_cv - 0.05*p.Ns。

function [I_ref, mode] = cc_cv_ref(Vt, I_now, p) % cc_cv_ref 充电参考电流生成:恒流 → 恒压 → 截止,三段状态机 % mode: 1 恒流、2 恒压、3 截止 persistent st vint if isempty(st), st = 1; end if isempty(vint), vint = 0; end I_cc = 0.5 * p.cap_Ah; % 恒流段 0.5C ≈ 111 A V_cv = 4.15 * p.Ns; % 恒压段目标 ≈ 398.4 V I_cut = 0.05 * p.cap_Ah; % 截止电流 0.05C ≈ 11 A Kp = 0.9; Ki = 0.02; % 电压环增益,先给经验值再微调 switch st case 1 % 恒流段 I_ref = I_cc; if Vt >= V_cv st = 2; vint = I_cc; % 积分项预置为当前电流,避免切换冲击 end case 2 % 恒压段:电压环输出电流参考 err = V_cv - Vt; vint = vint + Ki * err; vint = min(max(vint, 0), I_cc); % 抗积分饱和 I_ref = min(max(Kp * err + vint, 0), I_cc); if I_now < I_cut % 电流衰减到截止值,充电结束 st = 3; end otherwise % 截止 I_ref = 0; end mode = st; end

那个vint = I_cc的预置是这段代码里最关键的一行。不做预置,进入恒压瞬间电压环误差接近零,积分项从零开始爬,输出电流参考直接掉到零,然后再慢慢爬回来,曲线上看就是恒压段开头凹陷一块,充电时间凭空多出十几分钟。做了预置,切换瞬间电流是连续的。

截止判据也有讲究。用瞬时电流< I_cut容易误触发,实际工程里一般要求连续若干个采样周期都低于阈值,或者用滑动平均。模型里可以简单地用 10 s 的持续判断代替,成本很低但能挡掉大部分误截止。

4.3 工况注入:自定义电流曲线与仿真加速

放电侧不用状态机,直接灌工况。数据源可以是标准工况的功率时间序列,也可以是一段实车采集的电流曲线,统一存成两列.mat(时间、电流),用From Workspace读进来,注意时间列必须单调递增,重复时间点会让求解器报错。

如果要做长时间的循环寿命仿真,比如跑 500 次充放循环,逐次sim会很慢。常见做法是把单次循环封成一个Simulink Function或引用模型,外面套for循环,每轮结束后把末态(SOC、V1、V2、累计安时)写回初值,同时按循环次数更新容量衰减和内阻增长。这样 500 次循环可以在一两分钟内跑完,比一次跑 500 轮的等效模型要真实得多。

5. 避坑与排查:跑不动查三处、跑不对查两处

这个模型我前后在三个不同规模的包上跑过,出问题的地方高度集中。下面五条是按“先跑起来、再跑对”的顺序排的,基本覆盖了九成以上的翻车场景。

5.1 跑不起来:求解器、代数环、初始化

现象一:点运行立刻报代数环(Algebraic loop)错误,或者提示“模型包含代数环,无法求解”。原因通常是 EKF 观测器或电流环的反馈路径里存在直通:I_ref依赖Vt,而Vt又依赖本拍的I,中间没有延时单元,Simulink 只能迭代求解。原因是输入端直接用了Vt而没做单位延迟。 解决办法是在反馈路径上插一个Unit Delay(采样 1 ms),把Vt和I_meas都延后一拍再喂给控制器。物理上这是合理的——真实控制器本来就有采样保持,一拍延时对应 1 ms,对闭环稳定性影响可以忽略。

现象二:仿真跑到某个时刻突然卡住,进度条不动,几十分钟后报“步长小于最小值”。八成是模型发散导致的步长塌陷,根源往往在某个限幅缺失。常见的是 OCV 查表外插,或者 SOC 积分器没有钳位,SOC 冲到 1.02 之后 OCV 算出 4.3 V,端电压继续升,状态机继续充电,恶性循环。 解决办法有三步:给 SOC 积分器加Saturation(0~1);查表前钳位;在Model Configuration里把Min step size设一个下限(比如1e-8),让它报错而不是干等。

现象三:打开模型全是红色虚线,提示库链接未解析。这是电池库没在路径上。lib_battery.slx被顶层引用,但model/目录没加进 MATLAB 路径。 解决办法是在init_model.m开头补一行addpath(genpath('model')),并确认PreLoadFcn回调里调用了它。换机器或者拉了一份新代码,第一件事就是手动跑一遍这个脚本。

5.2 跑得动但结果不对:SOC 与端电压

现象四:充电过程 SOC 一直不涨,或者越充越小,但曲线很平滑看不出异常。原因是符号约定在某个环节反了。最常见的重灾区是 CC-CV 状态机给出的参考电流是正数(按“充电为正”写),而电池模型按“放电为正”处理,于是充电被算成放电。 解决办法是全局搜一遍所有出现电流符号的地方:安时积分、端电压合成、电流环误差、状态机输出,四处必须一致。改完之后跑一次小电流(0.1C)充电对一遍:SOC 单调上升、端电压单调升到恒压值,两条都满足才算对。

现象五:恒压段电流掉得特别快,几分钟就截止,或者反过来怎么都掉不到截止值。前者多半是电压环Ki太大或者积分项没预置,后者通常是Kp太小或者V_cv设得偏高。还有一个容易被忽略的原因:I_cut是按包级容量算的,如果参数脚本里cap_Ah忘了乘并联数,I_cut会小一倍,永远触发不了。 解决办法是先打印I_cc、I_cut、V_cv三个值对一遍量级(222 Ah 的包,0.5C 约 111 A,0.05C 约 11 A),再调增益。调Ki的时候把Kp先固定,单调一个,不然两个参数互相掩盖,越调越乱。

提示:仿真结果不对时,先别急着改参数。把I_ref、I_meas、Vt、SOC、mode五条信号接到一个Scope里并排看,异常出现在哪一段、哪个信号先动,通常一眼就能定位到模块。

6. 二次开发:把 96 串的电池包换成你自己的那一块

拿到这个模型想改成自己的参数,最容易犯的错是“一把梭改参数然后直接跑”。我吃过这个亏:把一个 50 Ah 的小包参数填进去,其他全没动,结果恒流段电流直接给了 111 A,两秒之内 SOC 从 0.9 掉到 0.1,还以为是模型坏了。后来才反应过来I_cc = 0.5 * p.cap_Ah是跟着容量走的,改容量没问题,但 DC/DC 的电流上限、线束内阻、截止电流这些都没跟着换算。

正确的改造顺序是四个步骤,一步一验证。

第一步换电芯参数。把单体容量、R0/R1/R2/C1/C2、串并数改掉,先只改这些,跑一次 0.2C 的小电流恒流放电,看端电压从满电放到截止能不能对上数据手册的放电曲线。对不上就回去查内阻和 OCV 表,别往下走。

第二步换 OCV-SOC 曲线。如果有实测静置数据,直接替换p.soc_bp和p.ocv_v;没有的话可以拿一个单体做一次 0.05C 的慢充慢放,正负两个方向的平均值近似当作 OCV。曲线两端的陡峭段最关键,中间平台区反而不用太纠结。

第三步按新容量重算控制参数。参考电流、截止电流、电流环增益都要动,经验公式是Ki大致和容量成反比。这一步可以用一个小脚本扫一遍。

% sweep_cap.m —— 换包之后先扫增益,别拍脑袋填 caps = [50, 100, 222]; % 三档包容量,Ah for k = 1:numel(caps) p = battery_param(); % 重新载入基础参数 p.cap_Ah = caps(k); p = rescale_gains(p); % 按容量重算 I_cc / I_cut / Ki assignin('base', 'p', p); % 送进模型工作区 out = sim('ev_battery_charge.slx'); fprintf('cap=%3d Ah, 充电时长 %.0f s, 末态 SOC %.3f\n', ... caps(k), out.tout(end), out.logsout.get('SOC').Values.Data(end)); end

rescale_gains里做的就是把I_cc、I_cut按新容量重算,Ki按容量反比缩放,V_cv保持单体 4.15 V × 新串数不变。扫完看三组数据的充电时长和末态 SOC,如果末态 SOC 都在 0.98 以上、时长随容量大致线性增长,说明整条链路是自洽的。

第四步做温度扩展。这一步是让模型从“能用”到“敢用”的分水岭,因为低温下内阻能翻三四倍,恒流段撑不了多久就提前转恒压。

温度R0 倍率R1 倍率可用容量说明
-10 ℃4.26.50.72恒流段明显缩短,需降倍率
0 ℃2.63.40.85常规低温,0.3C 起步
25 ℃1.01.01.00基准工况
45 ℃0.90.81.02内阻略降,注意温升与截止

这张表里的数字不是实测,是我按常见三元电芯的温度特性给的经验值,你要用自己的电芯就老实做一次不同温度下的 HPPC。表怎么用:在battery_param.m外面包一层apply_temp(p, T),按温度查表插值后覆盖R0/R1/R2,再把p.cap_Ah乘以可用容量系数,剩下的流程完全不动。

验证方法我给一个笨但管用的:改完参数先跑一遍 25 ℃ 的 1C 放电,把仿真端电压和实测数据画在同一张图上,算均方根误差。低于 20 mV 算合格,20~50 mV 检查内阻和 OCV 表,超过 50 mV 一定是参数换算的串并关系错了,回去看那两行电容折算。这个检查我每次换包都做,花五分钟省下半天。

从那以后我每次改电池参数,都强制先跑一遍 0.2C 小电流的单向充放电对曲线,对上了再开控制环。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询