2. Stateflow编辑器与对象层级

Stateflow 的核心并不是“画流程图”,而是用一套可执行的层次化对象模型描述事件驱动的状态逻辑。理解这套对象层级,是后续做状态机、任务调度、模式管理和自动生成代码的前提。Stateflow 编辑器中的每一个图形元素,最终都会映射为模型中的对象,并参与仿真与代码生成。本节围绕六类核心对象展开:Chart、State、Transition、Junction、Graphical Function、Simulink Function,重点说明它们各自的职责、创建方式以及组织关系。

一、Chart:状态逻辑的容器与边界

Chart 是 Stateflow 逻辑的顶层容器,也是与 Simulink 模型交互的边界。在 Simulink 中新建 Chart 后,双击进入 Stateflow 编辑器,所有状态、转移、节点和函数都组织在 Chart 内部。Chart 本身定义了输入、输出、局部数据、参数、事件以及仿真目标,这些内容决定了内部逻辑如何与外部 Simulink 信号连接。

创建 Chart 的常见方式有两种:在 Simulink 画布中使用 Stateflow 库拖入 Chart 模块,或在已有子系统上右键选择添加 Stateflow Chart。Chart 的接口配置在“Symbols”面板中完成。例如一个电机模式管理 Chart,可以定义输入 cmd(uint8,取值 0=停止、1=运行、2=故障复位)、输入 fault(boolean)、输出 mode(uint8,0=Idle、1=Run、2=Fault)。这些符号一旦定义,内部状态和转移就可以直接引用,Chart 的边界由此清晰。

Chart 还决定了执行语义。Chart 的更新方法(如 Inherited、Discrete)和采样时间会影响状态转移的触发时机。若 Chart 设置为离散采样 0.01 s,则内部无事件触发的转移会在每个采样点评估一次;若使用输入事件触发,则只在事件发生时评估。这一区别直接影响状态机的响应行为,是组织逻辑时必须先确定的前提。

二、State:状态语义的载体

State 表示系统所处的模式或阶段,是 Stateflow 中最基本的语义单元。创建 State 的方式是:在 Stateflow 编辑器工具栏选择 State 工具,在画布上单击放置,或使用快捷方式直接输入名称。State 的名称应表达业务含义,例如 Idle、Run、Fault,而不是 state1、state2。

State 内部可以包含三类内容:entry 动作、during 动作、exit 动作,以及内部嵌套的子状态和转移。entry 在进入状态时执行一次,during 在状态保持期间每个评估周期执行,exit 在离开状态时执行一次。例如 Run 状态可以写:

entry: mode = 1;
during: speedRef = 1500;
exit: speedRef = 0;

这段逻辑表示进入 Run 时输出模式置 1,保持期间给定转速参考 1500 r/min,退出时清零转速参考。State 还可以设置默认转移,用于指定父状态首次激活时进入哪个子状态。State 的层次结构是 Stateflow 组织复杂逻辑的关键:父状态负责公共行为,子状态负责细分模式,从而避免把所有逻辑平铺在一层。

三、Transition:状态之间的迁移规则

Transition 是连接状态的有向边,表示在满足条件时从一个状态迁移到另一个状态。创建方式是选择 Transition 工具,从源状态边界拖到目标状态边界。每条转移都可以附带条件表达式和动作表达式,格式为 [条件]{动作}。例如从 Idle 到 Run 的转移可以写:

[cmd == 1]{mode = 1;}

这表示当输入命令为 1 时,迁移到 Run 并执行动作。转移的评估遵循 Stateflow 的语义:同一时刻可能有多个转移条件成立,此时按优先级和层次顺序选择。默认转移用于没有明确源状态的入口,常见于父状态内部选择初始子状态。转移条件应尽量使用明确的布尔表达式,避免依赖隐式顺序;当条件复杂时,可以拆分为多个转移或引入 Junction 作为中间判断点。

四、Junction:条件分支与路径汇聚

Junction 是一个无状态的连接节点,用于表达条件分支、路径合并和中间判断。它本身不表示状态,也不保持历史,只影响转移的走向。创建方式是选择 Junction 工具,在画布上放置小圆点,然后用转移连接。Junction 的典型用法是把一个转移拆成多个条件分支:从某个状态出发,先到达 Junction,再从 Junction 引出多条带条件的转移,分别指向不同目标状态。

例如故障处理逻辑中,从 Run 出发到达 Junction,再根据 fault 和 cmd 的组合决定进入 Fault、Idle 还是保持 Run。Junction 还可以用于汇聚多条路径,使多个状态在满足条件时进入同一个后续状态。需要注意的是,Junction 上的转移条件应按互斥且完备的原则设计,避免出现无出口或条件重叠导致的语义歧义。

五、Graphical Function:可复用的图形化逻辑

Graphical Function 是在 Chart 内部定义的、用图形方式实现的函数。它拥有自己的输入输出参数和内部逻辑,可以被 Chart 中的状态、转移或其他函数调用。创建方式是在 Stateflow 编辑器的“Functions”视图中新建 Graphical Function,或使用工具栏中的函数工具。定义时需指定函数名、输入参数和输出参数,例如:

function y = limitSpeed(v)
  if v > 1800
    y = 1800;
  else
    y = v;
  end
end

Graphical Function 的价值在于把重复出现的判断或计算封装起来,使状态和转移的条件表达式保持简洁。它适合表达限幅、查表、模式仲裁、故障确认等可复用逻辑。与 State 不同,Graphical Function 不参与状态层次,不保持状态历史,调用时执行并返回结果。

六、Simulink Function:与 Simulink 模型的双向接口

Simulink Function 用于在 Stateflow 与 Simulink 之间建立函数级调用接口。它可以在 Chart 中定义,也可以在 Simulink 模型中定义,并通过函数调用端口连接。创建方式是在 Stateflow 编辑器中选择 Simulink Function,定义函数原型,例如 y = readSensor(),然后在 Simulink 侧提供对应的 Function-Call Subsystem 或导出函数实现。

Simulink Function 与 Graphical Function 的区别在于作用域:Graphical Function 只在 Chart 内部可见,Simulink Function 则跨越 Chart 边界,允许 Simulink 模型调用 Chart 中的函数,或让 Chart 调用 Simulink 模型中的函数。这使得 Stateflow 可以复用 Simulink 中已有的控制算法、查表模块或设备驱动接口,而不必在 Chart 内重复实现。

七、对象组织方式与创建顺序建议

在实际建模中,推荐的组织顺序是:先定义 Chart 的输入输出和局部数据,再划分顶层状态,然后为每个状态补充 entry/during/exit 动作,接着用 Transition 和 Junction 描述迁移条件,最后把重复逻辑抽取为 Graphical Function,把跨模型调用封装为 Simulink Function。这样做的原因是:接口决定边界,状态决定结构,转移决定行为,函数决定复用。

下面这张图展示了六类对象在 Chart 内部的层级与调用关系。图中同时标出了“定义位置”和“可见范围”,便于区分哪些对象属于 Chart 内部、哪些对象跨越 Chart 边界。

Stateflow Chart 对象层级与调用关系 Chart(顶层容器 / 与 Simulink 的边界) 输入 / 输出 / 局部数据 cmd, fault, mode, speedRef State(状态语义载体) Idle entry: mode=0 Run entry: mode=1 Fault entry: mode=2 [cmd==1] [fault] [cmd==0] Junction 条件分支 / 路径汇聚 Graphical Function(Chart 内部复用) function y = limitSpeed(v) if v > 1800 → y = 1800 else → y = v Simulink Function(跨边界调用) y = readSensor() Chart ↔ Simulink 双向接口 复用 Simulink 控制算法 / 驱动 调用 调用 Simulink 模型 Function-Call Subsystem 跨边界 State Junction Graphical Function Simulink Function Transition

从图中可以看出,Chart 是唯一与 Simulink 直接交互的顶层对象;State 和 Transition 构成状态逻辑的主体;Junction 只负责路径判断,不保持状态;Graphical Function 在 Chart 内部复用;Simulink Function 则跨越 Chart 边界,连接外部 Simulink 模型。理解这六类对象的职责边界,可以避免把状态逻辑写成大段条件判断,也能让后续的测试、调试和代码生成更加可控。

创建对象时建议遵循“先接口、后结构、再行为、最后复用”的顺序:先定义 Chart 的输入输出和局部数据,再划分 State 层次,然后补充 Transition 和 Junction,最后把重复逻辑抽取为 Graphical Function 或 Simulink Function。这样在模型规模扩大时,Chart 仍然保持清晰的对象层级。