如果你手头有一辆已经标定好的 CarSim 车辆模型,又想在 Simulink 里自己写巡航控制逻辑,边写边看车辆怎么响应,那你大概率缺的是一台“虚拟试验车”——把这两套环境搬到同一个仿真回路里。我最近正好用 Simulink 与 CarSim 联合仿真做了一轮巡航控制开发验证,从最初接口对不上、信号满天飞,到最终能在定速、跟车、前车插入等工况下稳定跑完,中间踩了不少坑。这篇就把整套思路、接口搭建、控制参数整定和排错经验整理出来,适合刚接触联合仿真、或者想在自己车型模型上验证巡航算法的朋友参考。
1. 为什么要把 Simulink 和 CarSim 放进同一个仿真环境
1.1 单车模型做巡航控制,缺的从来不是算法
巡航控制在算法层面并不复杂:定速巡航就是踩住油门让车速贴近目标值,自适应巡航再多一个“前车距离保持”的逻辑。但真正麻烦的是车辆动力学反馈。车重、轮胎、制动器响应、发动机扭矩曲线、风阻和坡道阻力,这些都会直接影响控制器的实际表现。如果只用一个简单的单自由度纵向动力学模型,控制器做出来往往是“自嗨”,一到实车或者高精度模型上就容易震荡甚至失控。
CarSim 的价值在于它把车辆动力学、轮胎、悬架、转向、制动这些底层环节都给你封装好了,你只需要选择车型,给定油门开度、制动压力、挡位这些输入,它就能算出一整套真实感很强的车辆响应,包括车速、纵向加速度、发动机转速、行驶里程等。而这正好是巡航控制算法验证需要的“试验台”。
Simulink 侧则负责控制策略。你可以用 S-Function、Stateflow 状态机、PID 模块、甚至自己写 C 代码来搭建控制逻辑。CarSim 负责“被控对象”,Simulink 负责“控制器”,两者各干各擅长的部分,联合起来就是一个可重复的、低成本的控制算法验证环境。
1.2 联合仿真的两种主流姿势
我在项目里尝试过两种联合仿真方式:CarSim 生成 S-Function 嵌入 Simulink,以及通过 FMU 进行模型交换。简单说一下区别和我的取舍。
- S-Function 方式:在 CarSim 界面中勾选 Simulink 接口,CarSim 会自动生成一个 S-Function 模块,放到 Simulink 模型里。这种方式最直接,输入输出端口清晰,CarSim 侧的通道配置在界面上点选即可,适合快速搭建和反复调整参数。我在大多数工况验证时都用这种方式。
- FMU 方式:将 CarSim 模型导出为 FMU,再通过 Simulink 的 FMU 模块导入。优点是模型封装性好,适合跨团队分发,CarSim 许可证不一定要每个人都装。缺点是调试不如 S-Function 直观,生成配置步骤更多,信号名核对起来也更繁琐。
如果你只是自己做控制策略验证,我建议先用 S-Function,跑通了再考虑 FMU。别一上来就追求“工业级封装”,联合仿真最怕的是把时间浪费在接口上而不是控制逻辑上。
1.3 联合仿真到底解决了什么问题
很多人问我:CarSim 自己也能做巡航控制仿真,为什么非要用 Simulink?因为 CarSim 内部的驾驶员模型和控制策略大多是封装好的,你只能调参数,很难自由实现复杂的控制策略。比如你想做一个带前车切入场景的自适应巡航,需要状态机判断何时从定速转为跟车,这种逻辑在 CarSim 内置环境里写起来非常别扭。
Simulink 的优势是控制逻辑搭建灵活,Simulink 里写 PID、写状态机、写滤波、做数据记录都非常方便。联合仿真等于把“高保真车辆模型”和“高度可编程控制器”拼在一起,既能验证控制算法在复杂动力学下的表现,又能快速迭代算法本身。这个组合特别适合做算法前期的模型在环验证,也就是在实车或者硬件在环测试之前,把控制策路的绝大多数问题提前暴露出来。
2. 环境准备与联合仿真接口搭建
2.1 版本匹配与基础配置
联合仿真第一个坑就是版本匹配。CarSim 的版本和 MATLAB 版本必须满足兼容关系,否则生成的 S-Function 可能编译不过。我用的是一套较新的 CarSim 版本搭配 MATLAB R2021b 之后的版本,整体还算顺利。如果你用的是老版本 CarSim,建议去官方文档里查一下支持的 MATLAB 版本范围,别凭感觉配。
此外,编译环境也要提前装好。Simulink 里的 S-Function 默认需要 C 编译器,Windows 下建议装 Visual Studio 对应的社区版,或者在 MATLAB 里运行mex -setup选择已安装的编译器。很多接口报错都是编译环境没配好导致的。
2.2 CarSim 侧输入输出通道映射
联合仿真的核心是搞清楚 CarSim 模型对外暴露了哪些输入输出通道。我常用的配置思路是:
- 输入通道:油门开度、制动压力、挡位信号、转向角。这些是控制器的执行输出。
- 输出通道:车速、纵向加速度、发动机转速、行驶里程、质心位置等。这些是控制器反馈信号和记录信号。
在 CarSim 主界面的“Simulink”页签里,你可以勾选“使用 Simulink 联合仿真”,并在 I/O Channels 列表中配置输入输出变量。这里一定要注意变量名的单位。CarSim 默认很多通道是国际单位制,车速单位是 km/h 还是 m/s,制动压力单位是 bar 还是 Pa,这些差异会导致你后续看到的曲线数值完全对不上。
我习惯把关键通道统一记录为国际单位制,然后在 Simulink 模块端口名上直接标注单位,比如Vx_mps、Ax_mps2、Throttle_01。端口名一旦清晰,后面调试少走很多弯路。
2.3 Simulink 侧模型组织
CarSim 生成 S-Function 后,Simulink 模型里会多出一个类似“CarSim S-Function”的模块。你可以把它当作一个普通被控对象模块来连接。
我的 Simulink 模型布局是这样的:
- 信号源与记录区:用于生成工况输入,比如目标车速曲线、前车距离曲线,以及把仿真结果输出到工作区。
- 控制器子系统:包含巡航控制算法,输入是当前车速、目标车速、前车距离等,输出是油门开度和制动压力。
- CarSim S-Function 模块:将控制器的油门、制动等信号送入车辆模型,并输出车辆状态反馈。
- 示波器和数据记录模块:把关键信号实时显示和保存。
整个模型不用追求“大而全”,关键是信号流向一目了然。第一版模型越简单越好,先把闭环跑通,再加复杂功能。
2.4 步长与仿真参数的关键取舍
联合仿真的步长直接影响仿真精度和速度。CarSim 模型本身是连续动力学模型,Simulink 中如果用了离散控制器,就需要设置合适的固定步长。我常用的步长是 0.001 秒,也就是 1 kHz 的控制频率。
为什么选 1 kHz?因为巡航控制中的油门和制动执行机构响应通常在几十到几百毫秒量级,1 kHz 采样已经足够描述这些动态;再往下压到 0.1 ms 仿真速度会明显变慢,而且对控制精度提升有限。如果只是想验证逻辑而非精确标定,0.01 秒(100 Hz)也能跑,但遇到紧急制动等快速工况时误差会明显增大。
仿真求解器建议选择ode45这类变步长求解器,但搭配离散控制器时要注意 Simulink 中控制器的采样步长和 S-Function 的步长设置。我个人习惯直接把求解器设为定步长、离散求解器,这样仿真行为和实际代码运行的时序更接近,也便于后续生成嵌入式代码。
3. 巡航控制模型的核心细节与参数整定
3.1 从定速巡航到自适应巡航的控制框架
巡航控制从简单到复杂,我把它拆成三个层次。
第一层是定速巡航:控制器根据目标车速和当前车速的误差,计算油门开度或制动压力,让车速稳定在设定值。这个层次的难点是油门和制动的协调,避免“刹车和油门同时踩”这种荒唐输出。
第二层是自适应巡航的间距策略:在定速基础上引入前车距离和前车速度,根据相对距离和相对速度调整本车速度,保持安全车距。常用的间距策略是恒定车头时距(Constant Time Gap),公式很简单:
d_ref = d0 + t_gap * v_ego其中d_ref是期望跟车距离,d0是最小静止间距,t_gap是车头时距,v_ego是本车车速。车头时距一般取 1.0~2.0 秒,取 1.5 秒左右比较舒适。这个公式的好处是车速越高跟车距离越大,符合驾驶直觉。
第三层是模式切换与仲裁:系统需要根据前车是否存在、前车距离是否低于安全阈值,决定当前是定速巡航模式、跟车巡航模式还是制动介入模式。这个逻辑我用 Stateflow 实现,状态清晰,后续调试也直观。
3.2 PI 控制器参数整定的实操方法
巡航控制最核心的控制器是车速环,我用的是带前馈的 PI 控制器。目标车速和当前车速做差,经过比例和积分环节,输出期望加速度;期望加速度再经过一个执行器映射,变成油门开度或制动压力。
PI 参数初值怎么给?可以从车辆响应时间估算。设车辆在 80 km/h 时,油门开度变化 10% 能带来约 0.5 m/s² 的加速度变化,那么从误差到加速度的比例增益大致可以取Kp_a = 5 / 10% ≈ 50(这里的量纲映射需要根据你自己的通道单位换算)。然后根据油门执行器的时间常数,给一个小的积分增益,避免超调和低频静差。
我在项目里采用的初值是这个量级的:
% 车速误差(单位:m/s)-> 期望加速度(单位:m/s^2) Kp_acc = 0.8; Ki_acc = 0.15; % 期望加速度 -> 油门开度(0~1)或制动压力(0~1,压力归一化) % 油门侧增益 0.02,制动侧增益 0.01 Throttle_gain = 0.02; Brake_gain = 0.01;这里特别提醒:PI 参数的整定一定要在联合仿真里跑真实工况,不要只在理想模型里调。因为 CarSim 模型里包含驱动半轴、轮胎滑移这些动态,理想模型里不震荡的参数,在这里可能明显 overshoot。我第一版参数在简化模型里调得很漂亮,放到 CarSim 里直接超调 10 km/h,后来把积分增益降了一倍才稳住。
3.3 前车距离信号的处理
做自适应巡航时,前车距离不是直接由 CarSim 输出的,而是需要在 Simulink 侧构建一个前车模型。我的做法是:预设前车速度曲线,通过积分得到前车位置,再用本车位置(由 CarSim 输出的里程积分得到)计算出相对距离。
这个“虚拟前车”虽然简单,但非常好用。你可以自由设定前车什么时候加速、什么时候减速、什么时候从旁边车道切入。比在 CarSim 里做复杂的交通场景要省事得多。
计算相对距离时要注意滤波。CarSim 输出的车速信号有噪声,如果用原始速度信号直接积分,位置误差会随时间漂移。我的做法是对车速信号做一阶低通滤波,时间常数取 0.1 秒,再用滤波后的信号计算里程。这个细节看起来不起眼,但能避免跟车距离曲线出现明显的高频抖动。
3.4 限幅与油门制动协调保护
控制器的输出必须有安全保护,这绝不是可有可无的事。一个合格的巡航控制算法,在仿真里就要带上这些保护逻辑:
- 油门开度限幅:0~1 之间,防止积分饱和导致油门长时间顶死。
- 制动压力限幅:0~最大值之间,并限制制动变化率,防止急刹顿挫。
- 油门制动互锁:当期望加速度为负时,油门逐步关闭,制动逐步接入;期望加速度为正时,制动完全松开。
- 积分器抗饱和:当输出到达上限时,停止积分累加,避免“冲出限幅再慢慢拉回来”的现象。
这些保护逻辑在 Simulink 里用饱和度模块和积分模块的外部重置端口就能实现。我建议把限幅参数做成模型里的 Constant 模块,方便后期做参数扫描,而不是写死在子系统的参数里。
4. 仿真工况设计与完整实操过程
4.1 工况怎么选才能暴露问题
巡航控制的验证不能只跑一个匀速工况,至少要覆盖这些场景:
- 定速巡航启动:从静止或低速加速到目标车速。
- 平路匀速巡航:验证稳态误差和油门波动。
- 前车减速:验证跟车距离保持和制动介入。
- 前车切出:验证从跟车模式回到定速模式的过程。
- 前车静止目标:验证低速避撞逻辑和起步控制。
我常用的一个基础工况是这样的:前 10 秒本车以 30 km/h 稳定行驶,10 秒时驾驶员打开定速巡航并设定目标车速为 80 km/h,本车开始加速;30 秒时前车以 60 km/h 匀速出现,相对距离低于阈值后控制器切到跟车模式;50 秒时前车减速到 40 km/h,验证制动介入;70 秒时前车加速离开,控制器切回定速巡航。
这个工况覆盖了最关键的几次模式切换,能一次性暴露大多数逻辑 bug 和参数问题。等这个工况跑顺了,再加更复杂的“前车切入”和“坡道巡航”场景。
4.2 完整实操步骤:从 CarSim 配置到 Simulink 闭环
步骤一:在 CarSim 中选择车型。我用的是一套城市 SUV 动力学参数,开启 Simulink 联合仿真接口,并配置输入输出通道。
步骤二:在 Simulink 中创建新模型,拖入 CarSim 生成的 S-Function 模块。双击模块确认端口数量和信号名,特别注意输入端口数量要与 CarSim 侧配置的输入通道一致。
步骤三:创建控制器子系统。我先从最简单的定速巡航 PI 控制器开始,在子系统里放目标车速 Constant、PID Controller 模块和限幅模块。
步骤四:连接信号。S-Function 的车速输出接到控制器的反馈输入,控制器的油门输出和制动输出接到 S-Function 的对应输入端口。
步骤五:设置仿真参数。求解器用定步长,步长 0.001 秒,仿真时长 80 秒。
步骤六:运行仿真。第一次跑的时候把示波器挂在车速、油门、制动这几个关键信号上,眼睛盯紧这三个量,任何异常立刻暂停。
我第一次跑这个闭环时就发现车速反馈信号一直没有,查了半天发现是 CarSim 输出通道里我勾选的是发动机转速而不是车速。这种“信号名没有错但选错了量”的问题,在联合仿真里非常常见,所以端口核对环节一定不要省。
4.3 仿真结果怎么看
仿真跑完之后,我重点看三个图:
- 车速对比图:目标车速曲线和实际车速曲线叠在一起,看稳态误差和超调量。巡航控制稳态误差通常要求小于 1 km/h,超调量最好控制在 2 km/h 以内。
- 油门制动曲线:观察控制量是否平稳,有没有频繁抖动,有没有油门制动同时输出。
- 跟车距离曲线:看实际距离和期望距离的偏差,在跟车过程中距离误差是否收敛。
这三个图能覆盖巡航控制 80% 的问题。如果油门曲线像锯齿一样抖,说明增益过大或信号噪声没有滤干净;如果跟车距离持续偏高或偏低,说明间距策略的时间常数或者 PI 增益需要调节。
5. 常见问题与排查技巧实录
5.1 仿真慢到不能忍怎么办
联合仿真慢是普遍问题,但慢到什么程度算不正常?如果一个 10 秒工况要跑 5 分钟以上,那就要检查原因。我的经验是,先看步长是不是设得太小,再看有没有动态显示模块或者全局变量记录拖慢速度。
Simulink 里的 Scope 模块对仿真速度影响非常大,尤其是多个 Scope 同时打开显示曲线时。我后来把所有信号都记录到工作区变量,只在跑完后再用绘图命令查看,仿真速度提升非常明显。如果你需要在仿真过程中实时观察,只留一个精简的示波器就够了。
5.2 信号一直是零或者数值巨大
这个问题八成是通道单位和端口连接问题。CarSim 输出的车速默认可能是 km/h,你在控制器里按 m/s 算误差,算出来的增益完全偏掉,控制律自然不正常。
我这边遇到过的经典问题:CarSim 里制动压力通道的单位是 bar,而我在控制器里按 MPa 处理,中间差了 10 倍。仿真跑出来整车完全没有减速,因为控制器认为制动力一直很大,但实际 CarSim 收到的只是它期望值的十分之一。排查单位问题的最快方式,是在 Simulink 模型里加几个 Display 模块,直接看端口输出的数值量级,立刻就能发现异常。
5.3 仿真中途报错退出
联合仿真最常见的报错之一是 S-Function 模块无法编译,或者运行时提示输入输出数量不匹配。遇到这种情况,第一步不是改代码,而是回到 CarSim 界面,确认生成的 S-Function 版本和当前 MATLAB 版本匹配,确认输入通道数量与 Simulink 模块端口数量完全一致。
还有一个容易忽略的点:如果你在 Simulink 模型运行中途修改了 CarSim 的通道配置,必须重新生成一次 S-Function 模块,否则模型里缓存的是旧接口。这个问题我遇到过至少两次,每次都是“明明改了为什么不变”,最后发现是模块没有刷新。
5.4 控制量发散或剧烈震荡
控制量发散基本可以锁定为参数增益过大或者积分饱和没有处理。排查思路是先从简单工况开始:把目标车速设成恒定值,关闭自适应巡航逻辑,只保留定速 PI,然后把比例增益从很小值开始逐步增大。
我自己的经验是,每增大一倍增益就重跑一次仿真,直到出现震荡,再退回 0.6~0.7 倍留出稳定裕度。这个“临界增益法”虽然原始,但比盲目调参可靠得多。要注意的是,在 CarSim 这种高保真模型里,临界点的增益往往比简化模型低不少,不要拿简化模型的经验直接套。
5.5 避坑清单与个人建议
最后整理一份我在联合仿真过程中沉淀下来的避坑清单,希望能帮你少走点弯路:
| 问题现象 | 主要原因 | 处理建议 |
|---|---|---|
| 仿真速度极慢 | 步长过小或 Scope 过多 | 步长设为 1 ms,信号改录工作区变量 |
| 车速反馈为 0 | CarSim 通道选错 | 核对输出通道变量名和单位 |
| 制动效果微弱 | 压力单位换算错误 | 统一压力单位并检查量级 |
| 控制量锯齿状抖动 | 增益偏大或信号噪声 | 降低增益,增加低通滤波 |
| 模式切换卡顿 | 状态机缺少过渡条件 | 增加速度滞回和距离滞回 |
| 仿真中途无法编译 | 编译器未配置或版本不兼容 | 用mex -setup配置编译器,确认版本匹配 |
我个人在实际操作中的体会是:联合仿真第一版最重要的是把信号链路弄清爽,宁可算法简单一点,也要把接口基础打牢。很多人一上来就搭 ACC 状态机加最复杂的间距策略,结果接口信号全是错的,最后排查问题时根本分不清是算法 bug 还是通道问题。
另外一个小建议:第一次联合仿真的时候就把数据记录做全,CarSim 里多勾几个输出通道并不费事,但后续分析控制效果时会非常省时间。我通常把车速、加速度、发动机转速、行驶里程、油门、制动压力、目标车速、前车距离等十几个信号全部记录下来,跑一次就能做完整复盘。这套流程跑顺之后,后续换车型、加传感器模型、改控制器逻辑都会非常快,因为你已经拥有了一条稳定可靠的“虚拟试验回路”。