每个做混动能量管理的人,几乎都是从逻辑门限控制起步的,我也不例外。P2构型更是这套思路最能发挥优势的舞台:发动机和电机中间夹着一个离合器,纯电、直驱、联合驱动、行车充电在物理结构上分得明明白白,控制算法只需要回答“现在走哪种模式、各给多少扭矩”这两个问题。这篇文章我就顺着一个能真正跑通的P2混动Simulink模型往下拆,把逻辑门限的门限值设计、规则表优先级、Stateflow状态机搭建、以及跑起来之后常见的坑完整过一遍。适合三类人:准备华为杯这类研究生建模赛题的同学,刚接手混动策略的工程师,还有那些想让Simulink模型从“能跑”进化到“可信”的研究生。
1. P2构型和门限控制:为什么这对组合最容易上手
1.1 P2混动到底是什么结构
P2这个代号,大家在做混动调研时应该都见过,它说的是电机在动力总成里的具体位置。布置上通常是这样的:发动机输出端先经过一个离合器K0,然后是电机转子,电机后面再接变速器。K0一断开,动力链就变成电池到电机再到车轮,车辆就是一台纯电动车;K0一闭合,发动机就可以和电机在变速器输入轴前完成扭矩耦合,既可以发动机单独驱动,也可以电机顶上去一起发力,还可以让发动机多出来的扭矩带着电机发电。
和其他混动构型比一下会更清楚。P1的电机直接装在发动机曲轴上,结构最紧凑,但发动机必须跟着转,想彻底纯电非常困难;P3/P4的电机放在变速器之后或后桥,回收效率高、纯电体验好,但联合驱动时发动机和电机的扭矩在轮端不容易做挡位配合,低速爬大坡时电机能力容易被轮端扭矩要求放大。P2的优势在于保留了传统变速器,电机又能和发动机完全解耦:要纯电时离合器一断,发动机就是个纯粹的乘客;要动力时离合器一合,两个动力源还能通过变速器挡位一起发力。正因为这种物理上的解耦,P2能组合出的控制模式比P1和P3更完整,也最适合拿来做能量管理策略的教学和验证。
1.2 为什么逻辑门限控制特别适合P2
混动能量管理的数学本质,其实是两个嵌套在一起的问题:外层是模式选择,这是个整数变量;内层是给定模式下发动机和电机怎么分配扭矩,这是个连续变量。真正的全局最优可以用动态规划、Pontryagin极小值原理、凸优化去做,但代价是计算开销、标定难度和对非线性模型的容忍度都会陡增。工程上最实用的妥协方案,就是用一组门限值把工况切成若干区域,每个区域对应一条固定的决策规则——这就是逻辑门限控制。
门限控制说白了,就是把“高效区间在哪里”这件事翻译成边界值。低速小负荷是电机的高效区,就切纯电;中高速中等负荷是发动机的高效区,就切直驱;负荷超过发动机经济区上限或者电量不足时,就并联或者充电。这样做的好处是几乎没有计算负担、规则完全可解释、改一个门限就能直接看到油耗变化趋势,而且在Simulink里用Stateflow或者普通条件选择模块都能实现。很多量产车的初版标定其实就是门限加查表,区别只是表格更密、门限更多。所以无论你后面打算做ECMS、做动态规划还是做强化学习,门限控制都是那个最值得先跑通的baseline。
2. 门限值怎么定:从整车需求倒推控制规则
2.1 先明确门限控制的输入和输出
门限控制的输入,习惯上取三个量:电池SOC、当前车速、驾驶员需求扭矩。输出是模式代号、发动机扭矩指令、电机扭矩指令。三个输入里最容易被忽略的是需求扭矩,很多初学的人只拿SOC和车速做门限,后面做低速爬坡或高负荷超车时会发现逻辑完全错乱。原因也很简单:车速低不一定代表负荷小,坡道对扭矩的需求可能远超电机能力,如果不把扭矩纳入判断,门限控制就没有办法保护电池和电机。
扭矩信号的参考轴也要提前统一。我强烈建议把所有扭矩定义在变速器输入轴,也就是电机和发动机所在的轴。原因在于控制器最终写出去的指令就是这个轴上的扭矩,而轮端需求扭矩要先除以总速比才能回到这个轴。这个换算关系看着简单,做混动模型的人十个里有九个在单位换算上翻过车,后面我会专门讲。
2.2 门限参数有哪些,取值思路是什么
下面是P2逻辑门限控制里最常用的几个门限参数,以及它们各自的作用。这些值是常见工程标定的起始参考,并不是某个车型的真实参数,具体车型必须根据部件MAP重新标定。
| 门限参数 | 示例起始值 | 物理意义 | 取值思路 |
|---|---|---|---|
| SOC_sustain_low | 0.30 | 最低保电门限 | 低于此值进入强制行车充电 |
| SOC_sustain_high | 0.50 | 退出充电门限 | 高于此值停止强制充电,中间留迟滞 |
| v_ev_max | 40 km/h | 纯电允许最高车速 | 取电机在对应挡位下高效率工作的车速区间 |
| T_ev_max | 电机峰值扭矩留10%裕量 | 纯电允许最大需求扭矩 | 高于此值即使车速低,也应启动发动机 |
| T_charge_add | 15到30 N·m | 行车充电附加扭矩 | 发动机在多出的扭矩段带动电机发电 |
| T_ice_opt(n) | 查BSFC最低油耗曲线 | 每个转速下经济区扭矩 | 从发动机万有特性曲线提取 |
门限不是拍脑袋定的,都能从部件特性倒推出来。T_ev_max基本就是电机的峰值扭矩Map再留出10%的保护裕量;v_ev_max看电机在某个挡位下能不能覆盖日常30%到40%的行驶区间;T_charge_add要小于发动机在对应转速下能稳定运行的最大扭矩,否则低速充电时发动机会被拖到很难看的工况区;SOC下限则受电池倍率性能和寿命约束,乘用车通常在0.25到0.35之间。
2.3 规则表的优先级比门限数值更关键
逻辑门限控制能不能用得好,判断顺序的优先级比门限数值本身更重要。我见过不少模型,门限设得挺漂亮,结果低SOC时还在纯电,就是因为规则顺序写反了。我建议的优先级是:制动回收先单独走一条路径;正常驱动情况下,强制保电优先级最高,其次纯电,再次并联,最后直驱。充电逻辑必须是“无条件拦截”,只要SOC低于下限,其他所有正常模式都让位。
一个可以落地的规则表如下,按优先级从高到低排列:
| 优先级 | 条件 | 控制模式 | 发动机扭矩指令 | 电机扭矩指令 |
|---|---|---|---|---|
| 1 | SOC低于SOC_sustain_low | 行车充电 | T_req + T_charge_add | -T_charge_add(发电) |
| 2 | SOC较高,且车速低于v_ev_max,且T_req低于T_ev_max | 纯电EV | 0 | T_req |
| 3 | T_req高于发动机经济区扭矩 | 联合驱动 | T_ice_opt(n) | T_req - T_ice_opt(n) |
| 4 | 其他正常驱动工况 | 发动机直驱 | T_req | 0 |
| 5 | 制动且SOC未满 | 能量回收 | 0 | 取制动扭矩限值和电机能力的小值 |
这个规则表背后的逻辑很清晰:纯电模式是一组AND条件,只要车速、扭矩、SOC三个条件任何一个不满足,就退回燃油或并联模式;联合驱动则专门盯需求扭矩是否超过了发动机经济区,超过的部分交给电机补,目的是让发动机始终不离开万有特性的高效区。这套逻辑几乎可以解释所有门限控制策略的骨架。
2.4 迟滞带:为什么门限不能是单值
上面表格里的门限,实际工程里大多数不能直接用单值,必须拆成进入门限和退出门限两套值。原因很简单:车速或扭矩在门限附近扰动时,单值门限会让模式在一个步长里来回切,每次切换都伴随离合器动作和发动机启停。假如跑一个WLTC工况,硬门限可能会导致上百次切换,这个结果拿去做耐久性仿真等于灾难。
具体做法有两种。第一种是双门限迟滞,比如车速门限拆成v_ice_on=45启动发动机、v_ice_off=35关发动机,中间留10km/h宽度的迟滞带。这样即使车速在40附近上下波动,只要没有顶过45又掉到35,发动机状态就一直保持。SOC门限也一样,强制充电下限设为0.30,退出充电上限设为0.50,中间带0.2的宽度。第二种是加最小驻留时间,比如要求发动机启动后至少运行3秒才允许切回EV,这在Stateflow里等于状态内的计时器判断。
迟滞带本质上是用一点效率换稳定性:模式保持时虽然偶尔会在一个不那么优的区域多待几秒,但省掉了反复启停发动机的燃油、排放和顿挫成本,综合来看非常划算。宽度怎么标定?在Simulink里把两个门限分别做成参数,跑同一工况统计切换次数和等效油耗,画一条tradeoff曲线找拐点即可,和实车标定的思路完全一致。
3. Simulink模型骨架搭建:接口约定、Stateflow状态机、动力源简化
3.1 顶层架构怎么分层,接口怎么约定
仿真建模第一步一定不是急着画模块,而是先把信号流向定下来。P2混动模型我习惯分成六块:驾驶员模块、能量管理策略、发动机、电机、电池、车辆纵向动力学。驾驶员模块按目标工况的车速曲线做PI闭环,输出需求扭矩;能量管理策略接收SOC、车速、需求扭矩,输出模式与扭矩指令;发动机、电机、电池、车辆动力学模块按照指令执行并反馈状态。
接口约定是建模中最容易被低估的环节。我把常用信号整理成一张表,建模型前先按这个约定布线,后面联调会省很多事:
| 信号 | 接口位置 | 单位 | 说明 |
|---|---|---|---|
| T_req | 驾驶员模块输出到EMS | N·m | 统一到变速器输入轴 |
| v_veh | 车辆模型反馈到EMS | km/h | 门限判断用 |
| SOC | 电池模块输出到EMS | % | 门限判断用 |
| mode | EMS输出到记录 | - | 模式代号,建议用整数枚举 |
| T_ice_ref | EMS输出到发动机 | N·m | 发动机扭矩指令 |
| T_mot_ref | EMS输出到电机 | N·m | 正为驱动,负为发电 |
同样的扭矩,定义在不同轴上是完全不同的数。如果你在驾驶员模块里直接用轮端需求扭矩去对比T_ev_max,就必须先除以总速比。很多人在这里踩坑:轮端扭矩是大几千牛米,电机峰值扭矩只有三百多牛米,一对照发现怎么都不可能纯电,其实是忘了除以速比。
3.2 用Stateflow实现带迟滞的模式状态机
门限控制的状态机在Stateflow里实现非常顺,因为Stateflow的迁移条件天然支持两个方向不对称的门限值,正好对应迟滞带。我的做法是建四个状态:EV、ICE_Drive、ICE_Charge、Combine,其中Combine兼作联合驱动状态。下面是核心迁移逻辑的示意写法:
{EV} on entry: T_ice_ref = 0; T_mot_ref = T_req; transition to ICE_Charge: SOC < SOC_sustain_low; transition to ICE_Drive: v_veh > v_ice_on || T_req > T_ev_max; {ICE_Drive} on entry: T_ice_ref = T_req; T_mot_ref = 0; transition to EV: v_veh < v_ice_off && T_req < T_ev_max && SOC > SOC_sustain_low; transition to ICE_Charge: SOC < SOC_sustain_low; transition to Combine: T_req > T_ice_opt(v_veh); {ICE_Charge} on entry: T_ice_ref = T_req + T_charge_add; T_mot_ref = -T_charge_add; transition to ICE_Drive: SOC > SOC_sustain_high && T_req > T_ev_max; transition to EV: SOC > SOC_sustain_high && v_veh < v_ev_max && T_req < T_ev_max; {Combine} on entry: T_ice_ref = T_ice_opt(n_ice, gear); T_mot_ref = T_req - T_ice_ref; transition to ICE_Drive: T_req < T_ice_opt(n_ice, gear) - 5;里面有几个细节值得说。EV到ICE_Drive的退出条件,我故意把v_ice_on和T_ev_max用OR连接而不是AND。因为低速爬坡时车速可能只有20km/h,但需求扭矩已经超过电机能力,这时如果还在EV硬顶,电池放电倍率会超标。门限控制最容易漏掉的就是这个“扭矩超限”条件。反过来,ICE_Drive回到EV的条件用了AND,要求车速、扭矩、SOC三个条件同时满足,这就能有效防抖。
另一个工程建议是加最短驻留时间。在ICE_Drive状态的迁移条件中加一个after(3, sec),表示发动机启动后至少运行3秒才允许切回EV。这一步能显著降低WLTC低速段里发动机反复启停的次数,而且实现成本极低,值回票价。
3.3 动力源模型怎么简化而不失真
发动机模型对门限控制策略研究来说不需要燃烧细节,做准静态就够:输入转速n_ice和扭矩T_ice_ref,查二维BSFC map,输出比油耗,再换算成瞬时油耗。换算公式是P_kW = T_ice_ref * n_ice / 9550,瞬时油耗gm_s = bsfc_g_kWh * P_kW / 3600。注意转速单位是rpm,如果你在Simulink里用积分器算出的是rad/s,必须乘60/(2π)转回rpm,否则油耗算出来能差一百倍。
电机模型也是查效率Map,但效率Map要分驱动方向和发电方向,两类效率并不一样。驱动时电机功率由电池输出,P_bat = P_mech / η;发电时电机功率输出给电池,P_bat = P_mech * η。我习惯把发电时的T_mot_ref写成负值,这样P_mech = T_mot_ref * n_motor / 9550会自动变负,电池功率自然按符号流进电池,不用再额外判断正负方向。
电池模块用安时积分法测SOC就够了,表达式是SOC_percent = SOC0 - (1/(Q_Ah * 3600)) * ∫P_bat_w dt * 100。这里P_bat_w的单位必须是瓦特。如果你用kW就一定要乘1000。另外,为了让SOC尽量真实,可以在开路电压OCV查表之外再串一个简单内阻修正,但门限控制研究阶段不做也能跑,前提是你别把SOC曲线当精确值去解读。
车辆纵向动力学模型则用一个纵向力平衡就够了:驱动力减去滚动阻力、空气阻力和坡道阻力,等于质量乘加速度,加速度积分得到车速。驱动力从变速器输入轴扭矩乘挡位速比、主减速比和传动效率,再除以车轮半径得到。转速反过来由车速除以车轮半径再乘总传动比得到。这套模型虽然简化,但能真实反映门限切换时的车速响应,用来做策略对比完全够用。
3.4 把EMS独立成子系统,为联合仿真留好口子
建模型时有一个容易后悔的决策:把能量管理策略和车辆模型全画在一个图层里。前期调试看着无所谓,一旦要换车辆动力学软件做联合仿真,或者要做软件在环测试,就得返工。我的习惯是EMS做成独立子系统,所有输入输出走Bus总线,顶层只保留几个关键接口。这样后面如果要接Carsim这类第三方动力学软件,直接替换车辆模型那部分,EMS和动力源模块都不用动。这个设计思路在竞赛和实际项目里都非常实用。
4. 仿真跑起来之后的调参日志:模式震荡、代数环、SOC漂移
4.1 低速爬坡时模式来回跳的根因排查
第一个让我印象最深的问题是“低速爬坡时EV和ICE_Drive来回切”。症状是车速大约25km/h,需求扭矩在电机峰值附近波动,模型一会纯电一会直驱,一个WLTC统计下来切换两百多次。当时第一反应是看门限值,但v_ev_max明明设成40,车速25根本不满足,为什么还会切?
顺着日志往细看才发现,问题的根源不是车速门限,而是扭矩门限。原始规则里写了“需求扭矩超过电机峰值就切ICE”,但退出ICE的条件里却没有扭矩迟滞。于是当需求扭矩在峰值附近抖动时,模式就跟着抖。修法也很明确:把EV到ICE_Drive的触发条件改为T_req > T_ev_max,要求真正高过峰值;ICE_Drive回到EV的条件则改为T_req < T_ev_max * 0.8,低于峰值的80%才允许退出。两个门限之间留出20%的迟滞区,再配合车速双门限,这一改切换次数就从两百多次降到了三四十次。
这个案例的关键在于:门限控制的迟滞带不是只对车速和SOC起作用,扭矩门限同样需要。而且触发条件和退出条件要分开写,不能共用同一个判断式。
4.2 代数环是被扭矩输入绕出来的
第二类常见问题是Simulink提示出现Algebraic Loop,或者仿真速度突然慢得离谱。我当时排查时把信号链一层层看过去,发现EMS输出的电机扭矩进了车辆模型,车辆模型算出车速,车速又进入变速比计算,变速比乘回电机当前扭矩,这个扭矩又回到EMS输入。同一个变量绕成一个等号,Simulink只能靠迭代求解,自然又慢又不稳。
解决办法有两个,我建议先把接口层解耦:驾驶员模型根据目标车速和实际车速的差,直接计算出需求扭矩估计值发到EMS;车辆模型内部的实际扭矩只负责驱动整车动力学。需求扭矩不等于实际扭矩没有关系,控制策略本来要的是驾驶员意图,而不是物理负反馈的信号循环。第二个办法是在交叉信号链路上插一个Unit Delay,把信号延迟一拍。这样会引入一个采样周期的控制延迟,对策略研究影响很小,但能立刻切断代数环。
4.3 SOC漂移多数是单位问题
还有一类问题是SOC莫名其妙往上走。我当时怀疑是电机发电判反了,抓了一个变量看P_bat,发现纯驱动时P_bat反而是负的。再往下查,电池子系统里容量用的单位是Ah,功率用的单位是kW,结果SOC表达式写成SOC0 - (1/Q) * ∫P_kW dt,量纲错了两个数量级。修正成瓦特和安时统一后,曲线立刻恢复正常。
另一个SOC问题是积分漂移。固定步长求解器如果步长取0.1秒,电池功率变化快时SOC曲线会有明显锯齿;建议把步长取到0.01秒或者更小,算得慢一点但曲线干净。如果跑的是500秒的WLTC,0.01秒步长也完全能接受。再补充一点:SOC的初值设置也会影响观感,我一般设在0.5附近,这样工况跑完能看到明显的充电和放电过程,门限动作比较直观。
4.4 发动机一直开关式工作说明优先级没卡住
还有种常见现象:SOC明明已经掉到0.25,发动机还是按需启停,时不时出现纯电。这就是状态机优先级写反了。很多初学者喜欢把判断顺序写成先看车速再看SOC,所以EV的迁移条件最先满足。在Stateflow里,迁移是有优先级的,靠下的迁移条件即使同样满足,也会被上面的先触发。只要EV的迁移排在前面,低SOC时它照样纯电。
我的习惯是把强制充电迁移放在EV和ICE_Drive迁移列表的最前面,用无条件高优先级来保证“只要SOC低于下限,任何状态都跳过去”。在Stateflow里可以用Transition Order去拖拽调整优先级,也可以写复合条件时把SOC判断放在第一个guard位置。验证方法很简单:把SOC初值设成0.2,跑一段工况,观察发动机是否一直在运行且SOC在缓慢回升。如果发动机没有持续运行,那答案就是优先级仍不对。
5. 从“能跑”到“可信”:SOC修正、切换统计与门限敏感性
5.1 评估油耗前必须先做SOC修正
到了验证阶段,最容易犯的错误是拿不同初始SOC的仿真结果直接比油耗。跑WLTC时,SOC初值0.6,终值0.4,等于车里多用了0.2个SOC的电,纯油消耗自然低,但这不代表策略厉害,而是电池在帮你扛。正确做法是让初始SOC和终端SOC尽量一致,或者做电量修正。
简洁的修正是先算电量变化量ΔE = (SOC0 - SOC_final) * Q_Ah * 3600 * V_bat_nominal,把Wh折算成kWh,再按试验标准里的折算系数换算成等效油耗。不同电池电压和平均发动机效率会让系数在0.08到0.12 L/kWh之间浮动,所以最好每次标定都记录清楚自己用的系数。提交结果时把SOC轨迹画出来,注明初末值,评审或同事才会觉得这份数据有说服力,这也是竞赛报告中常见的加分项。
5.2 用切换次数和门限敏感性给策略定案
门限控制能不能定案,光看一次工况不够。我会同时关注三个指标:总油耗、SOC终值、模式切换次数。切换次数可以直接对模式信号做差分统计,也可以用Stateflow自带的运行事件记录来数。如果切换次数超过人工可接受的阈值,说明迟滞带或驻留时间还没标定好;如果SOC终值明显偏离初值,说明保电策略失衡。
标定敏感性的具体做法是:选定一个代表性门限,比如v_ice_on,在正负20%范围扫5到7个点,每次跑同一工况,记录油耗和切换次数,做成一张小表。你会很直观地看到油耗不是单调的,存在一个拐点区域,这个区域就是当前工况下的推荐门限。这种数据放到竞赛论文或者项目报告里,比单纯贴几条曲线有说服力得多,也方便后续评审质疑时快速复盘。
5.3 从门限控制向ECMS、DP与代码生成扩展
门限控制最大的价值,是当一个可解释的baseline。我自己做项目的顺序是先跑通门限,统计SOC轨迹和发动机工作点分布,然后会发现门限策略的发动机工作点基本集中在BSFC低油耗区附近,只是边界不如高级算法那么平滑。这个时候再上ECMS或动态规划,就有了参照物:ECMS的等效因子可以按SOC轨迹的斜率去调,动态规划得到的最优SOC路径也可以和门限控制的SOC轨迹做对比,差异一目了然。
如果项目要做代码生成或者硬件在环,Stateflow实现的逻辑门限在Simulink Coder里生成C代码非常方便,因为整个策略全是离散状态和查表,没有浮点迭代逻辑。有两点要注意:一是所有门限参数要抽成模型参数变量,不要硬编码在常量里,否则刷写标定的时候你会在一个不显眼的地方迷失;二是模式信号最好用枚举类型或纯整数,方便上位机解析,也方便和底层代码对接。
最后说点我自己的习惯。我现在审阅模型或者带新人,只要看到规则表里没有明显的优先级顺序,基本就能预判后面一定会出振荡问题。反过来,把门限控制老老实实跑透的人,后面去做ECMS、动态规划这些进阶算法会非常快,因为你知道自己在优化什么。如果你搭模型时也遇到“逻辑明明写对了,模式就是乱跳”这种玄学问题,优先查三样东西:迟滞带有没有留、强制充电优先级有没有提到最高、单位有没有统一。这三样检查完,绝大多数问题当场就能解决。