最近在做增程式电动汽车(EREV)的整车能量管理仿真时,最折腾我的问题就是电池从亏电到满电这段过程里,增程器到底该怎么工作。刚开始我搭的模型非常简单——SOC低了就启动增程器,SOC高了就关掉,结果仿真曲线像锯齿一样,增程器几分钟就启停一次,电池充电功率也经常顶到保护限值。后来把整套逻辑重新梳理了一遍,用MATLAB/Simulink按整车动力学、电池、增程器、控制策略四层重新搭,才真正跑通从SOC 15%亏电状态一路充到95%以上的完整过程。这篇文章就把整个建摸过程和控制逻辑完整拆开讲一遍,包括模型架构、子系统模型、亏电到满电的控制策略设计,以及我在调参过程中踩过的坑。想用MATLAB做新能源整车仿真,特别是EREV/PHEV能量管理策略的同学,可以直接按这套思路去复现。
1. EREV模型到底要解决什么问题:架构、目标与仿真方式的选择
1.1 增程式电动车和插混、纯电在建模上的本质差异
很多人一开始会把EREV当成"纯电+发电机"的组合,模型上直接拿纯电模型加一个受控电流源,后来发现完全不是这么回事。EREV的动力传递路径是固定的:电池给电机供电,电机驱动车轮;增程器里的发动机带动发电机发电,电能可以给电池充电,也可以直接给电机供电,但发动机和车轮之间没有机械连接。这一点和插电混动(PHEV)有本质区别——PHEV存在发动机直接驱动车轮的并联模式,建模时必须考虑离合器状态、变速器挡位、扭矩叠加甚至模式切换的平顺性,复杂度要高一个量级。
EREV的优势恰恰在于"解耦"。发动机的工作点不受车速约束,控制策略可以始终让增程器运行在效率较高的点。反映到建模上,就是增程器不需要建立详细的发动机瞬态模型,只需要一个"输入功率指令、输出发电功率和油耗"的准静态模型就够用了。而真正的难点,全部集中在能量管理层:增程器什么时候启动、发多少电、发电优先给驱动还是优先给电池充电、SOC目标定多少、接近满电时怎么降功率。这套从亏电到满电的逻辑,才是EREV模型的核心价值。
1.2 模型用途决定细节粒度:后向仿真还是前向仿真
动工之前,先想清楚一个事:你搭这个模型是干什么用的。如果只是算综合油耗、续航里程,用后向仿真就够了,也就是直接根据循环工况的车速反推整车需求功率,再沿着传动链从车轮推到电池和发动机,模型简单、仿真速度快,适合做大量参数扫描。但后向仿真有一个问题:它假设车辆完全按目标工况行驶,没有驾驶员模型,动态控制过程中的功率响应、SOC波动、模式切换都被抹掉了。拿它研究亏电到满电的控制逻辑,基本等于拿着地图找下水道,方向对但看不到细节。
我这次的目标是研究和验证控制策略,所以选择前向仿真。前向仿真以驾驶员需求扭矩作为输入,信号流是真实的因果链:目标车速进入驾驶员模型,驾驶员模型输出加速踏板或制动踏板开度,整车控制器根据当前状态给出扭矩和功率分配指令,电机执行指令,车辆纵向动力学计算实际车速,再反馈给驾驶员模型形成闭环。前向仿真能清楚看到增程器启动瞬间的功率分配、电池SOC的响应轨迹、以及策略参数变化带来的影响,代价是模型更重、调试更麻烦,但对控制逻辑研究来说这是必须的。
1.3 顶层架构怎么搭
前向仿真的顶层架构,我在模型里分了五层:
- 工况层:输入CLTC/WLTC等目标车速序列
- 驾驶员层:PID控制器输出需求扭矩
- 策略层:能量管理逻辑,决定增程器启停和发电功率
- 执行器层:电机、增程器、电池的物理响应
- 车辆层:整车纵向动力学,计算实际车速
控制策略层是大脑,但大脑的信号离不开物理层反馈。电池SOC估算模块计算当前SOC,反馈给策略层;策略层根据SOC、驾驶员需求功率、附件功率,计算增程器发电功率指令;增程器模块执行这个指令,把发电功率送入DC母线;母线功率平衡决定了电池是放电还是充电,进而影响SOC。这个闭环一旦建立,后续所有控制逻辑都在这套架构上改。
2. 把整车拆成四块:电池、增程器、电机和纵向动力学建模细节
2.1 电池模型:安时积分SOC和二阶RC等效电路
电池是EREV的能量缓冲器,它的模型精度直接影响SOC变化趋势。我选择的是二阶RC等效电路模型,包含一个电压源OCV(SOC)、一个内阻R0、两组RC并联网络。为什么不直接用理想电压源加内阻?因为电池在动态工况下会出现极化效应,电流突变后端电压不会立刻跳变,而是有一个渐变过程。一阶RC能模拟一部分极化,但响应太单调;三阶RC精度更高,可是参数辨识工作量大幅增加,对于能量管理策略研究来说性价比不高。二阶RC是比较好的折中。
模型方程很简单:
- 端电压:U_t = OCV(SOC) - I_bat * R0 - U_1 - U_2
- RC网络动态:dU_1/dt = -U_1/(R1C1) + I_bat/C1,dU_2/dt = -U_2/(R2C2) + I_bat/C2
- SOC估算:SOC = SOC0 - 1/(3600 * Q) * ∫I_bat dt
其中Q是电池安时容量。以38kWh电池包、标称电压350V为例,容量大约是108Ah。如果图省事用能量积分法也可以,但电压变化会造成偏差,我建议还是用安时积分配合OCV查表。R0、R1、C1、R2、C2都可以标成SOC的函数,做成二维查表,在Simulink里直接用Lookup Table模块,比用simscape电学元件更轻量,仿真也稳定。
在MATLAB里搭的时候注意一点:电池的充放电内阻可能不同,最好分别建表。另外,SOC的积分环节记得加初始值和上下限饱和,否则仿真中途出现SOC超过0~1的区间,后面的查表和逻辑判断全都会乱。
2.2 增程器模型:发动机BSFC MAP和发电机效率MAP
增程器建模的思路和电池类似,不需要把发动机缸内燃烧过程建出来,那是发动机开发团队的事。能量管理仿真只关心一个问题:在某一个转速和扭矩下,增程器消耗多少燃油、输出多少电功率。所以发动机部分用BSFC(Brake Specific Fuel Consumption)MAP表示,横轴是转速、纵轴是扭矩,等值线是燃油消耗率(g/kWh)。发电机部分用效率MAP表示,给定转速和扭矩,查出发电效率。
增程器功率计算关系:
- 发动机输出机械功率 P_ice = T_ice * n_ice / 9550
- 油耗率 m_dot_fuel = P_ice * BSFC / 3600
- 发电机输出电功率 P_gen = P_ice * η_gen
同一发电功率下,发动机可以有不同的转速扭矩组合,但BSFC差别很大。所以在控制策略里需要预先把"最优工作线"整理出来:对每个功率需求,找出BSFC最低或综合效率最高的转速扭矩点作为目标工作点。这个最优工作线可以做成二维表,也可以写成一个MATLAB脚本,在离线环境下预先算好,再给Simulink查表。
我还加了两个工程化细节。第一,增程器从启动指令到稳定输出发电功率有一个响应时间,我把它简化为一阶惯性环节,时间常数大约1~2秒,这样不会出现功率指令阶跃导致母线电压过冲。第二,增程器输出功率变化率要限幅,我设定为5kW/s,模拟真实发动机的加/减速能力,也让控制策略的功率调整不会太激进。
2.3 电机与传动:驱动、回馈和传动效率
电机模型在外特性上是一条扭矩-转速包络线,低速区域受峰值扭矩限制,高速区域受峰值功率限制。电机效率用效率MAP,给定扭矩和转速查效率,这个MAP通常可以从供应商数据或台架实验得到。在EREV中电机是唯一的驱动单元,必须同时考虑驱动和发电两种工作状态:驱动时电池放电,效率η_mot;再生制动时电机反转发电,把动能回收到电池,效率同样按MAP查,但功率方向相反。
整车纵向动力学是模型反馈回路的终点,也是标定基础。滚动阻力、空气阻力、坡道阻力、加速阻力四部分叠加:
function F = vehicle_resistance(v, a, grade, m, Cd, A, rho, f) g = 9.81; F_roll = m * g * f * cos(grade); % 滚动阻力 F_aero = 0.5 * rho * Cd * A * v^2; % 空气阻力 F_grade = m * g * sin(grade); % 坡道阻力 F_acc = m * a; % 加速阻力 F = F_roll + F_aero + F_grade + F_acc; end得到车轮端需求力之后,乘以车速得到车轮端功率,再除以传动效率 η_trans,就是电机需要输出的机械功率。如果车辆有减速器,主减速比会影响电机转速和扭矩换算,我在参数表里用了9这个速比,轮端扭矩除以速比再除以传动效率就是电机扭矩需求。
2.4 驾驶工况与驾驶员模型
研究亏电到满电控制逻辑,工况选择很关键。我建议先用CLTC或WLTC做基础验证,再叠加一段70~80km/h左右的恒速路段。CLTC低速启停多,SOC消耗快;中高速恒速段可以让增程器发电功率大于驱动需求,SOC实打实往上涨。只跑一个NEDC或只看WLTC可能看不到完整的"亏电-满电"过程,因为高速大功率工况下增程器可能连维持SOC都困难,更别提充电。
驾驶员模型我用了PID控制,输入目标车速和实际车速的偏差,输出需求扭矩。PID参数不能随手拍,调得太激进会导致车速震荡,调得太慢会导致工况跟随误差大。我的经验是先P后PI,P给20~50,I给2~5,保证需求扭矩平滑即可。这个模块在Simulink里直接放一个PID Controller模块就能实现,注意把输出限幅在电机最大扭矩和最大再生制动扭矩之间。
3. 亏电到满电的控制逻辑:从单阈值切到状态机闭环
3.1 为什么"SOC到了就启停"会失败
先说我的反面教材。第一版控制逻辑很简单:SOC低于20%就启动增程器,高于30%就关掉。仿真结果惨不忍睹——增程器启动后给电池充电,SOC很快升到30%,然后停机;停机后纯电行驶又把SOC拉低,不到两分钟又触发启动条件。整个仿真过程增程器反复启停,燃油消耗和排放特性完全失真,电机母线电压也跟着来回波动。
问题本质是缺了两个东西:滞回比较和状态记忆。单阈值带只有20%~30%的区间,SOC实际在区间边界来回穿越时,控制指令也跟着来回切换。解决办法不是把区间拉大就完事,而是要把控制逻辑从"if-else"改成"状态机+滞回+最小运行时间"。增程器一旦启动,至少要稳定运行一段时间(比如120秒),不允许因为SOC短暂越过阈值就立刻关停;SOC一旦低于下限,也不会因为SOC升到30%就马上停机,而是保留一个安全余量。
3.2 状态机设计:CD、CS、强制充电和满电停机
我最终用Stateflow实现了四状态控制逻辑,这四个状态完成了从亏电到满电的所有场景:
表格里的SOC阈值都来自实际参数表的默认值,不是拍脑袋:
| 状态 | 进入条件 | 退出条件 | 增程器输出 |
|---|---|---|---|
| CD纯电行驶 | SOC > 30%,且无强制充电请求 | SOC ≤ 20% | 0,纯电驱动 |
| CS电量维持 | SOC ≤ 20%,且无强制充电请求 | SOC ≥ 30% | P_load + P_chg_set,维持SOC在目标区间 |
| Charge强制充电 | 手动开启或SOC ≤ 12% | SOC ≥ 95% | 发电功率尽量大,充电优先 |
| Stop停机 | Charge状态下SOC达到95% | SOC ≤ 90% | 0,等待下次循环 |
自动模式下,从亏电状态进入CS,增程器跟随驱动功率并叠加一段充电功率,SOC爬到30%后进入CD,这是常规的"维持"逻辑。强制充电模式下就不一样了,增程器持续运行,目的是把SOC从亏电一路送到95%,再进入Stop状态。Stop状态不是终态,SOC之后因为行驶消耗掉5%~10%,又会重新进入CS或者Charge,所以状态机是循环的。
为了防止状态边界上的抖动,所有状态切换条件都用了滞回。比如Charge状态退出条件是SOC>=95%,重新进入条件是SOC<=90%,中间5%的空档就是缓冲区。CD和CS之间同样有20%/30%的滞回。
3.3 SOC闭环调节和充电功率限幅
状态机只解决了"什么时候启停",还要解决"发多少电",也就是功率闭环。这里我用了一个非常直接的功率平衡关系:
P_gen = P_load + P_chg_target
其中P_load是驱动功率加附件功率,P_chg_target是希望给电池充进去的功率。只要增程器输出电功率大于负载消耗,多余部分自然流入电池,SOC上升;反过来SOC就下降。P_chg_target用一个PI控制器调节,输入是SOC目标值和当前SOC的偏差,输出是期望充电功率,再限幅到0到P_chg_max之间。
之所以用PI而不是直接查表,是因为接近目标SOC时需要平滑降功率。如果SOC在90%之前一直是30kW恒功率充电,到95%瞬间变成0,电池端电压会有一个明显的突变,BMS保护逻辑很可能介入。用PI或者分段线性降功率,让充电功率在SOC 90%~95%区间逐步减到0,就相当于模拟了电池CC-CV充电曲线的CV段。
MATLAB里实现这个限幅逻辑可以直接写一个MATLAB Function:
function Pchg = chargePowerLimit(SOC, SOC_target, Pchg_max) taper_zone = 5; % 进入目标SOC前5%开始降功率 if SOC >= SOC_target Pchg = 0; elseif SOC > SOC_target - taper_zone Pchg = Pchg_max * (SOC_target - SOC) / taper_zone; else Pchg = Pchg_max; end end增程器端还要加一层功率变化率限制,我设成5kW/s。这样即使PI输出一个大的阶跃,增程器也不会瞬间从0跳到60kW,更接近真实发动机响应,也避免母线电压过冲。
3.4 从亏电到满电的完整过程
把上述逻辑串起来,一个典型仿真过程是这样的:初始SOC 15%,打开强制充电模式。第一段,SOC在15%~20%,增程器启动并迅速升功率到60kW,除满足驱动和附件负载外,剩余功率全部充电;第二段,SOC进入20%~90%,增程器仍按较高功率输出,充电功率限制在30kW;第三段,SOC超过90%,充电功率按线性降到0;第四段,SOC到达95%,增程器停机,系统回到纯电驱动。整个过程大约需要40到50分钟仿真时间。
这里有几个细节值得注意。一是行车过程中如果驱动功率本身就很大,比如高速爬坡,增程器即使满功率60kW也可能不够同时驱动和充电,此时电池反而会小幅度放电。这不是控制逻辑错误,而是物理功率上限决定的,策略设计时要接受这种合理的SOC波动。二是为什么目标定95%而不是100%,因为充电末段的效率极低,且高SOC状态下电池回收再生制动的能力下降,日常行车到100%反而对能量管理和电池寿命都不利。
4. MATLAB模型的实现方式:Simulink结构、Stateflow和关键参数
4.1 工具选型:从零搭建还是用Powertrain Blockset
这个问题我纠结了很久,也建议你先想清楚再动手。
Simscape Electrical里有很多现成的电池、电机、发电机模块,拖动就能搭,画出来的模型很接近物理结构,看起来专业。但Simscape模型是物理域的网络,仿真步长和代数环问题会让人头疼,而且控制策略里很多信号无法直接接入物理端口,调试成本高。
Powertrain Blockset更夸张,它自带EREV Reference Application,点一下就能生成一整套带参考控制策略的整车模型,发动机、电机、电池、驾驶员、工况全都有。如果你只是想做整车参数分析,直接改参数跑就行。但问题是这个参考模型层级非常多,代码生成、总线信号、配置界面都封装好了,想在里面改SOC控制逻辑,反而比从零搭更难。
我的建议是:研究控制逻辑阶段用纯Simulink查表模型加Stateflow,物理结构用公式或者查表近似,这样每一个信号都能看到、能改、能调试;等逻辑验证完毕,再迁移到Powertrain Blockset或者Simscape做高保真验证。从零搭的模型虽然看起来朴素,但它是完全透明的,方便后续加需求、加约束。
4.2 Simulink模型层级和关键模块
顶层模型我按信号流分成六个部分,清晰,也好定位问题:
- Drive Cycle:From Workspace读入目标车速序列
- Driver Model:PID Controller输出需求加速度
- Energy Management:Stateflow模块,输出增程器启停命令和发电功率指令
- EREV Plant:包含电池、电机、增程器、纵向动力学这些被控对象
- Bus:直流母线功率平衡
- Scope/Data Logging:记录SOC、增程器功率、电池电流等
所有物理量单位统一。我用的策略是功率统一用kW,转速用rpm,扭矩用Nm,车速用km/h换算成m/s。很多仿真问题最后都出在单位不一致上,尤其是km/h和m/s的换算,在Simulink里最容易被忽略。
求解器我选择离散定步长,固定步长0.001秒,控制策略的采样周期单独设为0.01秒,用Rate Transition模块做不同步长之间的信号缓存。整车动力学模型的响应频率不高,1ms足够的,但比控制周期细,能捕捉到控制量变化引发的物理量振荡。
4.3 Stateflow状态机怎么落地
Stateflow是这套模型里我最喜欢的部分。建一个Chart,输入是SOC、P_load、force_charge_request,输出是eng_on和P_gen_ref。Chart内部就是上一节说的四个状态和状态切换条件。
在这里提醒几个容易踩的细节:
- 状态内部不要直接输出P_gen_ref的连续计算值然后马上反馈给增程器,否则容易产生代数环。输出端加一个Memory或者Rate Transition,把计算值作为一个采样信号传给物理层。
- 状态切换条件里用的SOC阈值不能只在进入状态时判断一次,要在整个状态运行期间持续判断。Stateflow默认的transition是在每个采样周期都检查的,所以设置条件是OK的。
- 增加一个duration条件防止频繁切换,例如"eng_on持续运行超过120秒后才允许从CS切换到CD",这个功能在Stateflow里可以直接用after(120,sec)这种时序运算符实现。
4.4 关键参数标定建议
这套模型里常用的参数我列成一个表,基本可以直接照抄:
| 参数 | 数值 | 说明 |
|---|---|---|
| 整车质量 | 1800 kg | 含电池、增程器 |
| 风阻系数 | 0.28 | 常见SUV/轿车水平 |
| 迎风面积 | 2.2 m² | 常见轿车水平 |
| 滚动阻力系数 | 0.012 | 沥青路面 |
| 轮胎半径 | 0.33 m | 约18英寸轮胎 |
| 主减速比 | 9 | 单级减速器 |
| 传动效率 | 0.95 | 包括减速器和半轴 |
| 电机峰值功率 | 120 kW | 满足整车动力性 |
| 电池容量 | 38 kWh | 标称350V |
| 增程器额定功率 | 60 kW | 可覆盖大部分巡航负载 |
| SOC低阈值 | 20% | 自动模式增程器启动点 |
| SOC高阈值 | 30% | 自动模式增程器停机点 |
| 强制充电目标SOC | 95% | 不追求100% |
| 最大充电功率 | 30 kW | 受电池许可限制 |
| 增程器功率变化率 | 5 kW/s | 模拟真实响应 |
| 控制周期 | 10 ms | Stateflow采样时间 |
这些参数不需要一次调准,先跑通,再根据曲线调整。比如说如果高速段SOC持续下滑,说明增程器功率不够,要么提高增程器额定功率,要么降低目标充电功率;如果增程器启停频繁,就扩大滞回区间或者增加最小运行时间。
5. 调参和踩坑实录:从波形异常反推问题根源
5.1 增程器频繁启停:不是阈值问题,是状态记忆问题
第一版仿真跑完,我看到增程器启停信号就像心电图一样密集,一秒钟的仿真数据里on/off切换了十几次。刚开始怀疑是阈值区间设得太窄,把20%~30%改成15%~35%,没用,只是把锯齿间隔拉长了一点。后来才意识到,单纯靠SOC阈值切换是省事,但问题是增程器停机后,电动机立刻从电池取电,SOC的下滑速度非常快,而增程器再启动需要时间,SOC会跌穿下阈值很多,于是整个过程变成了"启动→充满→停机→立马又被拉低→再启动"的恶性循环。
解决办法不只在阈值,而是状态机加了两个约束:最小运行时间120秒,最小停机时间60秒。增程器启动后,即使SOC已经升到30%,只要运行时间没满120秒,不允许切换回CD;停机后即使SOC已经降到20%,如果停机时间没满60秒,不允许重新启动。这两个时间窗口加进去,启停次数立刻降了一个数量级。
5.2 SOC接近满电时过充:恒功率充电的坑
另一个问题出现在强制充电模式。SOC从15%一路充到90%都很顺利,再往上去,仿真突然报错,提示电池端电压超过允许最大值。查了半天发现不是电池模型的问题,是控制策略的锅——充电功率一直保持30kW,到了SOC 92%的时候电池OCV明显升高,内阻压降叠加之后,端电压突破了BMS保护限值。
真实电池在充电末段会切换为恒压充电,充电电流逐渐减小。我在策略里加了一个线性降功率区间,SOC在90%到95%之间,充电功率从30kW线性降到0,同时把强制充电目标定在95%而不是100%。这样既避免了过压保护,也符合实际电池管理策略,仿真曲线变得平滑很多。
5.3 功率指令和SOC反馈之间的代数环
模型里还有一个让我查了半天的Simulink报错:代数环。报错信息指向Stateflow输出的增程器功率指令和电池SOC计算模块之间存在循环依赖。因为P_gen_ref的取值会影响电池充放电功率,电池功率影响SOC,SOC又反过来影响P_gen_ref的计算,如果模型里没有离散化缓存,Simulink必须在同一个步长内解这个环。
我的处理方式是把控制策略整体离散化:Stateflow和控制逻辑模块的采样周期设为10ms,增程器和电池等物理模型仍然用1ms步长,中间所有跨采样周期的信号都加Rate Transition。这样一来,控制策略在一个控制周期内使用的是上一拍采样的SOC,物理层在当前周期内执行最新的指令,循环依赖自然断开。对于整车能量管理这个量级的仿真,10ms控制延迟完全不影响结果。
5.4 用能量守恒校验模型对不对
调试到最后,我还会做一次能量守恒校验,这是判断模型是否可靠的关键一步。把所有能量源和能量消耗方积分起来:燃油消耗的化学能、电池初始电能、电机驱动消耗的能量、再生制动回收的能量、附件消耗、增程器发电量,以及电池最终剩余能量,两边应该基本相等。误差在5%以内,说明模型没有明显丢能量;如果误差大于10%,基本可以确定模型里有信号单位错误、效率算了两遍,或者某个积分模块的初值设错。
我的做法是在模型里加一个Energy Meter子系统,用积分模块分别统计各支路能量,然后在MATLAB脚本里跑完仿真后自动对比。这个方法花不了多少时间,但能救你很多次,因为单位写错这种问题从波形上看不出来,只有从能量守恒的角度才能暴露。
最后关于这套逻辑如何迁移到实车或HIL的小经验
如果你后续要做代码生成或者硬件在环测试,这套Stateflow策略可以直接生成C代码,但要注意几个工程化改动:把SOC阈值和功率限幅做成参数而不是硬编码,方便标定工程师不重新编译就调参;把控制周期从10ms改成实际VCU的调度周期,比如20ms或者50ms;增程器模型里的MAP数据要处理成适合定点的查表格式。我个人认为,先把这个透明化的MATLAB模型跑熟,把"亏电到满电"过程理解透了,再去碰官方参考模型或者实车标定,会比直接抄一个大而全的模型轻松得多。