我们刚刚在 Simulink 中搭建的,在汽车工程界被称为 平均值发动机模型 (Mean Value Engine Model, MVEM)。
要理解它的原理,首先要明白"平均值"三个字的含义。真实的四冲程发动机(进气、压缩、做功、排气)在微观上是非常暴躁、断续的,每个气缸的压力都在剧烈波动。但 MVEM 模型忽略了这种曲轴转角级别的毫秒级波动,将发动机视为一个连续运转的"黑盒" ,只计算几个发动机周期内的平均物理量。
这使得模型既能准确反映发动机的动态迟滞,又不会因为计算量太大而卡死,是做 ECU 控制算法(比如你刚做的怠速启停)最完美的模型。
它的核心原理建立在三大经典物理定律之上,正好对应你搭建的三个子系统:
1. 进气歧管动态:质量守恒定律 (流体力学)
进气歧管(节气门之后、气缸之前的管道)就像一个带有进气口和出气口的弹性气球。
- 流入(节气门): 当你踩下油门开大节气门时,空气并不是瞬间冲进气缸的,而是先进入进气歧管。
- 流出(气缸抽气): 发动机的活塞像水泵一样,不断从这个歧管里把空气抽走。
- 原理: 歧管内部的压力变化率,完全取决于"进气速度"和"抽气速度"的差值。如果进气比抽气快,歧管压力就上升;反之则下降。这就是为什么你在这个子系统里必须用一个 积分器 (Integrator)。
物理方程:
dPmandt=R⋅TmanVman(m˙in−m˙out)\frac{dP_{man}}{dt} = \frac{R \cdot T_{man}}{V_{man}} (\dot{m}{in} - \dot{m}{out})dtdPman=VmanR⋅Tman(m˙in−m˙out)
(这就是为什么你踩下油门后,发动机动力总是会"慢半拍"的核心原因------歧管需要时间来"充气"建立压力。)
2. 燃烧扭矩:热力学映射与做功迟滞
发动机产生扭矩的大小,本质上取决于气缸里吸进了多少空气(由前面的歧管压力决定),以及当前的转速。
- 查表法 (MAP): 我们没有在模型里写复杂的化学燃烧方程,而是使用了台架测试标定好的 二维查表 (2-D Lookup Table)。这相当于直接告诉模型:"在某压力、某转速下,你能爆发出多少力气"。
- 物理延迟: 空气进入气缸后,还要经过压缩冲程才能点火做功。四缸机大约有半圈(180度)曲轴转角的延迟。所以你在模型中加了一个变传输延迟 (Variable Transport Delay) 模块,延迟时间 τ=30N\tau = \frac{30}{N}τ=N30。转速越慢,延迟越长。
3. 曲轴动力学:牛顿第二定律 (刚体转动)
这是初中物理 F=maF = maF=ma 的旋转版本。
- 原理: 发动机燃烧产生的"净扭矩"(已经扣除了自身摩擦),与测功机或车轮施加的"外部阻力扭矩"进行拔河。
- 如果 净扭矩 > 阻力扭矩,曲轴就会加速旋转。
- 如果 净扭矩 < 阻力扭矩,曲轴就会减速。
- 你在这个模块用的 积分器,就是将角加速度积分成了最终的发动机转速 (RPM)。
物理方程:
dNdt=30π⋅J(Tnet−Tload)\frac{dN}{dt} = \frac{30}{\pi \cdot J} (T_{net} - T_{load})dtdN=π⋅J30(Tnet−Tload)
(其中 JJJ 就是转动惯量,它决定了转速上升和下降的"平滑程度"。重飞轮的发动机,转速变化就很迟钝。)
请打开一个空的 Simulink 模型文件 (Blank Model),我们分四个核心子系统进行搭建。
第一部分:进气歧管压力子系统 (Intake Manifold)
这个子系统的目标是计算实时的进气歧管绝对压力 (PmanP_{man}Pman)。为了模型稳定且易于搭建,我们使用二维查表法来代替复杂的流体力学公式。
1. 拖拽以下模块到画布:
- Inport (2个):在库浏览器中搜
Inport。 - 2-D Lookup Table (2个):搜
2-D Lookup Table。 - Sum (1个):搜
Sum。 - Gain (1个):搜
Gain。 - Integrator (1个):搜
Integrator。 - Outport (1个):搜
Outport。
2. 双击模块设置参数:
-
Inport 1 :双击,将
Block name改为Throttle_Cmd (%)。 -
Inport 2 :双击,将
Block name改为RPM_Feedback。 -
第一个 2-D Lookup Table (流入质量 m˙in\dot{m}_{in}m˙in):
-
双击,改名为
m_dot_in_Table。 -
Breakpoints 1(节气门开度):[0 10 30 60 100] -
Breakpoints 2(歧管压力Pa):[20000 40000 60000 80000 101300] -
Table data(流入流量 kg/s):[0 0 0 0 0; 0.005 0.004 0.003 0.001 0; 0.015 0.012 0.009 0.003 0; 0.04 0.035 0.025 0.01 0; 0.06 0.05 0.04 0.015 0] -
第二个 2-D Lookup Table (流出质量 m˙out\dot{m}_{out}m˙out):
-
双击,改名为
m_dot_out_Table。 -
Breakpoints 1(转速RPM):[800 2000 4000 6000] -
Breakpoints 2(歧管压力Pa):[20000 50000 80000 100000] -
Table data(流出流量 kg/s):[0.002 0.005 0.008 0.01; 0.006 0.015 0.025 0.03; 0.015 0.035 0.06 0.075; 0.02 0.05 0.08 0.1] -
Sum :双击,将
List of signs改为|+-。 -
Gain :双击,将
Gain设为43050000。(这是物理常数 R⋅TVman=287⋅3000.002\frac{R \cdot T}{V_{man}} = \frac{287 \cdot 300}{0.002}VmanR⋅T=0.002287⋅300 计算得来的)。 -
Integrator :双击,将
Initial condition设为35000(代表怠速歧管压力 35kPa,千万不能是 0 ,否则查表报错)。勾选Limit output,Lower limit设为10000,Upper limit设为105000。 -
Outport :双击,改名为
P_man。
3. 连线方式 (Wiring):
- 将 Inport 1 (Throttle_Cmd) 连到 m_dot_in_Table 的第一个输入端。
- 将 Integrator 的输出端拉出一条反馈线,连到 m_dot_in_Table 的第二个输入端。
- 将 Inport 2 (RPM_Feedback) 连到 m_dot_out_Table 的第一个输入端。
- 将 Integrator 的输出端再拉出一条反馈线,连到 m_dot_out_Table 的第二个输入端。
- 将 m_dot_in_Table 的输出连到 Sum 的
+端。 - 将 m_dot_out_Table 的输出连到 Sum 的
-端。 - 将 Sum 的输出连到 Gain 的输入。
- 将 Gain 的输出连到 Integrator 的输入。
- 将 Integrator 的输出连到 Outport (P_man)。
需要做的具体修改步骤:
- 断开连线: 删除目前
Gain模块输出端到P_man端口之间的连线。 - 移动模块: 将左侧那个悬空的 积分器 (
1/s) 拖拽移动到右边,放在Gain和P_man之间。 - 重新连接主线: 将
Gain的输出端连接到 积分器 的输入端;然后再将 积分器 的输出端连接到P_man端口。 - 重新连接反馈线: 从 积分器的输出端 (也就是它和
P_man之间的那根线上)引出节点,像你现在画的那样,分别连接给上下两个 2-D Table 的u2输入端。
修改后的主干信号流向应该是这样的直线串联:
Sum 输出 →\rightarrow→ Gain →\rightarrow→ Integrator →\rightarrow→ Outport (P_man)
然后从 Integrator 的后面取信号反馈给前面。按照这个逻辑调整后,第一部分的物理意义和模型结构就完全正确了。
第二部分:扭矩生成与做功延迟子系统 (Torque Production)
这个子系统将压力和转速转化为发动机产生的扭矩。
1. 拖拽以下模块到画布:
- Inport (2个)。
- 2-D Lookup Table (1个)。
- 1-D Lookup Table (1个)。
- Math Function (1个):在
Math Operations库下。 - Gain (1个)。
- Variable Transport Delay (1个):在
Continuous库下。 - Sum (1个)。
- Outport (1个)。
2. 双击模块设置参数:
-
Inport 1 :改名为
P_man_Input。 -
Inport 2 :改名为
RPM_Input。 -
2-D Lookup Table (指示扭矩):
-
改名为
Indicated_Torque_Map。 -
Breakpoints 1(RPM):[800 2000 4000 6000] -
Breakpoints 2(Pressure):[30000 50000 80000 100000] -
Table data(Nm):[15 35 60 75; 30 70 120 145; 40 90 160 190; 35 85 140 165] -
Math Function :双击,
Function选择reciprocal(取倒数),用于计算延迟时间 1RPM\frac{1}{RPM}RPM1。 -
Gain :设为
30。(时间延迟公式 τ=30RPM\tau = \frac{30}{RPM}τ=RPM30)。 -
Variable Transport Delay :双击,
Maximum delay设为0.2,Initial output设为15。 -
1-D Lookup Table (摩擦扭矩):
-
改名为
Friction_Torque。 -
Breakpoints 1:[0 800 2000 4000 6000] -
Table data:[5 12 18 28 42] -
Sum :将
List of signs改为|+-。
3. 连线方式 (Wiring):
- 将 Inport 2 (RPM) 连到 Indicated_Torque_Map 的第一个输入;将 Inport 1 (P_man) 连到第二个输入。
- 将 Inport 2 (RPM) 分支引出,连到 Math Function (reciprocal)。
- 将 Math Function 连到 Gain (30)。
- 将 Indicated_Torque_Map 的输出连到 Variable Transport Delay 的第一个输入端 (数据端口)。
- 将 Gain (30) 的输出连到 Variable Transport Delay 的第二个输入端 (时间延迟控制端口
*td)。 - 将 Inport 2 (RPM) 再次分支引出,连到 1-D Lookup Table (Friction_Torque)。
- 将 Variable Transport Delay 的输出连到 Sum 的
+端。 - 将 Friction_Torque 的输出连到 Sum 的
-端。 - 将 Sum 的输出连到 Outport ,改名为
Net_Torque。
第三部分:曲轴转速计算子系统 (Crankshaft Dynamics)
利用净扭矩和外部负载计算转速。
1. 拖拽与设置:
- Inport 1 :命名为
Net_Torque。 - Inport 2 :命名为
Load_Torque(测功机阻力)。 - Sum :
List of signs设为|+-。 - Gain :设为
47.74。 (这是 30π⋅J\frac{30}{\pi \cdot J}π⋅J30 的结果,假设惯量 J=0.2 kg⋅m2J = 0.2 \text{ kg}\cdot\text{m}^2J=0.2 kg⋅m2)。 - Integrator :
Initial condition设为0。勾选Limit output,Lower limit设为0,Upper limit设为7000。 - Outport :命名为
Engine_RPM。
2. 连线方式 (Wiring):
- 将 Inport 1 (Net_Torque) 连到 Sum 的
+端。 - 将 Inport 2 (Load_Torque) 连到 Sum 的
-端。 - 将 Sum 连到 Gain (47.74)。
- 将 Gain 连到 Integrator。
- 将 Integrator 连到 Outport (Engine_RPM)。
(注意:将第一、二、三部分的 Outport 和 Inport 对应连接起来,形成一个闭环,你的物理被控对象就搭建完成了。进气管的 RPM Feedback 必须连到曲轴模块输出的 Engine_RPM 上。)
第四部分:启停与怠速控制系统 (Controller)
这部分负责输出节气门指令 (Throttle_Cmd)。
1. 拖拽与设置:
-
Discrete PID Controller:
-
双击,
Controller选PID。 -
Time domain选Discrete-time。 -
Proportional (P)设为0.2。 -
Integral (I)设为0.05。 -
点开
PID Advanced选项卡,勾选Limit output,Upper limit设为20,Lower limit设为0(怠速时节气门最多开20%)。 -
Constant 1 :设为
800(怠速目标转速)。 -
Sum :
List of signs设为|+-。 -
Switch :双击,
Criteria for passing first input选u2 >= Threshold,Threshold设为0.5。
2. 连线方式 (Wiring):
- 将 Constant (800) 连到 Sum 的
+端。 - 将全局实际转速 Engine_RPM 连到 Sum 的
-端。 - 将 Sum 连到 Discrete PID Controller。
- 将 Discrete PID Controller 的输出连到 Switch 的第一个输入端 (端口 1)。
- 创建一个新的 Inport 命名为
Accel_Pedal(油门踏板,0-100),将其连到 Switch 的第三个输入端 (端口 3)。 - 创建一个 Constant ,值为
1或0,连到 Switch 的中间控制端 (端口 2)。
- 手动测试说明:当 Constant 为 0 时,Switch 导通踏板信号 (动态加速);当 Constant 为 1 时,Switch 导通 PID 信号 (闭环怠速)。
- 将 Switch 的输出连到 第一部分 (进气系统) 的 Throttle_Cmd 输入端。
按照上述具体的数值和连接口一一对应搭建,点击 Run 仿真,你应该能看到模型在 800 转附近平稳收敛,并且在改变负载 (Load_Torque) 时,PID 会自动调节节气门将转速拉回 800。
下面我为你详细指出需要调整的唯一地方------顶层连线(Top-Level Wiring):
内部审查反馈(做得非常好的地方)
- 图3(进气歧管内部): 积分器、反馈线、加减法方向完全正确。
- 图4(扭矩生成内部): 延迟模块的转速倒数时间控制、查表映射完全正确。
- 图5(转速与控制器内部): 动力学积分、PID 反馈闭环、Switch 切换逻辑完美实现。
- 小建议:图5最右侧输出给 Switch 的 Outport
2,建议双击改名为Throttle_Out,这样在顶层看的时候更清晰。
需要修改的地方:打通全局闭环(针对图1/图2)
请在顶层视图执行以下"连连看"操作:
- 连接节气门指令(连接控制与进气):
将右下角方块(Subsystem2)的第二个输出端口(即你内部连着 Switch 的那个端口),直接连到左侧方块(P_man进气子系统)的throttle_cmd输入端口上。 - 连接歧管压力(连接进气与扭矩):
将左侧方块(P_man)的输出端口,直接连到上方中间方块(Net_Torque1)的P_man_Input端口上。 - 连接净扭矩(连接扭矩与动力学):
将上方中间方块(Net_Torque1)的输出端口,直接连到右下角方块(Subsystem2)的Net_Torque输入端口上。 - 连接转速全局反馈(最关键的一步):
右下角方块(Subsystem2)输出的Engine_RPM(端口1)是全局的核心信号。你需要从这个端口拉出一条长线,分成两路:
- 一路连回左侧方块的
RPM_Feedback端口。 - 另一路连回上方中间方块的
RPM_Input端口。
- 添加外部激励信号:
在空白处拖入两个Constant(常数)模块:
- 第一个命名为
外部负载,连到右下角方块的Load_Torque输入端(设定为如 20 Nm)。 - 第二个命名为
油门踏板,连到右下角方块的Accel_Pedal输入端(设定为 0)。
完成这些连线后,你的屏幕上应该只剩下三个相互连接的方形子系统和两个常数输入。点击 Run,你的发动机模型就能真正运转起来并稳定在 800 转了!
为了最直观地评估你的模型,我建议你添加 3个核心 Scope。你可以直接在顶层视图(Top-Level)的那些连线上引出分支来接 Scope,这样最清晰。
核心观测点 1:全局转速 (Engine Speed) ------ 这是最终结果
这是衡量你模型是否成功的最关键指标。
- 位置: 在右下角方块输出的
Engine_RPM那根长线上,拉出一个分支,接上一个Scope。 - 双击 Scope 命名为:
RPM_Scope - 你应该看到的波形: 点击运行后,转速应该从 0 开始迅速上升,稍微越过 800(超调),然后在一两秒内平滑地稳定在一条 800 RPM 的水平直线上。
核心观测点 2:进气歧管压力 (Intake Manifold Pressure) ------ 这是动态过程
发动机的"迟滞"主要来源于这里。
- 位置: 在左侧方块输出的
P_man那根线上拉出一个分支,接上第二个Scope。 - 命名为:
MAP_Scope(Manifold Absolute Pressure) - 你应该看到的波形: 启动瞬间,压力会有一个大的波动,稳定怠速后,绝对压力应该停留在 30,000 ~ 40,000 Pa (30-40 kPa) 左右。如果你把节气门突然开大,压力不会瞬间跳跃,而是呈现一条有平滑弧度的上升曲线(一阶惯性环节)。
核心观测点 3:控制器动作与外部负载 ------ 这是因果关系
我们要看 PID 是如何与外部负载"搏斗"的。这里建议把两个信号放进同一个 Scope 里对比。
- 操作方法: 1. 拖出一个新的
Scope。
- 双击打开它,点击顶部的齿轮图标(设置),找到
Number of input ports(输入端口数),改为2。 - 或者去图库里搜一个
Mux模块,把两个信号绑成一根线接给 Scope。
-
位置: * 端口 1 接到 PID 输给进气系统的
throttle_cmd线路上。 -
端口 2 接到你的
外部负载常数块的线路上。 -
命名为:
Control_vs_Load -
你应该看到的波形: 稳定在 800 转时,节气门开度可能在一个很小的值(比如 5%)。如果你在仿真中途(比如第 5 秒)让
外部负载突然从 0 跳变到 20 Nm,你会看到转速瞬间掉下来一点,紧接着这个 Scope 里的throttle_cmd会迅速爬升,把节气门顶开,从而把转速重新拉回 800。
💡 Simulink 进阶小贴士:把数据传给你的论文脚本
我们之前聊过要在 MATLAB 里画高大上的论文 MAP 图。Scope 只是用来看的,要画图必须把数据送回 MATLAB 的工作区(Workspace)。
在确认波形没问题后,你可以把上面这几个位置的 Scope 替换成(或者并联上)To Workspace 模块:
- 搜
To Workspace拖进来。 - 双击它,把
Variable name分别改为sim_rpm,sim_pman,sim_throttle。 - 把
Save format(保存格式)改为Array(数组),这样最方便后续用代码处理。



