第十章Stateflow 状态机10.1 Stateflow 基础10.1.1 什么是 StateflowStateflow 是 Simulink 的扩展工具箱用于设计和仿真有限状态机FSM和流程图。Stateflow 解决的问题 纯 Simulink 擅长 连续/离散数学运算 信号处理 控制算法 Stateflow 擅长 逻辑判断和状态切换 事件驱动的行为 模式管理 安全监控逻辑 典型应用 汽车变速箱控制P/R/N/D档位切换 交通灯控制红/黄/绿状态循环 电机控制模式启动/运行/停止/故障 通信协议状态机握手/传输/断开 飞行控制模式起飞/巡航/降落/紧急10.1.2 有限状态机概念有限状态机FSM由以下要素组成 ① 状态集合 S {S1, S2, S3, ...} 系统在任意时刻处于且仅处于一个状态 ② 输入事件集合 E {e1, e2, e3, ...} 触发状态转移的事件 ③ 转移函数 δ: S × E → S 在状态S收到事件e后转移到新状态 ④ 初始状态 S0 系统启动时的初始状态 ⑤ 输出函数 在特定状态或转移时产生的输出 示例简单开关状态机 状态{OFF, ON} 事件{press_button} 转移 OFF press_button → ON ON press_button → OFF 初始状态OFF10.1.3 Stateflow 与 Simulink 的关系集成方式 Simulink 模型 └── ChartStateflow图表 ├── 状态States ├── 转移Transitions ├── 事件Events └── 数据Data Stateflow Chart 作为 Simulink 的一个模块存在 输入端口接收 Simulink 信号触发事件或数据 输出端口向 Simulink 输出数据 数据流向 Simulink 信号 ──→ Stateflow Chart ──→ Simulink 信号 连续/离散信号 逻辑状态机 控制信号/状态输出10.2 Stateflow 基本元素10.2.1 状态State状态表示系统的一种工作模式或条件。状态的图形表示 ┌─────────────────────────────┐ │ StateName │ ├─────────────────────────────┤ │ entry: 进入时执行的动作 │ │ during: 每个时间步执行的动作 │ │ exit: 离开时执行的动作 │ └─────────────────────────────┘ 状态类型 普通状态AND/OR OR 状态同一层级只有一个激活 AND 状态同一层级同时激活并行状态 超状态Superstate 包含子状态的状态 实现层次化状态机 历史节点History Junction 记住上次离开超状态时的子状态 重新进入超状态时恢复到历史子状态状态动作Actionsentry进入动作 进入该状态时执行一次 用于初始化、复位操作 例entry: speed 0; led ON; during持续动作 在该状态中每个时间步执行 用于持续计算或监控 例during: temperature read_sensor(); exit退出动作 离开该状态时执行一次 用于清理、保存操作 例exit: save_data(); alarm OFF; on event_name事件动作 收到特定事件时执行 例on BUTTON_PRESS: count count 1;10.2.2 转移Transition转移定义了状态之间的切换条件和动作。转移的图形表示 [源状态] ──────────────────────────→ [目标状态] 条件[guard]/动作{action} 转移语法 event[condition]{action} event触发转移的事件可省略 [condition]转移条件布尔表达式 {action}转移时执行的动作 示例 TIMEOUT[speed 0]{brake ON} → 收到 TIMEOUT 事件且速度大于0时 执行 brakeON然后转移到目标状态 默认转移Default Transition 没有源状态的转移 用于指定初始状态 图形实心圆点 ●──→ [初始状态]转移优先级当多个转移同时满足条件时 优先级由转移的编号决定数字越小优先级越高 可以在转移属性中设置优先级 最佳实践 避免多个转移同时满足条件 使用互斥条件确保唯一性10.2.3 事件Event事件是触发状态转移的信号。事件类型 ① 输入事件Input Event 来自 Simulink 的触发信号 在 Chart 输入端口显示为触发端口 ② 输出事件Output Event Stateflow 向 Simulink 发送的事件 可以触发 Simulink 中的触发子系统 ③ 局部事件Local Event Chart 内部使用的事件 用于状态间的内部通信 ④ 时间事件Temporal Event 基于时间的事件 after(n, sec)n秒后触发 after(n, tick)n个时间步后触发 every(n, sec)每n秒触发一次 示例 after(5, sec)5秒后触发 after(10, tick)10个仿真步后触发 every(1, sec)每秒触发一次10.2.4 数据DataStateflow 中的数据用于存储和传递数值。数据作用域 Local局部 只在 Chart 内部使用 不与 Simulink 交换 Input输入 从 Simulink 接收数据 对应 Chart 的输入端口 Output输出 向 Simulink 发送数据 对应 Chart 的输出端口 Parameter参数 常量参数不随时间变化 从 MATLAB 工作区获取 Constant常数 固定不变的值 数据类型 double / single / int8 / uint8 / boolean / ... 与 Simulink 数据类型一致10.2.5 动作Action动作是在状态或转移中执行的代码。支持的语法 赋值 x 5; y x 1; flag true; 条件语句 if x 0 y x; else y -x; end 循环 for i 1:10 sum sum i; end 函数调用 y my_function(x); [a, b] another_function(x, y); MATLAB 函数部分支持 y abs(x); y sqrt(x); y mod(x, 10); 发送事件 send(EVENT_NAME); 广播事件 send(EVENT_NAME, target_state);10.3 搭建状态机10.3.1 创建 Chart方法1从 Library Browser 添加 Library Browser → Stateflow → Chart 拖拽到 Simulink 模型画布 方法2从菜单创建 Simulink 模型中 菜单 Diagram → New → Chart 方法3命令行 add_block(stateflow/Chart, mymodel/MyChart)Chart 属性配置双击 Chart 进入编辑界面 右键 Chart → Properties General 标签 Action Language MATLAB推荐语法熟悉 C性能更高代码生成 Update method Inherited继承 Simulink 采样时间 Discrete指定采样时间 Continuous连续更新 Enable super step semantics 允许在一个时间步内执行多次转移10.3.2 添加状态和转移添加状态方法1工具栏 Chart 编辑器工具栏 → 状态图标矩形→ 点击画布 方法2右键菜单 在画布空白处右键 → Add State 方法3快捷键 按住 S 键 点击画布 配置状态 双击状态 → 输入状态名称 在状态内部输入动作代码 entry: 初始化代码 during: 持续执行代码 exit: 退出代码添加转移方法1拖拽 鼠标悬停在源状态边缘 出现蓝色箭头时拖拽到目标状态 方法2工具栏 选择转移工具 → 点击源状态 → 点击目标状态 配置转移 双击转移线 → 输入转移标签 格式event[condition]{action} 例TIMEOUT[speed 0]{brake ON}添加默认转移指定初始状态方法 工具栏选择默认转移工具 点击目标状态初始状态 → 生成从实心圆点到初始状态的箭头 每个层级必须有且只有一个默认转移10.3.3 配置转移条件转移条件语法示例 简单条件 [speed 100] [temperature 80] [flag true] 复合条件 [speed 100 temperature 50] [mode 1 || mode 2] [~alarm_active] 时间条件 [after(5, sec)] → 5秒后 [after(100, tick)] → 100个时间步后 [every(1, sec)] → 每秒用于周期性转移 事件条件 BUTTON_PRESS[count 3] → 收到 BUTTON_PRESS 事件且 count 3 时转移 无条件转移立即转移 不写任何标签 → 进入源状态后立即转移到目标状态 通常用于连接节点10.3.4 仿真调试Stateflow 调试工具运行仿真时Chart 编辑器实时显示 当前激活的状态高亮显示 已执行的转移箭头高亮 数据的当前值 调试功能 断点右键状态/转移 → Set Breakpoint 单步执行仿真暂停后逐步执行 数据监视查看变量当前值常见调试问题问题1状态机不转移 检查转移条件是否正确 检查事件是否正确触发 检查数据类型是否匹配 问题2状态机在两个状态间振荡 原因转移条件互相满足来回切换 解决添加时间延迟或计数器防抖 问题3初始状态不正确 检查默认转移是否指向正确的初始状态 检查entry 动作中的初始化是否正确10.4 实战交通灯控制系统10.4.1 需求分析交通灯控制需求 状态 RED红灯持续 30 秒 GREEN绿灯持续 25 秒 YELLOW黄灯持续 5 秒 转移规则 RED → GREEN红灯持续 30 秒后 GREEN → YELLOW绿灯持续 25 秒后 YELLOW → RED黄灯持续 5 秒后 输出 red_lightboolean红灯开关 green_lightboolean绿灯开关 yellow_lightboolean黄灯开关 countdowndouble倒计时秒数 初始状态RED10.4.2 状态机设计状态机图●默认转移 │ ↓ ┌─────────────────────────────────────┐ │ RED │ │ entry: red1; green0; yellow0; │ │ countdown30; │ │ during: countdowncountdown-dt; │ └─────────────────────────────────────┘ │ │ [after(30, sec)] ↓ ┌─────────────────────────────────────┐ │ GREEN │ │ entry: red0; green1; yellow0; │ │ countdown25; │ │ during: countdowncountdown-dt; │ └─────────────────────────────────────┘ │ │ [after(25, sec)] ↓ ┌─────────────────────────────────────┐ │ YELLOW │ │ entry: red0; green0; yellow1; │ │ countdown5; │ │ during: countdowncountdown-dt; │ └─────────────────────────────────────┘ │ │ [after(5, sec)] └──────────────────────────────────→ RED循环10.4.3 Simulink 集成搭建步骤Step 1新建 Simulink 模型 Step 2添加 Stateflow Chart 模块 Library Browser → Stateflow → Chart Step 3配置 Chart 输出端口 在 Chart 中定义输出数据 右键画布 → Add Data → Output 添加red_light, green_light, yellow_light, countdown Step 4在 Chart 内部搭建状态机 添加三个状态RED, GREEN, YELLOW 添加默认转移到 RED 添加三条转移使用 after() 时间条件 在每个状态的 entry 动作中设置灯光输出 Step 5连接 Simulink 模块 Chart 输出端口 → Display 模块显示倒计时 Chart 输出端口 → Scope显示灯光状态 Step 6配置仿真 Stop Time 120s观察两个完整周期 Solver Fixed-step, Step size 1sChart 内部代码RED 状态 entry: red_light true; green_light false; yellow_light false; countdown 30; GREEN 状态 entry: red_light false; green_light true; yellow_light false; countdown 25; YELLOW 状态 entry: red_light false; green_light false; yellow_light true; countdown 5; 转移条件 RED → GREEN[after(30, sec)] GREEN → YELLOW[after(25, sec)] YELLOW → RED[after(5, sec)]10.4.4 仿真验证%% 交通灯仿真验证脚本% 运行仿真simOutsim(traffic_light,StopTime,120);tsimOut.tout;% 获取输出数据redsimOut.logsout.getElement(red_light).Values.Data;greensimOut.logsout.getElement(green_light).Values.Data;yellowsimOut.logsout.getElement(yellow_light).Values.Data;% 绘图figure;subplot(3,1,1);stairs(t,double(red),r-,LineWidth,2);ylabel(红灯);ylim([-0.11.1]);grid on;title(交通灯控制仿真);subplot(3,1,2);stairs(t,double(green),g-,LineWidth,2);ylabel(绿灯);ylim([-0.11.1]);grid on;subplot(3,1,3);stairs(t,double(yellow),Color,[10.70],LineWidth,2);ylabel(黄灯);ylim([-0.11.1]);grid on;xlabel(时间 (s));% 验证时序fprintf( 交通灯时序验证 \n);% 找红灯开始时间red_startst(diff([0;double(red)])0);fprintf(红灯开始时刻);fprintf(%.0f ,red_starts(1:min(3,end)));fprintf(...\n);% 验证周期iflength(red_starts)2periodred_starts(2)-red_starts(1);fprintf(交通灯周期%.0f 秒期望60秒\n,period);end综合实战电机控制模式管理系统描述工业电机控制模式管理 模式状态 IDLE空闲电机停止等待命令 STARTING启动电机加速到目标转速 RUNNING运行电机以目标转速运行 STOPPING停止电机减速到零 FAULT故障检测到故障紧急停机 转移条件 IDLE → STARTING收到 START 命令 STARTING → RUNNING转速达到目标值speed target_speed RUNNING → STOPPING收到 STOP 命令 STOPPING → IDLE转速降到零speed 0 任意状态 → FAULT检测到故障fault_detected true FAULT → IDLE故障清除fault_cleared true 输出 motor_enableboolean电机使能 speed_setpointdouble转速设定值 status_codeint8状态码0空闲,1启动,2运行,3停止,4故障状态机代码IDLE 状态 entry: motor_enable false; speed_setpoint 0; status_code 0; STARTING 状态 entry: motor_enable true; speed_setpoint target_speed; status_code 1; RUNNING 状态 entry: status_code 2; during: % 监控运行状态 if speed target_speed * 0.9 % 转速下降可能有负载变化 speed_setpoint target_speed * 1.1; % 适当提高设定值 else speed_setpoint target_speed; end STOPPING 状态 entry: speed_setpoint 0; status_code 3; exit: motor_enable false; FAULT 状态 entry: motor_enable false; speed_setpoint 0; status_code 4; alarm true; exit: alarm false; 转移 IDLE → STARTINGSTART[~fault_detected] STARTING → RUNNING[speed target_speed * 0.95] RUNNING → STOPPINGSTOP STOPPING → IDLE[speed 1.0] IDLE → FAULT[fault_detected] STARTING → FAULT[fault_detected] RUNNING → FAULT[fault_detected] STOPPING → FAULT[fault_detected] FAULT → IDLE[fault_cleared]本章小结本章核心要点 ✅ Stateflow 用于设计逻辑状态机补充 Simulink 的数学计算能力 ✅ 状态机三要素状态State/ 转移Transition/ 动作Action ✅ 状态动作entry进入时/ during持续/ exit退出时 ✅ 转移语法event[condition]{action} ✅ 时间条件after(n, sec) / every(n, sec) ✅ 默认转移指定初始状态实心圆点箭头 ✅ 层次化状态机超状态包含子状态实现复杂逻辑 ✅ 并行状态AND多个状态同时激活 ✅ 历史节点记住上次离开时的子状态 ✅ 调试仿真时高亮显示当前激活状态和转移课后练习搭建简单开关状态机状态OFF / ON转移按钮按下时切换输出LED 状态0/1在 Simulink 中用 Pulse Generator 模拟按钮搭建交通灯控制系统按照本章示例完整搭建添加紧急模式收到 EMERGENCY 信号时所有灯闪烁黄灯验证时序是否正确搭建电梯控制状态机状态IDLE / MOVING_UP / MOVING_DOWN / DOOR_OPEN转移楼层请求、到达目标楼层、开关门输出当前楼层、运动方向、门状态将电机控制模式管理集成到 SimulinkStateflow 管理模式Simulink 实现电机动力学模型测试各种模式切换场景测试故障注入和恢复