2. Stateflow建模核心要素

Stateflow 的验证难点,往往不在仿真工具本身,而在于模型是否“可测”。一个可测的 Stateflow 模型,应当让每个状态、每条转移、每个条件与动作都能被外部激励单独触发,并能通过输出或日志观察到明确结果。要做到这一点,必须先理解 Stateflow 的八个核心建模要素:状态、转移、条件、动作、层次结构、并行状态、历史节点与真值表。它们共同决定了模型的状态空间、执行顺序与可观测性。

状态与转移:可测性的最小单元

状态(State)是 Stateflow 的基本存储单元,表示系统在某一时刻所处的模式。每个状态可以携带 entry、during、exit 三类动作,分别在该状态被激活、保持激活、被退出时执行。转移(Transition)是状态之间的有向连接,只有源状态处于激活状态且转移条件成立时,转移才会被触发。转移上可以标注条件(Condition)和条件动作(Condition Action),条件动作用于在转移判定成立后、目标状态进入前执行一次性计算。

从验证角度看,状态的可测性体现在:能否通过输入使模型进入该状态,能否在该状态停留足够时间以观察 during 动作,能否通过转移条件离开该状态。若某个状态没有任何入向转移可达,或没有任何出向转移,它就是一个“孤岛状态”,在 MIL/SIL/PIL 中都无法被有效覆盖。因此建模时应保证每个状态至少有一条入向和一条出向转移,除非该状态是初始状态或终止状态。

条件与动作:把判定逻辑显式化

条件通常写成布尔表达式,例如 speed > 30 && brake == 0。动作则包括数据赋值、函数调用、事件广播等。Stateflow 中常见的动作位置有:状态 entry/during/exit、转移条件动作、转移目标动作。验证时最忌讳的是把复杂逻辑塞进一个巨大的条件表达式,因为这样既难以构造测试用例,也难以定位失败原因。推荐做法是把复合条件拆成多个中间变量,在转移条件中只引用这些变量,使每个判定点都能被单独观测。

例如,一个车速控制状态机中,可以把“车速大于 30 且制动未按下”拆成 speedHigh 和 brakeOff 两个布尔量,转移条件写成 speedHigh && brakeOff。这样在 SIL 测试中,只要分别激励两个输入,就能判断是哪个子条件导致转移未触发。

层次结构与并行状态:控制状态爆炸

层次结构(Hierarchy)允许在一个父状态内部嵌套子状态机。父状态激活时,其内部子状态机才开始运行;父状态退出时,内部状态的历史信息可选择保留或清除。层次结构能显著减少转移数量,但也带来“默认转移”和“内部转移”的语义差异:默认转移决定进入父状态后首先激活哪个子状态,内部转移则不退出父状态,只切换子状态。

并行状态(Parallel State)用虚线分隔的多个区域表示,同一父状态下多个区域可同时激活。并行状态适合表达“同时成立”的多个子系统,例如“发动机控制”与“变速箱控制”同时运行。验证并行状态时,必须确认各区域之间是否存在共享数据竞争;若两个区域同时写同一变量,MIL 与 SIL 的结果可能因执行顺序不同而出现差异。

Stateflow 核心要素与可测性关系图 父状态:VehicleMode entry: init(); during: update(); exit: log() 子状态:Idle entry: rpm = 0; during: checkKey(); exit: — 子状态:Run entry: startFuel(); during: regulate(); exit: stopFuel(); keyOn [rpm>0] keyOff / reset() H 历史节点:恢复上次子状态 默认转移 并行状态:EngineCtrl || GearCtrl 区域A:喷油控制 fuel = f(rpm, load) 区域B:换挡控制 gear = g(speed, throttle) 真值表:换挡决策 speedHigh throttleHigh gear 0 0 1 0 1 2 1 0 2 1 1 3 每个条件组合对应唯一输出,便于覆盖 可测性检查点 ✓ 每个状态有入/出转移 ✓ 条件可拆分为中间变量 ✓ 历史节点明确恢复语义 ✓ 并行区域无共享写冲突 ✓ 真值表覆盖全部条件组合 ✓ 动作可被日志观测

历史节点:让“回到上次位置”可验证

历史节点(History Junction)用于记录父状态退出时内部子状态的激活情况。当父状态再次进入时,若使用历史节点,则恢复到上次激活的子状态;若不使用,则从默认转移重新开始。历史节点分为浅历史与深历史:浅历史只恢复直接子状态,深历史递归恢复所有层次。验证历史节点时,必须构造“进入—退出—再进入”的序列,并检查恢复后的子状态是否与预期一致。若模型中没有历史节点,却期望恢复上次状态,就会在 SIL 与 PIL 中产生行为差异。

真值表:把组合逻辑变成可覆盖的判定表

真值表(Truth Table)是 Stateflow 中表达组合逻辑的另一种形式,适合描述“多个条件组合对应一个输出”的决策。真值表的每一行是一个条件组合,每一列是一个条件或输出。与转移条件相比,真值表的优势在于:条件组合被显式枚举,便于做等价类划分和边界值分析。例如,换挡决策可以用 speedHigh 与 throttleHigh 两个条件,枚举四种组合,分别输出 gear=1、2、2、3。验证时只需覆盖这四行,即可认为该真值表逻辑被完整覆盖。

可测模型的设计原则

综合以上要素,建立可测 Stateflow 模型应遵循以下原则。第一,状态命名与语义一致,避免一个状态承担多种模式。第二,转移条件尽量原子化,复杂条件拆成中间变量,便于在 SIL 中单独激励。第三,层次结构不宜过深,一般不超过三层,否则默认转移与历史节点的组合会迅速增加测试用例数量。第四,并行状态之间避免共享写变量,若必须共享,应明确执行顺序并在 MIL 与 SIL 中对比结果。第五,真值表应覆盖全部条件组合,若组合过多,可用等价类合并。第六,所有 entry/during/exit 动作都应产生可观测的输出或日志,否则无法判断状态是否被正确激活。

在 MIL 阶段,建议先用 Simulink 信号源构造覆盖每个状态和每条转移的激励序列;进入 SIL 后,用相同的激励序列对比输出差异;进入 PIL 后,再对比目标板执行结果。若三者一致,说明模型在状态、转移、条件、动作、层次、并行、历史与真值表八个维度上均具备可测性。

需要特别注意的是,Stateflow 的执行顺序遵循“从外到内、从上到下、从左到右”的默认规则,并行区域之间也存在确定的执行次序。若模型依赖执行顺序,必须在注释中明确说明,并在 SIL 与 PIL 中验证顺序是否一致。对于历史节点,还要确认其恢复的是浅历史还是深历史,避免因语义理解偏差导致测试用例设计错误。

最后,可测模型不是一次建模就能完成的,而是在 MIL/SIL/PIL 迭代中逐步收敛的。每发现一个无法触发的状态、无法覆盖的条件或无法观测的动作,就回到模型中进行拆分、补充或重构。只有把八个核心要素都变成可激励、可观察、可判定的对象,Stateflow 模型才真正具备联合验证的基础。