2. Simulink模型工程化基础
在把Simulink模型接入CI/CD之前,必须先解决一个更基础的问题:模型本身是不是一份“可被机器稳定构建和验证的资产”。如果模型依赖某个工程师桌面上的变量、某个未纳入版本管理的MAT文件、某个只在本地生效的配置参数,那么流水线即使跑起来,结果也不可复现。本节围绕模型文件组织、数据字典、配置集、回调函数以及项目与工程引用五个方面,说明如何把模型整理成CI/CD可管理的工程资产。
一、模型文件组织:让目录结构表达依赖关系
工程化的第一步是让文件系统结构反映模型之间的真实依赖。一个可被流水线稳定构建的Simulink工程,通常按“入口—组件—数据—配置—脚本—产物”分层组织,而不是把所有slx文件平铺在一个目录里。例如:
VehicleCtrl_Project/
├─ models/
│ ├─ top/VehicleCtrl_Top.slx % 顶层集成模型
│ ├─ subsys/MotorCtrl.slx % 子系统模型(模型引用)
│ └─ subsys/BrakeCtrl.slx
├─ data/
│ ├─ VehicleCtrl.sldd % 数据字典
│ └─ calibration/veh_params.mat % 标定数据(纳入版本管理)
├─ config/
│ ├─ cfg_mil.mat % MIL配置集
│ └─ cfg_sil.mat % SIL配置集
├─ scripts/
│ ├─ setup_project.m % 工程初始化脚本
│ └─ run_regression.m % 回归入口
└─ artifacts/ % 流水线产物(不纳入版本管理)
这里的关键约定是:models/下只放模型,data/下只放数据,config/下只放配置集,artifacts/由流水线生成且加入.gitignore。目录结构一旦固定,流水线脚本就可以用相对路径定位资产,而不依赖任何绝对路径。模型引用(Model Reference)应优先于库链接(Library)用于需要独立编译和独立测试的组件,因为模型引用支持增量构建和独立仿真,这对回归测试的并行化至关重要。
二、数据字典:把变量从“工作区”搬进“受管资产”
Simulink模型中的参数、信号和总线对象如果定义在基础工作区(Base Workspace),就只存在于当前MATLAB会话中,CI代理上不会自动拥有这些变量。数据字典(.sldd)的作用是把这些定义持久化为可版本管理的文件。典型做法是:在数据字典中建立Design Data和Calibration两个分区,前者存放Simulink.Parameter和Simulink.Signal对象,后者存放标定用的数值。
以电机控制为例,数据字典中可定义:
% 在数据字典中定义参数对象
MotorCtrl.Kp = Simulink.Parameter(1.25);
MotorCtrl.Kp.DataType = 'single';
MotorCtrl.Kp.Min = 0; MotorCtrl.Kp.Max = 10;
MotorCtrl.Kp.DocUnits = 'N*m/A';
MotorCtrl.SpeedRef = Simulink.Signal;
MotorCtrl.SpeedRef.DataType = 'single';
MotorCtrl.SpeedRef.Dimensions = 1;
模型通过Simulink.data.dictionary接口或直接在模型属性中绑定该字典。这样,CI代理检出代码后,只要加载数据字典,模型就能解析所有符号。需要特别注意的是,数据字典本身是二进制文件,Git无法做行级合并,因此团队应约定“同一时间只有一人修改字典”,或改用基于脚本的.m文件生成字典,以便在流水线中重建。
三、配置集:把仿真配置从模型里“抽出来”
配置集(Configuration Set)保存求解器、步长、代码生成目标、诊断级别等设置。如果这些设置直接写在模型里,MIL、SIL、代码生成三种场景就会互相干扰。正确做法是为每种场景建立独立的配置集,并在流水线中按需激活。例如:
| 配置集 | 求解器 | 步长 | 主要用途 |
|---|---|---|---|
| cfg_mil | ode45 | 变步长 | 模型在环功能验证 |
| cfg_sil | FixedStepDiscrete | 0.001 s | 软件在环、与C代码比对 |
| cfg_codegen | FixedStepDiscrete | 0.001 s | 嵌入式代码生成 |
在脚本中可通过setActiveConfigSet切换,或在SimulationInput对象中指定配置集,使每次回归运行都使用确定的配置,避免“上次手动改过求解器”这类不可复现问题。
四、回调函数:把初始化逻辑变成可执行契约
模型的PreLoadFcn、PostLoadFcn、InitFcn等回调函数,是模型加载和仿真时自动执行的钩子。工程化用法是把“加载数据字典、设置路径、检查依赖”等动作写进PostLoadFcn,而不是依赖工程师手动运行脚本。例如:
% PostLoadFcn 示例
if ~bdIsLoaded('VehicleCtrl_Top')
load_system('VehicleCtrl_Top');
end
% 绑定数据字典
Simulink.data.dictionary.open('VehicleCtrl.sldd');
% 添加工程路径
addpath(genpath(fullfile(pwd,'scripts')));
但回调函数也有风险:如果其中包含交互式命令(如input、uiwait)或依赖图形界面,CI代理会挂起。因此,回调中只应保留无交互、幂等的初始化逻辑,并把复杂逻辑封装到scripts/下的函数中,由回调调用。
五、项目与工程引用:把资产打包成可复现单元
MATLAB Project(.prj)把上述模型、数据字典、配置集、脚本和路径设置打包成一个可引用的工程单元。工程引用(Project Reference)允许一个工程引用另一个工程,从而支持多团队并行开发。在CI中,推荐的做法是:顶层工程引用组件工程,流水线检出顶层工程后,通过openProject自动解析所有引用并设置路径。
图中展示了从顶层工程到组件工程、数据字典、配置集和回调函数的加载关系。CI流水线的典型入口是openProject('VehicleCtrl_Project.prj'),它会自动解析工程引用、设置路径、加载数据字典并触发回调。这样,流水线脚本只需要一条命令就能把整个工程恢复到可构建状态,而不需要逐项手动配置。
六、为CI/CD准备可管理资产的检查要点
在把上述资产接入流水线之前,建议逐项确认:模型是否全部使用相对路径引用;数据字典是否纳入版本管理且不依赖基础工作区;配置集是否按场景分离且可脚本激活;回调函数是否无交互、无图形界面依赖;工程引用是否形成有向无环图,避免循环引用。这些检查可以直接写成scripts/check_assets.m,在流水线的“静态检查”阶段执行,失败即阻断后续构建。
完成本节整理后,模型不再是一堆散落的slx文件,而是一份结构清晰、依赖明确、可被脚本完整重建的工程资产。这是后续搭建持续集成流水线、实现自动化回归测试的前提。