3. 状态、转移与层次结构建模
Stateflow 的建模能力,本质上来自四个基本语义要素的组合:状态表示系统在某一时刻所处的模式;转移表示模式之间允许发生的切换;转移标签规定切换在什么事件、什么条件下、执行什么动作;层次结构则把大量状态组织成可复用、可维护的父子关系。理解这四者的语义,是后续处理复杂模式切换、故障降级、多工况调度的前提。
状态语义:激活、互斥与并行
一个状态被“激活”,意味着它当前正在参与执行。Stateflow 中状态分为两类:互斥(OR)状态与并行(AND)状态。互斥状态同一时刻只能有一个子状态处于激活;并行状态的所有子状态同时激活。例如一个电机控制器,顶层用互斥状态表达“停机 / 运行 / 故障”,而“运行”内部又用并行状态同时表达“转速控制”和“温度监控”,两者互不排斥、同时工作。
状态还可以携带 entry、during、exit 三类动作。entry 在进入状态瞬间执行一次,适合做初始化,如 speedRef = 0;;during 在状态保持激活的每个采样步执行,适合做持续控制;exit 在离开状态时执行一次,适合做清理,如 integral = 0;。把初始化放在 entry、把复位放在 exit,可以避免状态切换时残留旧值,这是工程上最常见的错误来源之一。
默认转移:确定初始激活路径
当父状态被首次激活时,它必须知道从哪个子状态开始。默认转移就是这条“入口路径”,用一条从默认转移点出发、不带事件和条件的短箭头表示。若父状态有多个子状态而没有默认转移,Stateflow 会报错或行为不确定。对于带历史节点的父状态,默认转移只在“从未进入过”时生效;一旦进入过,历史节点会记住上次激活的子状态。
转移标签:事件、条件与动作
转移标签的完整语法为 event[condition]{action},三段均可省略,但顺序固定。事件是触发源,如 tick、faultDetected;条件是布尔表达式,如 [temp > 85];动作是转移发生时执行的语句,如 {mode = 2;}。只有条件没有事件时,表示该转移在每个采样步都评估条件,属于“条件转移”;只有事件没有条件时,表示事件一到就转移。
转移的评估遵循“从源状态向外、按优先级”的规则:同一层次内,靠左、靠上的转移优先。若多个转移同时满足,只有优先级最高的那条会执行。因此,在画故障转移时,通常把“故障”转移放在最靠前的位置,保证它优先于正常控制转移被评估。
% 转移标签示例
tick[temp > 85]{mode = FAULT;} % 事件+条件+动作
[cmd == STOP]{mode = IDLE;} % 纯条件转移
faultDetected{mode = FAULT;} % 纯事件转移
父子状态与历史节点
层次结构的价值在于“封装”。父状态对外只暴露少量转移,内部细节被子状态隐藏。当父状态被重新进入时,默认行为是从默认转移指定的子状态重新开始;如果希望“回到上次离开的地方”,就需要在父状态内放置历史节点。历史节点分为浅历史(H)和深历史(H*):浅历史只记住父状态直接子层的激活状态,深历史则递归记住所有嵌套层的激活状态。
以“运行”父状态为例,其内部有“加速 / 稳态 / 减速”三个子状态。若使用浅历史,从“运行”退出再进入时,会回到上次激活的子状态;若内部还有嵌套的并行监控状态,则需要深历史才能完整恢复。历史节点用带 H 或 H* 的圆圈表示,并用默认转移指向“从未进入过”时的初始子状态。
复杂模式切换的层次化表达
面对多模式系统,推荐采用“顶层互斥 + 内部并行 + 历史恢复”的三层组织方式。顶层用互斥状态表达大模式,如“初始化 / 待机 / 运行 / 故障 / 停机”;“运行”内部用并行状态同时处理控制与监控;“运行”与“待机”之间用历史节点保存上次工况,实现快速恢复。这样,模式切换逻辑集中在顶层少量转移上,内部细节各自独立,修改一个模式不会波及其它模式。
上图展示了一个典型的层次化模式切换结构:顶层“运行”是互斥父状态,内部“加速 / 稳态 / 减速”互斥切换,并通过浅历史节点保存上次工况;“运行”内部还嵌套了并行的温度与电流监控,一旦越限立即触发故障转移。故障转移使用橙色高亮,表示它在优先级上高于正常控制转移。待机与运行之间通过 [cmd=run] 条件转移切换,停机则通过 exit 动作保存状态。
在工程实现时,建议遵循以下检查顺序:先确认每个父状态都有默认转移或历史节点;再确认互斥子状态之间没有遗漏的转移路径;然后检查转移标签的事件与条件是否与外部输入一致;最后验证历史节点在“退出—重进”后是否恢复到预期子状态。可以用一个简单的测试序列验证:进入运行→切到减速→退出到待机→重新进入运行,观察是否回到“减速”而非“加速”。若回到“加速”,说明历史节点未生效或默认转移被误用。