3、创建第一个状态图:从Simulink库中添加Stateflow图表、建立简单状态、运行仿真并观察行为
Stateflow是Simulink环境中用于建模有限状态机(FSM)和控制逻辑的图形化工具。它允许工程师以状态转移图(State Transition Diagram)的形式描述事件驱动的复杂行为,并与Simulink的连续时间、离散时间求解器无缝集成。本章将引导您完成从Simulink库中拖拽Stateflow图表、定义第一个状态、建立状态转移,到运行仿真并观察行为变化的完整闭环。我们将以一个简单的“开关灯”控制逻辑为例,演示状态机建模的核心流程,并深入剖析状态激活、转移条件、默认转移等关键概念。
上图展示了从Simulink模型到Stateflow图表,再到仿真与观察的完整链路。本章将围绕这一链路,详细讲解每个环节的操作方法、背后的状态机原理以及常见陷阱。
3.1 核心原理:Stateflow图表在Simulink中的角色与执行机制
Stateflow图表本质上是一个封装了有限状态机语义的S-Function(系统函数)。当您从Simulink库中拖拽一个Chart模块时,Simulink会将其视为一个具有输入端口、输出端口和内部状态的动态系统。在仿真过程中,Simulink求解器在每个时间步长调用Stateflow图表,图表根据当前激活的状态、输入信号的值以及定义好的转移条件,决定是否发生状态转移,并执行相应的动作(如进入状态时的entry动作、退出状态时的exit动作、转移过程中的during动作等)。
理解Stateflow的执行语义至关重要。它遵循“事件驱动”和“轮询”相结合的模式:在离散时间步长中,图表会评估所有从当前激活状态出发的转移边。如果某个转移条件为真,则执行转移;如果多个转移同时为真,则根据转移的优先级(通常由绘制顺序或显式优先级决定)选择一个执行。状态激活是互斥的(在同一个父状态内部),这意味着同一时刻只有一个子状态处于激活状态。
核心概念:Stateflow中的“状态”代表系统的一种稳定行为模式。例如,在“开关灯”例子中,OFF状态对应灯熄灭,ON状态对应灯点亮。状态转移由“条件”触发,条件可以是输入信号(如switch == 1)、时间条件(如after(5, sec))或事件(如上升沿触发)。动作则是在状态进入、退出或转移发生时执行的代码,用于更新输出或内部数据。
Stateflow图表与Simulink的交互通过端口实现。输入端口接收来自Simulink其他模块的信号(如传感器数据、控制指令),输出端口将状态机的计算结果(如控制量、状态编码)送回Simulink。这种双向数据流使得Stateflow非常适合作为混合系统(连续+离散)中的决策核心。
3.2 操作流程:从库中添加图表到建立第一个状态
下面我们以“开关灯”模型为例,逐步演示创建过程。该模型的目标是:当输入信号 switch 为1时,输出 light 为1(灯亮);当 switch 为0时,输出 light 为0(灯灭)。这是一个典型的二状态有限状态机。
步骤1:创建Simulink模型并添加Chart模块
- 在MATLAB命令窗口输入
simulink打开Simulink库浏览器,或直接点击“新建”模型。 - 在库浏览器左侧导航栏中找到 Stateflow 库,点击展开。
- 将 Chart 模块拖拽到模型画布中。该模块图标通常显示为带有“Chart”字样的矩形。
- 同时,从 Simulink/Sources 库中添加一个 Step 模块(作为输入信号源),从 Simulink/Sinks 库中添加一个 Scope 模块(用于观察输出)。
步骤2:进入Stateflow编辑器并创建状态
- 双击Chart模块,打开Stateflow编辑器。此时会看到一个空白的画布,左上角有一个默认的“入口”节点(一个带箭头的圆圈)。
- 在左侧工具栏中,选择“状态”工具(矩形图标),在画布上单击并拖动,创建一个状态框。将其命名为
OFF。 - 重复上述操作,创建第二个状态框,命名为
ON。将两个状态框并排放置。
步骤3:定义默认转移和状态转移
- 设置默认转移: 默认转移用于指定系统启动时进入哪个状态。将鼠标移动到入口节点(圆圈)的箭头上,按住鼠标左键,拖出一条带箭头的曲线,连接到
OFF状态的顶部。这条线即为默认转移路径。 - 绘制状态转移: 将鼠标移动到
OFF状态的右侧边缘,会出现一个十字箭头。按住鼠标左键,拖出一条曲线到ON状态的左侧边缘,松开鼠标。这样就创建了一条从OFF到ON的转移边。 - 同样地,从
ON状态的右侧边缘拖出一条曲线,连接到OFF状态的左侧边缘,创建从ON到OFF的转移边。
步骤4:编写转移条件和动作
- 双击从OFF到ON的转移边标签(通常显示为“?”),在文本编辑框中输入条件
[switch == 1]。方括号表示这是一个条件表达式。 - 双击从ON到OFF的转移边标签,输入条件
[switch == 0]。 - 双击
OFF状态,在状态属性对话框中,找到“动作”选项卡。在“entry”动作栏中输入light = 0;。这表示每次进入OFF状态时,将输出信号light置0。 - 双击
ON状态,在“entry”动作栏中输入light = 1;。
步骤5:连接Simulink信号并配置求解器
- 关闭Stateflow编辑器,返回Simulink模型画布。此时Chart模块上应显示两个输入端口(
switch)和一个输出端口(light)。 - 将Step模块的输出端口连接到Chart模块的
switch输入端口。 - 将Chart模块的
light输出端口连接到Scope模块的输入端口。 - 双击Step模块,设置其“Step time”为1,“Initial value”为0,“Final value”为1。这样,在t=1秒时,switch信号从0跳变到1。
- 在Simulink模型工具栏中,将求解器设置为“离散”(discrete),固定步长(如0.01s),仿真停止时间设置为10秒。
经验提醒: 在Stateflow中,条件动作(如 light = 1;)写在转移边上,而状态动作(如entry、during、exit)写在状态内部。对于简单的赋值,写在entry动作中即可保证状态激活时输出立即更新。如果需要在状态持续期间连续计算,则应使用during动作。
3.3 案例拆解:开关灯模型的仿真与行为观察
完成上述建模后,点击“运行”按钮进行仿真。仿真结束后,双击Scope模块查看输出波形。
预期行为:
- 在 t=0 到 t=1 秒期间,switch=0,系统处于OFF状态,light输出为0。
- 在 t=1 秒时,switch跳变为1,Stateflow检测到转移条件
[switch==1]为真,执行从OFF到ON的转移。进入ON状态时,执行entry动作,light变为1。 - 在 t=1 到 t=10 秒期间,switch保持为1,系统稳定在ON状态,light持续输出1。
然而,如果我们希望观察灯熄灭的过程,需要让switch信号在某个时刻变回0。我们可以修改Step模块的“Final value”为0,或者使用Signal Builder模块生成更复杂的输入序列。例如,设置Step模块在t=5秒时从1跳变回0,那么Scope上会看到light在t=5秒时从1跳变为0。
| 仿真时间 (s) | 输入 switch | 激活状态 | 输出 light | 转移事件 |
|---|---|---|---|---|
| 0 - 1 | 0 | OFF | 0 | 无(初始状态) |
| 1 - 5 | 1 | ON | 1 | t=1s 时 OFF→ON |
| 5 - 10 | 0 | OFF | 0 | t=5s 时 ON→OFF |
深入分析: 这个简单例子揭示了状态机的几个关键特性:确定性(给定输入和当前状态,输出和下一状态是唯一的)、记忆性(系统行为不仅取决于当前输入,还取决于历史状态)以及离散性(状态变化发生在离散时刻)。在实际工程中,这种逻辑可以用于电机启停控制、通信协议状态管理、用户界面导航等场景。
常见误区: 初学者常犯的错误是忘记设置默认转移。如果没有默认转移,Stateflow会报错,因为系统不知道初始状态是什么。另一个常见问题是转移条件写错,例如将 switch == 1 写成 switch = 1(赋值而非比较),这会导致条件永远为真或产生编译错误。此外,如果输入信号是连续变化的模拟量,直接与整数比较可能因浮点误差导致意外行为,建议使用容差比较或阈值判断。
3.4 常见误区与总结复盘
在创建第一个状态图的过程中,除了上述问题,还有几个高频误区需要特别留意。
- 误区一:状态内部没有动作,导致输出不更新。 如果只在转移边上写动作,那么输出只会在转移发生的瞬间更新。如果希望输出在状态激活期间保持某个值,必须在entry动作中赋值,或者使用during动作持续驱动。
- 误区二:混淆Simulink信号与Stateflow数据。 在Stateflow中,您可以使用
Input和Output对象来映射Simulink端口。如果忘记在Stateflow编辑器中添加这些数据对象,图表将无法识别端口名称。正确做法是:在Stateflow编辑器左侧的“符号”窗格中,点击“添加输入”和“添加输出”,并命名与Simulink端口一致的变量名。 - 误区三:忽略仿真步长的影响。 对于纯离散状态机,使用固定步长求解器是合适的。如果使用变步长连续求解器,Stateflow的转移检测可能发生在非整数时间点,导致波形出现毛刺。建议在控制逻辑模型中统一使用离散求解器。
- 误区四:认为状态图只能处理布尔逻辑。 Stateflow完全支持整数、浮点数、枚举类型,甚至可以在状态动作中调用MATLAB函数。这使得它能够处理复杂的计算任务,而不仅仅是简单的开关逻辑。
总结复盘: 创建第一个状态图的核心流程可以归纳为“五步法”:拖Chart、建状态、画转移、写动作、连信号。每一步都有其对应的原理支撑。拖Chart是建立Simulink与Stateflow的接口;建状态是定义系统的稳定行为模式;画转移是描述状态之间的切换路径;写动作是赋予状态和转移实际的计算意义;连信号则是将状态机嵌入到更大的仿真环境中。掌握这五步,您就具备了构建更复杂状态机(如层次化状态、并行状态、历史节点)的基础。
实战建议: 在开始一个Stateflow模型之前,先在纸上画出状态转移图,明确每个状态的含义、每个转移的触发条件以及每个状态需要执行的动作。这能显著减少在软件中调试的时间。同时,利用Stateflow的“调试”模式(在仿真时点击“调试”按钮),可以逐步查看状态的激活顺序和转移的评估过程,这是理解复杂逻辑的利器。