4. Stateflow模型仓库结构设计

Stateflow 模型一旦进入量产项目,就不再是单个工程师电脑里的一个 .slx 文件,而是一套需要被多个车型、多个团队、多个版本同时复用的资产。仓库结构设计的核心目标,是让“谁引用了谁、哪个车型用哪个版本、改动会影响哪些项目”这三个问题在目录层面就能被看清。本节围绕目录组织、命名规范、引用关系和变体管理四个维度展开,并给出一套可直接落地的仓库骨架。

一、目录组织:按“资产类型 + 复用层级”分层

量产仓库最常见的错误是按“项目名”平铺目录,例如 ProjectA/、ProjectB/ 各放一份模型,导致同一段控制逻辑被复制多份,修一个 bug 要改 N 个地方。更合理的做法是按资产类型分层,把“可复用单元”和“项目装配”分开:

stateflow-repo/
├── lib/                     # 可复用库,跨车型共享
│   ├── core/                # 基础状态机:上电、下电、故障降级
│   ├── bms/                 # 电池管理状态逻辑
│   └── thermal/             # 热管理状态逻辑
├── variants/                # 车型变体配置(只放差异,不放逻辑)
│   ├── variant_A.yaml
│   ├── variant_B.yaml
│   └── variant_C.yaml
├── projects/                # 项目装配层,引用 lib + variants
│   ├── project_A/
│   │   ├── top.slx          # 顶层装配模型
│   │   └── project_A.mk     # 构建/生成配置
│   └── project_B/
├── interfaces/              # 接口定义:数据字典、总线、枚举
│   ├── can_signals.sldd
│   └── enums.sldd
└── tools/                   # 校验脚本、CI 配置
    ├── check_naming.m
    └── check_refs.m

关键原则是:lib 只放逻辑,variants 只放差异,projects 只放装配。任何一段状态逻辑如果被两个以上车型使用,就必须下沉到 lib;任何车型差异如果只是参数或枚举取值不同,就不应该复制一份模型,而应通过变体配置注入。

二、命名规范:让文件名自解释

命名规范要解决“看到文件名就知道它是什么、属于谁、什么状态”。建议采用分段式命名,段间用下划线,段内用驼峰:

  • 库模型:lib_<域>_<功能>.slx,例如 lib_bms_socEstimation.slx;
  • 项目顶层:proj_<车型>_top.slx,例如 proj_variantA_top.slx;
  • 状态机内部:State 用 ST_ 前缀,如 ST_Init、ST_Fault;转移条件用 TR_ 前缀;
  • 数据对象:输入 u_、输出 y_、参数 p_、标定 cal_,例如 u_ignition、p_socLowThreshold。

命名规范必须可被脚本检查。例如用正则 ^lib_[a-z]+_[A-Za-z]+\.slx$ 校验库模型名,在 CI 中拦截不合规提交。规范不落到脚本,三个月后就会形同虚设。

三、模型引用关系:单向依赖,禁止环

Stateflow 模型之间通过 Model Reference、Library、Data Dictionary 建立引用。量产仓库必须保证引用关系是有向无环图(DAG):lib 可以被 projects 引用,projects 之间不能互相引用,lib 内部也尽量保持单向。下图展示了一个典型的多车型引用拓扑:

多车型 Stateflow 模型引用拓扑(单向 DAG) lib/ 可复用库(跨车型共享) lib_core_powerMode 上电/下电状态机 lib_bms_socEstimation SOC 估算状态逻辑 lib_thermal_fanCtrl 风扇控制状态机 interfaces/ can_signals.sldd · enums.sldd variants/ variant_A/B/C.yaml(仅差异) projects/ project_A / project_B 顶层装配 proj_variantA_top.slx 引用 lib + variant_A.yaml proj_variantB_top.slx 引用 lib + variant_B.yaml 引用规则 lib → projects:允许,库被项目引用 interfaces → lib:允许,接口被逻辑引用 variants → projects:允许,差异注入装配 ✕ projects 之间禁止互相引用,lib 内部禁止成环

引用关系必须可自动校验。一个实用的做法是在 tools/check_refs.m 中遍历所有 .slx,解析其 Model Reference 列表,构建邻接矩阵后检测环;一旦发现环或跨层引用(如 lib 引用 projects),CI 直接失败。这样可以在合并请求阶段就拦住结构性问题,而不是等到集成时才暴露。

四、多车型变体管理:差异外置,逻辑共享

多车型变体管理的本质是“把变化点集中到一处”。常见的变化点包括:阈值参数(如 SOC 低报警阈值)、枚举取值(如车型专属故障码)、状态机分支(某车型多一个“快充预热”状态)。前两类适合用变体配置文件注入,第三类才需要条件编译或变体模型。

以 SOC 低报警阈值 p_socLowThreshold 为例,variant_A 设为 20%,variant_B 设为 15%,variant_C 设为 25%。在 variants/variant_A.yaml 中只写差异:

variant: A
overrides:
  p_socLowThreshold: 20
  p_fanStartTemp: 45
  enums:
    faultCode_thermal: 0x21A

构建时由脚本读取对应 yaml,生成项目专属的标定数据文件,再与 lib 模型一起编译。这样 lib 模型本身不含任何车型硬编码,新增车型只需新增一个 yaml,而不是复制模型。对于确实需要新增状态分支的车型,建议在 lib 中预留可配置的“扩展状态”接口,通过变体开关决定是否激活,而不是在项目层直接改库模型。

判断一个差异该放 lib 还是 variants 的简单标准:如果差异只是“数值或枚举不同”,放 variants;如果差异是“状态或转移结构不同”,优先考虑在 lib 中做成可配置分支,仍无法覆盖时才允许项目层派生。

五、落地检查清单

仓库结构设计完成后,建议用以下清单做一次自检:目录是否按 lib/variants/projects/interfaces 分层;命名是否可被正则校验;引用关系是否为 DAG 且无跨层反向引用;车型差异是否全部外置到 variants;CI 是否包含命名检查和引用检查。这五项都通过,仓库才具备支撑多车型量产迭代的基础条件。