概述
1.1 Stateflow 概 述
Stateflow 是集成于 Simulink 中的图形化设计与开发工具,主要用于针对控制系统中的
复杂控制逻辑进行建模与仿真,或者说,Stateflow 适用于针对事件响应系统(Reactive System)
进行建模和仿真。与事件响应系统相对应的就是动态变换系统(Dynamic Transformational
System)。动态变换系统通常可以利用数学表达式、方程等组成的输入/输出关系进行描述,
像这样的系统利用 Simulink 进行建模是最为方便的。而事件响应系统通常利用一些自然语
言或者逻辑表达式进行描述,这样的系统就需要利用 Stateflow 来进行建模。Stateflow 与
Simulink 结合起来,可以创建确定性监管控制系统。利用 Stateflow 可视化的模型和直观的
仿真能力,可以清晰、简洁地反映出复杂动态逻辑关系。Stateflow 的基础是有限状态机理
论,它通过对状态图、流程图的创建,对事件驱动系统进行建模和仿真。
(以上概述来自 《Stateflow 逻辑系统建模 张 威 编著》 )希望大家好好理解两种系统的含义和区别。
1.2 Stateflow基本概念
在使用 Stateflow 创建模型时,需要首先澄清几个基本的概念——状态机、Stateflow 图
块和 Stateflow 框图的含义:
■ Stateflow 状态机(State machine) —— 包含在模型中的所有的 Stateflow 块的集合,
即一个 Simulink 模型中包含的所有 Stateflow 模型统称为一个 Stateflow 状态机。
■ Stateflow 图块(Chart) —— 包含状态图的模块,即 Simulink 模型中的 Chart。
■ Stateflow 框图(Diagram) —— 状态图的图形化表述,即具体的 Stateflow 图块所包
含的内容。在每个 Stateflow 块和 Stateflow 框图之间存在一一对应的关系
Stateflow 中包含图形对象和非图形对象,这些对象都是按照一定的层次组合在一起的。
在下图 中,总结了这些图形/非图形对象之间的关系,特别是不同的对象之间的相互包
含关系。
Stateflow 图形/非图形对象之间的关系图
在 Stateflow 数据字典中,Stateflow 的对象可以分为三个层次:
● Machine:状态机对象。状态机是当前模型中所有状态框图的集合,即状态机对象相
当于包含 Stateflow 图块的 Simulink 模型。在状态机中,可以包含事件、数据对象以及编译
目标等。
● Chart:状态图对象。状态图对象是状态机对象的子对象,状态图对象中可以包含状
态、图形函数、图形盒、连接节点、转移、注释、数据对象和事件等。
● State/Function/Box。State/function/box 这三个对象之间可以互相包含、互相嵌套,并
且也可以包含事件、数据对象、注释、转移、连接节点等。
1.3 Stateflow状态图和流程图的区别
在 Stateflow 模型中,将包含有状态(state)的 Stateflow 框图称为状态图,而将不包含任何状态
的 Stateflow 框图称为流程图(只包含节点junction)。
2 Stateflow语法
以下内容均来自MATLAB官网,本文只是整理记录,您可以直接去官网查看。
https://ww2.mathworks.cn/help/stateflow/syntax-for-states-and-transitions.html?s_tid=CRUX_lftnav
2.1状态
状态用于描述反应式系统的工作模式。在 Stateflow® 图中,状态用于顺序设计以创建状态转移图。
状态可以是激活或非激活。状态的激活或非激活情形会因事件和条件而发生变化。事件的发生会驱动状态转移图的执行,使状态变为激活或非激活。
在执行过程的任意时间点,都存在激活和非激活的状态。
2.1.1状态层次结构
要管理多级状态复杂性,可以在 Stateflow 图中使用层次结构。借助层次结构,可以表示系统中多个层级的子组件。
状态层次结构示例
在下例中,图中显示了三个层级。在一个状态的边界内绘制另一个状态表示内部状态是外部状态(或父状态)的子状态(或子级)。外部状态是内部状态的父级。
在本例中,图是状态 Car_done
的父级。状态 Car_done
是 Car_made
和 Car_shipped
状态的父状态。状态 Car_made
也是 Parts_assembled
和 Painted
状态的父状态。
也可以说状态 Parts_assembled
和 Painted
是 Car_made
状态的子级。
要以文本形式表示 Stateflow 层次结构,可以使用斜杠字符 (/)
表示图,使用句点 (.)
分隔状态层次结构中的每一级。下表提供了上例中对象层次结构的文本表示形式:
-
/Car_done
-
/Car_done
.Car_made
-
/Car_done
.Car_shipped
-
/Car_done
.Car_made
.Parts_assembled
-
/Car_done
.Car_made
.Painted
状态可以包含的对象
状态可以包含所有其他 Stateflow 对象。Stateflow 图表示法支持在存在包含关系的 Stateflow 图中表示图形对象层次结构。如果某个状态包含其他状态,则该状态为父状态。如果某个状态包含在另一状态中,则该状态为子状态。如果某状态既不是另一状态的父状态也不是另一状态的子状态,其父级是 Stateflow 图本身。
状态还可以包含非图形数据、事件和消息对象。此包含关系的层次结构会显示在 Model Explorer 中。通过指定父对象来定义数据、事件和消息包含关系。
2.1.2状态分解
每个状态(或图)都有分解,表示该状态(或图)可以包含哪些类型的子状态。父状态的所有子状态必须与父状态分解是同一类型。状态分解可以是互斥 (OR) 形式或并行 (AND) 形式。
互斥 (OR) 状态分解
带有实线边框的子状态表示互斥 (OR) 状态分解。此分解可用于描述互斥工作模式。当状态拥有互斥 (OR) 分解时,一次只能有一个子状态激活。
在下例中,状态 A
或状态 B
中的一个可以是已激活。如果状态 A
已激活,则状态 A1
或状态 A2
可以在给定时间激活。
并行 (AND) 状态分解
带有虚线边框的子状态表示并行 (AND) 状态分解。使用此分解可以描述并行工作模式。当状态拥有并行 (AND) 分解时,所有子状态同时激活。
在下例中,当状态 A
激活时,A1
和 A2
两者可以同时激活。
并行状态内的活动本质上独立的,如下例所述。
在下例中,当状态 A
变为激活时,状态 B
和 C
同时变为激活。当状态 C
变为激活时,状态 C1
或状态 C2
中的一个可以激活。
2.1.3状态标签
状态标签显示在状态的长方形框的左上角,一般为以下格式:
name/
entry:entry actions
during:during actions
exit:exit actions
on event_name:on event_name actions
on message_name:on message_name actions
bind:events
下例显示了状态标签的构成。
状态标签中的每个动作会显示在后面的子主题中。有关状态动作的详细信息,请参阅:
-
Stateflow 图的执行 - 描述图执行的方式和时间。https://ww2.mathworks.cn/help/stateflow/ug/chart-during-actions.html
-
状态动作类型 - 提供了每种状态动作类型(
entry
、during
、exit
)的更加详细的说明。https://ww2.mathworks.cn/help/stateflow/ug/state-action-types.html
下表汇总了不同的状态动作类型。
状态动作 | 缩写 | 说明 |
---|---|---|
entry | en | 状态变为激活时执行。 |
exit | ex | 状态已激活且发生转出状态的转移时执行。 |
during | du | 状态已激活且发生特定事件时执行。 |
bind | 无 | 绑定事件或数据对象,确保只有该状态及其子状态可以广播该事件或更改数据值。 |
| 无 | 状态已激活且收到 event_name 广播时执行。 |
| 无 | 出现 message_name 消息时执行。 |
| 无 | 执行时间:
有关详细信息,请参阅 |
| 无 | 执行时间:
有关详细信息,请参阅 |
| 无 | 执行时间:
有关详细信息,请参阅 |
| 无 | 执行时间:
有关详细信息,请参阅 |
2.1.4状态名称
状态标签开头为状态名称,其后可接 /
字符。在前面的示例中,状态名称是 On
和 Off
。有效的状态名称由字母数字字符组成,可以包含下划线字符 (_
)。有关详细信息,请参阅Rules for Naming Stateflow Objects。
层次结构为状态命名提供了一些灵活性。您在状态标签上输入的名称在前接父级状态名称后必须唯一。Stateflow 层次结构中的名称,由您输入的状态标签文本前接句点分隔的各父状态名称组成。每个状态在标签上显示的名称可以相同,只要其在层次结构内的完整名称唯一即可。否则,解析器会指示错误。
下例展示了状态的唯一命名机制。
以下每个状态因其在图中的位置而拥有一个唯一名称。状态在 FAN1
和 FAN2
中的完整名称为:
-
PowerOn.FAN1.On
-
PowerOn.FAN1.Off
-
PowerOn.FAN2.On
-
PowerOn.FAN2.Off
2.1.5状态动作
在名称后面,可以输入用于该状态的动作语句,其中带有标识动作类型的关键字标签。您可以不指定任何动作,或指定部分或全部动作。每个关键字必须后接冒号。状态名称后的斜杠不是必需的,只要名称后面接回车符即可。
对于每种动作类型,可以输入多个动作,以回车符、分号或逗号分隔。可以通过增添 on
event_name
或 on
message_name
行,为一个或多个事件或消息指定动作。
如果在名称和斜杠后直接输入动作,该动作将解释为 entry
动作。当您只是要指定 entry
动作时,此简化形式很有用。
entry 动作. 以前缀 entry
或 en
(简写)开头。在前面的示例中,状态 On
具有 entry
动作 on_count=0
。这表示无论何时状态 On
激活(进入),on_count
的值会重置为 0。
during 动作. 以前缀 during
或 du
(简写)开头。在上面的标签示例中,状态 On
有两个 during
动作,light_on()
和 on_count++
。无论何时状态 On
已激活并发生任何事件时,这些动作都会执行。
exit 动作. 以前缀 exit
或 ex
(简写)开头。在上面的标签示例中,状态 Off
有 exit
动作 light_off()
。如果状态 Off
之前为激活,在变为未激活(退出)后,会执行此动作。
On 动作. 以前缀 on
event_name
或 on
message_name
开头。在上面的标签示例中,状态 On
有一个 on power_outage
动作。如果状态 On
激活,事件 power_outage
发生,则会执行动作 handle_outage()
。
Bind 动作. 以前缀 bind
开头。绑定到状态的事件只能由该状态或其子状态广播。
2.2转移
转移是一条将多个图形对象连接在一起的带箭头的直线。在大多数情况下,转移表示系统在不同模式(状态)间转移的通道。转移通常连接来源和目标对象。源对象是转移开始的位置,目标对象是转移结束的位置。下图显示了从源状态 B
到目标状态 A
的转移。
节点将转移分为多个转移段。在这种情况下,一个完整的转移由从来源到目标状态经过的多个段构成。在确定完整转移有效性的过程中,会对每个段进行计算。
下例显示了两个转移段:一个从状态 On
到状态 Off
,另一个从状态 On
到其本身:
默认转移是一种没有源对象的特殊转移类型。有关详细信息,请参阅默认转移。
2.2.1转移层次结构
转移不能像状态那样包含其他对象。但是转移包含在状态中。转移的层次结构通过其父级、源状态和目标状态几个方面来描述。父级是最低层级,包含转移的源对象和目标对象。考虑下例中转移的父级:
下表分析了上例中每个转移的父级关系。/
字符表示图。状态层次结构的每一级使用句点字符 (.
) 分隔。
转移标签 | 转移父级 | 转移源 | 转移目标 |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
2.2.2转移标签表示法
转移标签可以包含事件或消息、条件、条件动作和转移动作。标签的每部分均为可选。?
字符是默认的转移标签。转移标签的完整格式如下:
event_or_message[condition]{condition_action}/transition_action
注意:
组成转移标签的四个部分不一定完整地出现,但是不论出现哪几个部分,标签的内容必须按照上面指定的顺序书写。
触发事件或消息
指定在条件为 true 时导致转移发生的事件或消息。使用 OR 逻辑运算符 (|
) 可指定多个事件。指定事件或消息是可选项。未指定事件或消息表示在发生任意事件时都会产生该转移。有关详细信息,请参阅通过广播事件同步模型组件和通过发送消息与 Stateflow 图通信。
在前面的示例中,只要条件 [off_count==0]
为 true,事件 E
的广播就会触发从 On
到 Off
的转移。
条件
指定一个布尔表达式,当其计算结果为 true 时,会对指定的触发事件或消息所关联转移的有效性进行验证。条件需括在方括号 ([]
) 内。如果未指定任何条件,则隐含的条件会计算为 true。有关详细信息,请参阅条件。
在前面的示例中,发生事件 E
时,条件 [off_count==0]
的计算结果必须为 true,从 On
到 Off
的转移才能生效。
条件动作
发生在转移条件的计算结果为 true 之后,到目标的转移被确定为有效之前。将条件动作括在花括号 ({}
) 中并放在条件后。有关详细信息,请参阅条件动作行为。
在前面的示例中,如果事件 E
发生且条件 [off_count==0]
为 true,则立即执行条件动作 {off_count = off_count + 1}
。
转移动作
在到目标的转移被确定为有效之后执行。如果转移包含多个段,则在到达最终目标的整个转移路径被确定为有效时,才会执行转移动作。转移动作发生在源状态的 exit 动作之后、目标状态的 entry 动作之前。转移动作前面要接 /
。有关详细信息,请参阅条件和转移动作行为。
在前面的示例中,如果发生事件 E
且条件 [off_count==0]
为 true,则转移动作 {Light_off()}
在从 On
到 Off
的转移被确定为有效后开始执行。转移动作发生在 On
变为非激活之后、Off
变为激活之前。
仅 Stateflow® Simulink® 模型中的图支持转移动作。
2.2.3有效转移
通常,当某个转移的源状态处于激活状态且转移标签有效时,该转移就是有效的。默认转移则不同,因为缺少源状态。对于进入某子状态的默认转移,当存在进入该子状态的父状态(假定该父状态是激活的)的转移时,会对该默认转移的有效性进行评估。此标签准则对默认转移和一般的转移都适用。下表列出了有效转移标签的各种可能的情况。
转移标签 | 在以下情况下有效 |
---|---|
仅事件 | 事件发生 |
事件和条件 | 事件发生,且条件为 true |
仅消息 | 该消息出现 |
消息和条件 | 该消息出现,且条件为 true |
仅条件 | 发生任何事件,且条件为 true |
仅动作 | 发生任何事件 |
未指定 | 发生任何事件 |
注意:
条件动作与转移动作两者之间的区别:
条件动作在条件满足的情况下就能够执行,而转移动作需要在整个转移通路都有效的情况下,在执行转移的时候才执行。
下图给出了一个例子。
这里的转移由两个部分组成,假设当前 C1 条件为真而 C2 条件为假,则整个转移通路是无效的,但是条件动作 A1 会执行,因为该条件所处的转移通路局部是有效的,但是由于
C2 为假,因此所有转移动作(A2 和 A4)都不会执行。C2 条件为假,则条件动作 A3 也不会执行。
此示例说明转移标签的各个部分。
2.2.4转移连接
互斥 (OR) 状态的出向/入向转移
此示例说明互斥 (OR) 状态的简单出向/入向转移。
以下转移... | 在以下情况下有效... |
---|---|
从 B 到 A | 状态 B 处于激活状态,且事件 E1 发生。 |
从 A1 到 A2 | 状态 A1 处于激活状态,且事件 E2 发生。 |
请参阅Transition Between Exclusive States了解有关此表示法语义的详细信息。
结点的出向/入向转移
下图显示连接结点的出向/入向转移。
图使用时序逻辑确定输入 u
何时等于 1。
输入等于 1 的时间点 | 产生的转移路径 |
---|---|
t = 2 之前 | 从 Start 到 Fast |
介于 t = 2 和 t = 5 之间 | 从 Start 到 Good |
在 t = 5 之后 | 从 Start 到 Slow |
有关时序逻辑的详细信息,请参阅使用时序逻辑控制图的执行。有关此表示法语义的详细信息,请参阅Transition from a Common Source to Multiple Destinations。
互斥 (OR) 父状态的出向/入向转移
此示例说明互斥 (OR) 父状态的出向/入向转移以及默认转移的使用。
该图在最高层级有两个状态,即 Power_off
和 Power_on
。默认情况下,Power_off
处于激活状态。事件 Switch
使系统在 Power_off
和 Power_on
状态之间切换。Power_on
有三个子状态:First
、Second
和 Third
。默认情况下,当 Power_on
变为激活状态时,First
也变为激活状态。当 Shift
等于 1 时,对于事件 Switch
的每次发生,系统从 First
转移到 Second
或从 Second
转移到 Third
或从 Third
转移到 First
,然后重复该模式。
有关此表示法语义的详细信息,请参阅Control Chart Execution by Using Default Transitions。
子状态的出向/入向转移
以下示例说明互斥 (OR) 子状态的出向/入向转移。
有关此图如何工作的详细信息,请参阅使用故障检测实现信号去抖。有关此表示法语义的信息,请参阅Transition from a Substate to a Substate with Events。
2.3转移动作的类型
转移可以有不同的动作类型,包括事件或消息触发器、条件、条件动作和转移动作。动作类型采用标签表示法,一般格式如下:
event_or_message trigger[condition]{condition_action}/{transition_action}
下面的示例说明了典型的转移标签语法:
转移 | 触发事件 | 条件 | 条件动作 | 转移动作 |
---|---|---|---|---|
从状态 A 到状态 C | event1 | temp > 50 | func1() | 无 |
从状态 A 到状态 B | event2 | 无 | 无 | data1 = 5 |
2.3.1事件或消息触发器
在转移标签语法中,事件或消息触发器作为事件或消息的名称首先出现。没有特别的区分字符可以将它们与转移标签中的其他动作区别开来。在转移动作的类型中的示例中,来自状态 A 的两个转移都有事件触发器。状态 A 到状态 B 的转移带有事件触发器 event2
,状态 A 到状态 C 的转移带有事件触发器 event1
。
事件触发器指定在已指定条件且条件为 true 时导致转移发生的事件。可以选择是否指定事件。消息触发器指定如果消息队列中存在消息则发生转移。未指定事件或消息表示在发生任意事件时都会产生该转移。可以使用 OR 逻辑运算符 (|
) 指定多个事件或消息。
2.3.2条件
在转移标签语法中,条件是括在方括号 ([]
) 中的布尔表达式。在转移动作的类型的示例中,从状态 A 到状态 B 的转移包含条件 temp > 50
。
条件是一个布尔表达式,用于指定在该指定表达式为 true 时会发生转移。遵循以下指导原则定义和使用条件:
-
条件表达式必须是计算结果为 true (1) 或
false
(0) 的布尔表达式。 -
条件表达式可以由以下任何项构成:
-
布尔运算符,用于比较数据和数值
-
函数,返回布尔值
-
in(state_name)
条件,当指定为参数的状态处于激活状态时,该条件计算结果为 true(请参阅 Check State Activity by Using the in Operator)注意
Stateflow 图无法使用
in
条件基于其他 Stateflow 图中状态的活动来触发动作。 -
时序逻辑条件(请参阅使用时序逻辑控制图的执行)时序逻辑条件https://ww2.mathworks.cn/help/stateflow/ug/using-temporal-logic-in-state-actions-and-transitions.html
-
-
条件表达式可以调用图形函数、真值表函数或返回数值的 MATLAB® 函数。
例如,
[test_function(x, y) < 0]
就是有效的条件表达式。注意
如果条件表达式调用可返回多个值的函数,将只使用第一个值,而不会使用其他返回值。
-
条件表达式不应调用会导致 Stateflow 图更改状态或修改任何变量的函数。
-
可以对布尔表达式进行分组:对于带 AND 关系的表达式,使用 &;对于带 OR 关系的表达式,使用
|
。 -
赋值语句不是有效的条件表达式。
-
一元递增和递减操作不是有效的条件表达式。
2.3.3条件动作
在转移标签语法中,条件动作接在转移条件后,并括在花括号 ({}
) 中。在转移动作的类型的示例中,从状态 A 到状态 C 的转移包含条件动作 func1()
,它是一个函数调用。
只要条件计算结果为 true,条件动作即开始执行,无论转移至目标的路径是否有效。如果未指定任何条件,则隐含的条件会计算为 true,并执行条件动作。
注意
如果条件由事件保障,则只检查事件触发器是否已激活。如果条件由消息保障,则只检查是否存在消息。
2.3.4转移动作
在转移标签语法中,转移动作以正斜线 (/
) 开头,并括在花括号 ({}
) 中。在转移动作的类型的示例中,从状态 A 到状态 B 的转移包含转移动作 data1 = 5
。在 C 语言状态图中,转移动作不需要括在花括号中。在使用 MATLAB 作为动作语言的图中,如果转移动作中缺少花括号,语法会自动更正。请参阅Auto Correction When Using MATLAB as the Action Language。
转移动作只在获取完整的转移路径之后才会执行。它们在转移目标确定为有效且条件(如果指定)为 true 后执行。如果转移由多个段组成,转移动作只在到最终目标的整个转移路径确定为有效后执行。
仅 Stateflow® Simulink® 模型中的图支持转移动作。
2.4默认转移
默认转移指定当系统不明确要进入两个或多个相邻的互斥 (OR) 状态中哪个状态时要进入的状态。默认转移具有目标对象,但是没有源对象。例如,默认转移指定在缺少任何其他信息(例如历史结点)的情况下,系统默认进入互斥 (OR) 分解类型的父状态的哪个子状态。默认转移也可以指定默认情况应进入结点。
2.4.1绘制默认转移
点击工具栏中的 Default transition 按钮,然后点击您想要作为默认转移之目标的状态或结点旁边的绘图区域中的某个位置。将鼠标拖放到目标对象以附加默认转移。在某些情况下,为默认转移添加标签会有帮助。
一个常见的编程错误是创建无默认转移的多个互斥 (OR) 状态。缺少默认转移时,不会指示哪个状态默认变为激活。注意,当您在 State Inconsistencies 选项处于启用状态的情况下进行模型仿真时,会标记此错误。
2.4.2为默认转移添加标签
您可以像为其他转移添加标签一样来为默认转移添加标签。例如,在某一情况下,您可能想指定某状态在某事件发生后应变为激活。在另一情况下,您可能会希望指定基于转移的目标来执行特定动作。
提示
为默认转移添加标签时,确保至少存在一个有效的默认转移。否则,图会转移至不同的状态。
2.4.3默认转移示例
下面提供了在 Stateflow® 图中使用默认转移的示例:
默认状态转移示例
下例显示了转至状态的默认转移。
没有进入状态 PowerOff
的默认转移时,如果 Stateflow 图唤醒,任何状态都不会激活。在运行时系统会报告状态不一致性错误。
请参阅Control Chart Execution by Using Default Transitions了解有关此表示法语义的信息。
默认结点转移示例
下例显示了转至结点的默认转移。
该连接结点的默认转移定义在进入 Stateflow 图后,将根据每个转移段的条件来确定目标。
请参阅Default Transition to a Junction了解有关此表示法语义的信息。
带标签的默认转移示例
下例显示了带标签的默认转移。
当图唤醒后,数据 p
和 v
会分别初始化为 10 和 15。(一般作为初始化使用)
请参阅Labeled Default Transitions了解有关此表示法语义的详细信息。
2.4.4默认转移注意事项
在默认转移上增加事件的限制时需要小心。这里,读者可通过运行 Stateflow 模型具体的实例,来了解一下默认转移的特殊之处。首先 创建如下图所示的 Stateflow 模型
如图所示模型的默认转移上面具有事件 On 作为转移的标签。也就是说,这个模型的默认转移是受 On 事件来监控的。那么,当整个系统第一个发生的触发事件是 On 时,系统会如何工作?如果整个系统第一个发生的触发事件不是 On,系统又会如何工作呢?很显然,如果整个系统第一个发生的触发事件是 On,则系统会正常工作。系统激活Stateflow 状态图,然后执行默认的转移,接着激活 PowerOn 状态。但当第一个发生的触发事件不是 On 时,认为上面的 Stateflow 状态图不进入活动状态而保持原样等待 On 事件的到来,就是一个非常严重的错误!
这里需要再次强调:一旦状态图被激活,则必须有一个子状态被激活,否则系统会发出一个二义性的警告。而且,只要有事件发生(不管发生的是哪个事件),系统都会尝试去激活状态图。所以上图中,当默认转移在状态图的第一层时,如果第一次触发事件发生时默认转移无效(因为发生的事件不是 On),则系统将发出一个二义性警告,因为系统无法确定具体哪一个子状态应该被激活。因此在执行该模型时,会出现如图 3-13 所示的警告界面。
另外也请读者牢记这样一点,一旦 Stateflow 状态图被激活,则状态图会一直处于激活状态直到系统仿真的结束。由于默认转移的执行需要依赖状态机的再次激活,因此上图中的默认转移将不再有机会执行了。
也就是说,默认转移只有一次被检测执行的机会,就是在状态机被激活的时候。
这是由于第一个发生的事件不是 On 事件,状态机激活时该默认转移虽被检测,但是无效,尽管下一个发生的事件是 On,但默认转移已经不起作用了。为了避免此类错误,一般最好不要在默认转移上增加事件的限制。
如果必须根据具体发生事件来触发整个系统的执行,则可以考虑将 Stateflow 的框图包含于使能子系统中,并且设置触发信号类型为 Reset。
总之,大家在创建 Stateflow 状态图时,一定要保证它能够被正确地激活,否则整个系统将无法正常工作。
2.5内部转移
内部转移是不退出源状态的转移。当为互斥(OR)分解定义超级状态时,内部转移功能强大。使用内部转移可以极大地简化状态流图,如以下示例所示:®
- 使用内部转移之前
- 使用内部转移到连接节点后
- 使用内部转移到历史记录节点
2.5.1使用内部转移之前
此图表是如何使用内部转移简化逻辑的示例。
任何事件发生并唤醒状态流图。默认转移到连接节点是有效的。转移的目标对象由 [c1 > 0]和 [c2 > 0]决定。如果为 [c1 > 0]true,则转移到A1为 true。
如果为 [c2 > 0]true,则 转移到A2为有效。如果两者[c1 > 0]或[c2 > 0]都不正确,则 转移到A3为有效。A1,A2和A3 之间的转移,由事件E,[c1 > 0] 和 [c2 > 0]决定。
2.5.2使用内部转移到连接节点后
以下内容大部分来自MATLAB官网 :https://ww2.mathworks.cn/help/stateflow/ug/inner-transitions.html 还有一部分来自:《Stateflow 逻辑系统建模 张 威 编著》
此示例使用内部转移到连接节点简化了前面的示例。
发生一个事件E并唤醒图表。到连接节点的默认转移有效。转移的目标由[c1 > 0] 和[c2 > 0] 确定。
您可以使用内部转移代替原始示例中所有状态之间的转移来简化图表。在 Stateflow 框图中,状态 A 为父状态,A1、A2 和 A3 状态为 A 状态的子状态。
在这个框图的执行过程中,使用事件 E 和条件 C1、C2 控制内部子状态之间的转移,同时条件 C1 和 C2 也控制了默认转移。在条件 C1 满足时,默认转移激活 A1 子状态,
条件 C2 满足时则激活 A2 子状态,两个条件都不满足时激活 A3 子状态。而子状态之间的转移首先需要事件 E 发生,而后根据条件进行判断,决定激活哪个子状态。总的来说,
当事件 E 发生且条件 C1 满足时,系统总会激活 A1 子状态;当事件 E 发生且条件 C2 满足时,系统总会激活 A2 子状态;当事件 E 发生但两个条件都不满足时,系统总会激活 A3 子状态。
这个框图的子状态之间的转移和默认转移的分支存在某些共同的东西,那么就可以使用内部转移来简化框图。
提示:
如上图 所示框图中的默认转移是不能忽略的,即使在系统中仅定义了一个事件 E,即父状态 A 是由事件 E 触发唤醒的也是如此。默认转移必须存在于父状态内部,如果忽略了默认转移,
在模型运行过程中会出现二义性错误,所以内部转移是无法替代默认转移的。默认转移发挥作用的前提是父状态已经处于活动状态。
注意:
当您使用连接到连接点的内部转移时,活动子状态可以在该子状态的转移条件有效时退出并重新输入。例如,如果子状态A1处于活动状态且[c1 > 0]为 true,则 转移到A1为 有效。在这种情况下:
- 用于A1执行完成和退出操作。
- A1变为非活动状态。
- A1变为活动状态。
- 用于A1 执行 和 完成 进入操作。
有关此表示法语义的信息,请参阅处理具有内部转移到连接节点的第一个事件。
如果内部转移的终点位于子状态边缘,则相应的内部转移就会激活相应的子状态。例如利用内部转移简化的车载音响系统的框图,如下图所示:
内部转移简化后框图,如下图所示
2.5.3使用内部转移到历史记录节点
此示例显示到历史记录节点的内部转移。
状态Power_on.High最初处于活动状态。发生事件 Reset 时,到历史记录节点的内部转移有效。由于内部转移有效,因此当前活动状态 Power_on.High退出。处理到历史记录结的内部转移时,最后一个活动状态 Power_on.High变为活动状态(重新进入)。如果在同一情况下Power_on.Low处于活动状态,则Power_on.Low将因此退出并重新进入。本示例中的内部转移等效于在Power_on.Low 和 Power_on.High上绘制外部自循环转移。
有关使用历史记录节点的另一个示例,请参阅历史记录节点示例。
有关此表示法的语义,请参阅内部转移到历史记录节点。
2.5.4内部转移的执行
内部转移的终点位于子状态的外边缘的情况很容易理解。如下图 所示的 Stateflow 框图中,定义了三个事件 E、T、R,其中事件 R 处于内部转移上,它用来限制内部转移的执行,同时状态 A 中的内部转移终点是历史节点。那么像这样的系统运行起来会是什么样的效果呢?
父状态A 和子状态 A1同时 处于活动状态
假设当前父状态 A 处于活动状态,同时子状态 A1 处于活动状态,当事件 R 发生时,系统将按照下列次序执行相应的对象和动作:
(1) 首先系统检查是否存在能够使状态 A 退出活动状态的转移,即是否有向外的转移,显然不存在这样的转移,因而此时内部转移有效;
(2) 于是退出子状态 A1,执行子状态 A1 的 exit 动作 out = 2,在 MATLAB 命令行窗体中将看到相应的输出 ;如果(out = 2;)末尾加分号了就不会输出到MATLAB 命令行窗体了。
(3) 此时历史节点记录 A1 子状态为最后一个退出活动的子状态;
(4) 根据历史节点的作用,系统重新激活子状态 A1,执行 A1 子状态的 entry 动作 out = 1,在 MATLAB 命令行窗体中将看到相应的输出;
(5) 系统进入到挂起状态,等待下一个触发事件的到来。
父状态A 和子状态 A2同时 处于活动状态
同理,如果当前父状态 A 处于活动状态,同时子状态 A2 处于活动状态,当事件 R 发生时系统将按照下列次序执行相应的对象和动作:
(1) 首先系统检查是否存在能够使状态 A 退出活动状态的转移,显然不存在这样的转移,因而此时内部转移有效;
(2) 退出子状态 A2,执行子状态 A2 的 exit 动作 out = 4,在 MATLAB 命令行窗体中将看到相应的输出;
(3) 此时历史节点记录 A2 子状态为最后一个退出活动的子状态;
(4) 根据历史节点的作用,系统重新激活子状态 A2,执行 A2 子状态的 entry 动作 out = 3,在 MATLAB 命令行窗体中将看到相应的输出;
(5) 系统进入到挂起状态,等待下一个触发事件的到来。
其实,让内部转移的终点处于历史节点相当于为每个子状态创建了自循环的转移,即从子状态的外边缘出发终止于同一个子状态外边缘的转移。下图所示的自循环框图与上图 所
示的框图是等效的
提示:
如果状态 A 具有 during 状态动作,则在执行框图内部转移的过程中,系统将首先执行状态 A 的 during 状态动作,然后再来处理内部转移的相关工作。同样,对于自循环转移框图也如此。
2.6自循环转移
自循环转移是源自同一状态并终止的转移。以下图表包含四个自循环转移:
有关此表示法的语义,请参阅以下部分:
- 自循环转移
- For-循环构造
2.7 使用连接节点构造多条路径
转移线段的标签格式
进入结点(junction)的转移线段的标签格式与进入状态(State)的转移段的标签格式相同,如以下示例所示。 图表使用出向转移的隐式排序(请参阅隐式排序)。
在此示例中,将执行转移,如下所示:
- 当事件发生时,将检查状态S1是否有指定了匹配事件的出向转移。
- 如果找到具有匹配事件的转移,则计算该转移的转移条件(括号内)。
- 如果
condition_1
的计算结果为“真”,则执行条件动作条件condition_action(大括号内)。 - 将检查交叉点的出向转移是否有效。由于
condition_2
为真,因此存在从S1到S2的有效状态转移。 - 完成操作并退出S1。
- 状态S1被标记为不活动。
- 转移动作transition_动作执行并完成。
- 完成从S1到S2的状态转移。
- 状态S2标记为活动。
- 状态S2进入动作执行并完成。
2.7.1If-Then-Else决策结构
这个例子展示了if-then-else决策构造的行为。图表使用传出转移的隐式排序(请参阅隐式排序)。
最初,图表处于休眠状态。然后状态A处于活动状态。条件为 [C_two] 为true。事件E_one 发生并唤醒图表,该图表从根向下处理事件,通过层次结构:
- 图表根检查是否由于E_one进行了有效转移。
- 存在从状态A到连接节点点的有效转移线段。 由于应用了隐式排序,因此将判断从结点的12点钟位置开始的转移线段的有效性。 标有条件[C_one]的第一个转移线段无效。 标记有条件[C_two]的下一个转移线段有效。 从状态A到状态C的完整转移是有效的。
- 状态A退出动作(exitA())执行并完成。
- 状态A被标记为不活动。
- 状态C被标记为活动。
- 状态C入口操作(entC())执行并完成。
- 图表回到睡眠状态。
此序列完成了与事件E_one相关的Stateflow®图表的执行。
2.7.2自循环转移
此示例显示使用连接节点的自循环转移的行为。图表使用出向转移的隐式排序(请参阅隐式排序)。
最初,图表处于睡眠状态。 状态A处于活动状态。 条件[C_one]为假。 事件E_one发生并唤醒图表,该图表从根到整个层次结构都处理该事件:
- 图表根检查是否由于E_one进行了有效转移。 存在从状态A到连接节点的有效转移线段。 因为应用了隐式排序,所以将判断带有条件的转移线段的有效性。 因为条件[C_one]无效,所以从状态A到状态B的完整转移是无效的。 从连接节点回到状态A的转移线段有效。
- 状态A退出动作(exitA())执行并完成。
- 状态A被标记为不活动。
- 执行并完成转移动作A_two。
- 状态A被标记为活动。
- 状态A输入动作(entA())执行并完成。
- 图表回到睡眠状态。
此序列完成了与事件E_one相关的Stateflow图的执行。
2.7.3For-循环构造
此示例显示使用连接节点的循环的行为。图表使用出向转移的隐式排序(请参阅隐式排序)。
最初,图表处于睡眠状态。 状态A处于活动状态。 事件E_one发生并唤醒图表,该图表从根到整个层次结构都处理该事件:
- 图表根检查是否由于E_one进行了有效转移。从状态A到连接节点点存在有效的转移。转移线段上的转移条件condition action i = 0执行并完成。在离开连接节点的两个转移中,作为自循环转移,接下来进行自循环返回连接节点(for循环有效性)的有效性判断。因为另一个转移线段未被使能,所以该转移具有判断有效性的优先权。此判断行为反映了图表中出向转移的隐式顺序。
- condition [i <10]判断为true。条件操作i ++和对func1的调用将执行并完成,直到条件变为假。由于连接节点不是最终目的地,因此转移目的地仍然是未知的。
- 状态B的无条件转移现在有效。从状态A到状态B的完整转移是有效的。
- 状态A退出动作(exitA())执行并完成。
- 状态A被标记为不活动。
- 状态B被标记为活动。
- 状态B入口动作(entB())执行并完成。
- 图表回到睡眠状态。
该序列完成了与事件E_one相关联的该图表的执行。
2.7.4流程图表示法
此示例显示使用流程图表示法的状态流图的行为。图表使用出向转移的隐式排序(请参阅隐式排序)。
最初,图表处于睡眠状态。状态A.A1处于活动状态。条件[C_one()]最初是 true。事件E_one发生并唤醒图表,该图表从根向下处理事件,通过层次结构:
- 图表根将检查 是否由于E_one 而存在有效的转移。没有有效的转移。
- 状态A检查自身是否存在有效转移,同时状态A检测到连接节点存在有效内部转移。
- 判断转移的下一个可能的部分。仅存在一个出向转移,并且它定义了一个{c_action}条件操作。{c_action}条件操作将执行并完成。
- 判断下一个可能的转移。存在两个出向转移:条件自循环转移和无条件转移。由于隐式排序适用,因此条件自循环转移优先。由于条件[C_one()]为 true,则采取自循环转移。由于尚未到达最终转移目标,因此此自循环一直持续到 [C_one()] false。
假设在五次迭代之后,[C_one()]为 false。
- 将计算下一个可能的转移(到下一个连接节点)。它是具有条件操作的无条件转移段。将执行转移段,{d=my_func()}并执行和完成条件操作。d返回的值是 84。
- 判断下一个可能的转移。存在三个出向转移:两个条件动作和一个无条件动作。由于隐式排序适用,因此标签为 条件[d < 100]转移线段首先根据两个出向条件转移段的几何体进行判断。因为d 返回的值为 84,所以条件为[d < 100] true,并且此转移到目标状态A.A1有效。
- 状态A.A1退出,操作 (exitA1()) 执行并完成。
- 状态A.A1标记为非活动状态。
- 状态标记为活动状态。A.A1
- 状态A.A1进入操作 (entA1()) 执行并完成。
- 图表回到睡眠状态。
此序列完成与事件关联的此状态流图的执行。E_one
2.7.5转移从公共源到多个目标
此示例显示使用连接节点从公共源到多个条件目标的转移行为。图表使用出向转移的隐式排序(请参阅隐式排序)。
最初,图表已睡眠。状态A处于活动状态。事件E_two发生并唤醒图表,该图表通过层次结构从根向下处理事件:
- 图表根将检查 是否由于E_two 而存在有效的转移。从状态A到连接节点存在有效的转移。由于隐式排序适用,因此对具有等效标签转移优先级的判断从连接节点上的 12 点钟位置开始,然后顺时针进行。第一个转移线段(标签为事件E_one)无效。下一个转移段(标签为事件E_two )有效。从状态A到状态C完成转移有效。
- 状态A退出操作 (exitA()) 执行并完成。
- 状态A标记为非活动状态。
- 状态C标记为活动状态。
- 状态C进入操作 (entC()) 执行并完成。
- 图表回到睡眠状态。
此序列完成与事件关联的此状态流图的执行。E_two
2.7.6解析同时有效的转移路径
什么是冲突转移?
冲突转移是在模拟过程中来自状态流图中同一源的两个同样有效的路径。在冲突的情况下,图表根据图表中的排序模式判断同样有效的转移:显式或隐式。
- 对于显式排序(默认模式),根据为每个转移指定的顺序对冲突转移进行判断。有关详细信息,请参阅显式排序。
- 对于 C 语言 图表中的隐式排序,根据隐式排序中描述的内部规则对冲突转移进行判断。
冲突转移示例
下面的图表有两个同样有效的转移路径:
隐式排序的冲突解决
对于隐式排序,图表以顺时针顺序计算多个具有相同标签优先级的出向转移,从状态上的十二点钟位置开始。在这种情况下,将发生从状态A到状态B的转移。
显式排序的冲突解决
对于显式排序,图表通过按您指定的显式顺序判断出向转移来解决冲突。例如,如果右键单击从状态A到状态C的转移,然后从上下文菜单中选择"执行顺序 > 1",则图表将首先判断该转移。在这种情况下,将发生从状态A到状态C的转移。
转移冲突是如何发生的
默认转移到状态A分配的数据a等于 1,数据b等于 10。状态A在during状态中,每个时间步长a的递增量和b的递减量。如果条件为[a > 4] true,从状态A到状态B的转移有效。如果条件为 [b < 7]true,从状态A到状态C的转移有效。在仿真期间,存在状态A处于活动状态且两个条件都为 true 的时间步长。此问题是转移冲突。
2.7.7从多个源转移到公共目标
此示例显示使用连接连接点从多个源对象到单个目标对象的转移行为。
最初,图表处于睡眠状态。状态A处于活动状态。事件E_one发生并唤醒图表,该图表通过层次结构从根向下处理事件:
- 图表根将检查 是否由于 E_one而产生有效的转移。有效的转移存在于从状态A到连接节点以及从连接节点到状态C。
- 状态A退出操作 (exitA()) 执行并完成。
- 状态A标记为非活动状态。
- 状态C标记为活动状态。
- 状态C进入操作 (entC()) 执行并完成。
- 图表回到睡眠状态。
此序列完成与事件E_one关联的此状态流图的执行。
2.7.8流程图中的回溯
此示例显示与在流程图中的转移和连接节点的强制回溯行为。图表使用出向转移的隐式排序(请参阅隐式排序)。
最初,状态A为活动状态,条件c1,c2 和c3为 true:
- 图表根检查是否有从状态A的有效转移。
存在一个有效的转移,该转移标有从状态A到连接节点的条件conditions c1
。
- 条件为 c1 true,执行条件操作a1。
- 条件为c3 true,执行条件操作a3。
- 条件c4不正确,控制流回溯到状态A。
- 图表根检查是否有另一个有效的转移从状态A。
存在一个有效的转移,该转移标有从状态A到连接节点的条件 c2
。
- 条件为c2 true,执行条件操作a2。
- 条件为 c3 true,执行条件操作a3。
- 条件c4不正确,控制流回溯到状态A。
- 图表进入睡眠状态。
前面的示例显示了执行操作a1和a2 的预期行为。另一个意外行为是执行操作a3两次。若要解决此问题,请考虑向终止的交汇点添加无条件转移。
终止交汇点允许流结束,如果c3或 c4不正确。此设计将状态 A 保持活动状态,而不需要执行不必要的操作。
2.8历史结点
历史结点表示 Stateflow® 图中的历史决策点。决策点基于与状态活动有关的历史数据。将历史结点置于父状态指示将使用历史状态活动信息来确定下一个要激活的状态。历史结点只会应用到层次结构中其所在的层级。
2.8.1历史结点示例
以下示例使用了一个历史结点:
父状态 Power_on
有一个历史结点并包含两个子状态。如果状态 Power_off
被激活且发生事件 switch_on
,则系统可以进入 Power_on.Low
或 Power_on.High
。第一次进入父状态 Power_on
时,会进入子状态 Power_on.Low
,因为它具有默认转移。在以后的某个时刻,如果状态 Power_on.High
被激活并且发生事件 switch_off
,则会退出父状态 Power_on
并激活状态 Power_off
。然后发生事件 switch_on
。由于 Power_on.High
是上一个激活子状态,因而它会被再次激活。在 Power_on
第一次被激活后,将由历史结点来确定是进入 Power_on.Low
还是 Power_on.High
。
请参阅Default Transition and a History Junction了解有关此表示法语义的详细信息。
2.8.2历史结点和内部转移
通过指定到历史结点的内部转移,您可以指定基于特定事件或条件,退出激活状态然后立即再次进入。
有关这种表示法的示例,请参阅Using an Inner Transition to a History Junction。
请参阅Inner Transition to a History Junction了解有关此表示法语义的详细信息。
https://ww2.mathworks.cn/help/stateflow/ug/history-junctions.html
最后
以上就是真实吐司为你收集整理的Sateflow学习知识点记录2 Stateflow语法的全部内容,希望文章能够帮你解决Sateflow学习知识点记录2 Stateflow语法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复