本页对应的英文页面已更新,但尚未翻译。 若要查看最新内容,请点击此处访问英文页面。

使用时序逻辑控制图的执行

时序逻辑通过时间控制 Stateflow 图的执行。在状态动作和转移中,可以使用两种类型的时序逻辑:基于事件和绝对时间。基于事件的时序逻辑会跟踪重复发生的事件。绝对时间时序逻辑会基于 Stateflow 图的仿真时间定义时间段。要对这些重复事件或仿真时间进行操作,可以使用称为时序逻辑运算符的内置函数。

时序逻辑运算符使用规则

  • 时序逻辑运算符只在以下各项中出现:

    • 状态动作

    • 来源于状态的转移

    • 来源于结点(当完整的转移路径连接两个状态时)的转移段

    注意

    此限制意味着您不能在默认转移或流程图转移中使用时序逻辑运算符。

    每个时序逻辑运算符都有一个关联状态,它是出现动作的状态或转移的来源状态。

  • 使用事件表示法来表示状态动作中基于事件的时序逻辑。请参阅基于事件的时序逻辑的表示法

  • 可以将任何显式或隐式事件用作时态运算符的基础事件。基础事件是指重复发生的事件,可使用时态运算符进行运算。

  • 对于没有输入事件的 Stateflow 图,可以使用 tickwakeup 事件表示图唤醒操作的隐式事件。

  • 使用关键字 secmsecusec,以秒、毫秒或微秒来定义自状态激活后已用的仿真时间。这些关键字只对状态动作以及来源于状态的转移有效。

    在以下情况下,请使用绝对时间时序逻辑,而不要使用隐式 tick 事件:

    • 用绝对时间时序逻辑表示的时滞独立于模型的采样时间。但是,tick 事件取决于采样时间。

    • 绝对时间时序逻辑适用于包含函数调用输入事件的 Stateflow 图。tick 事件不适用于包含函数调用输入的 Stateflow 图。

用于基于事件的时序逻辑的运算符

对于基于事件的时序逻辑,请使用下表所述的运算符。

运算符语法说明
after

after(n,E)

Eafter 运算符的基础事件;n 可以是:

  • 正整数

  • 计算结果为正整数值的表达式

如果基础事件 E 自关联状态激活后至少已发生 n 次,则返回 true。否则,运算符返回 false

在不包含输入事件的 Stateflow 图中,如果图自关联状态激活后已唤醒 n 次或更多次,after(n,tick)after(n,wakeup) 会返回 true

每次关联状态重新激活时,E 的计数器重置为 0。

at

at(n,E)

Eat 运算符的基础事件;n 可以是:

  • 正整数。

  • 计算结果为正整数值的表达式。

仅当基础事件 E 自关联状态激活后发生第 n 次时,才返回 true。否则,运算符返回 false

在不包含输入事件的 Stateflow 图中,如果 Stateflow 图自关联状态激活后已唤醒第 n 次,at(n,tick)at(n,wakeup) 将返回 true

每次关联状态重新激活时,E 的计数器重置为 0。

before

before(n,E)

Ebefore 运算符的基础事件;n 可以是:

  • 正整数。

  • 计算结果为正整数值的表达式。

如果基础事件 E 自关联状态激活后发生次数少于 n 次,则返回 true。否则,运算符返回 false

在不包含输入事件的 Stateflow 图中,如果 Stateflow 图自关联状态激活后唤醒次数少于 n 次,则 before(n,tick)before(n,wakeup) 会返回 true

每次关联状态重新激活时,E 的计数器重置为 0。

every

every(n,E)

Eevery 运算符的基础事件;n 可以是:

  • 正整数。

  • 计算结果为正整数值的表达式。

当基础事件 E 自关联状态激活后每发生 n 次时,返回 true。否则,运算符返回 false

在不包含输入事件的 Stateflow 图中,当图自关联状态激活后唤醒 n 的整数倍次数时,every(n,tick)every(n,wakeup) 会返回 true

每次关联状态重新激活时,E 的计数器重置为 0。

temporalCount

temporalCount(E)

EtemporalCount 运算符的基础事件。

自关联状态激活后,基础事件 E 每发生一次,值递增 1,并返回正整数。否则,运算符返回 0 值。

在没有输入事件的图中,temporalCount(tick)temporalCount(wakeup) 返回自激活关联状态以来图唤醒的次数。

每次关联状态重新激活时,E 的计数器重置为 0。

您可以使用引号将关键字 'tick''wakeup' 括起来。例如,after(5,'tick') 等效于 after(5,tick)

注意

时序逻辑运算符将阈值 n 与整数类型的内部计数器进行比较。如果 n 是一个定点数,且定义使用了不是 2 的整数幂的斜率,或使用了非零偏置,则比较时可能会由于舍入而产生意外的结果。有关详细信息,请参阅Relational Operations for Fixed-Point Data

基于事件的时序逻辑示例

以下示例说明了基于事件的时序逻辑在状态动作和转移中的使用。

运算符用法示例说明

after

状态动作 (on after)

on after(5,CLK): status('on');

从状态激活后开始 5 个时钟周期,每个 CLK 周期会出现一条状态消息。

after

转移

ROTATE[after(10,CLK)]

仅在广播 ROTATE 事件且状态激活 10 个 CLK 周期以后,才会发生转出关联状态的转移。

before

状态动作 (on before)

on before(MAX,CLK): temp++;

temp 变量在每个 CLK 周期递增一次,直到状态达到 MAX 限制。

before

转移

ROTATE[before(10,CLK)]

仅在广播 ROTATE 事件且在状态激活后的 10 个 CLK 个周期之内,才会发生转出关联状态的转移。

at

状态动作 (on at)

on at(10,CLK): status('on');

状态消息会在状态激活后的正好 10 个 CLK 周期时出现。

at

转移

ROTATE[at(10,CLK)]

仅在广播 ROTATE 事件且正好在状态激活后的 10 个 CLK 周期时,才会发生转出关联状态的转移。

every

状态动作 (on every)

on every(5,CLK): status('on');

状态激活后,每 5 个 CLK 周期会出现一条状态消息。

temporalCount

状态动作 (during)

du: y = mm[temporalCount(tick)];

此动作会对状态激活后的时钟时间进行计数并返回整数值。然后,该动作会为变量 y 赋予 mm 数组的值,该数组的索引是 temporalCount 运算符返回的值。

基于事件的时序逻辑的表示法

可以使用以下两种表示法之一来表示基于事件的时序逻辑。

事件表示法

使用事件表示法定义仅依赖基础事件的状态动作或转移条件。

事件表示法采用以下语法:

tlo(n,E)[C]

其中

  • tlo 是一个布尔时序逻辑运算符(afterbeforeatevery

  • n 是运算符的出现次数

  • E 是运算符的基础事件

  • C 是一个可选条件表达式

条件表示法

使用条件表示法定义依赖基础事件和非基础事件的转移条件。

条件表示法遵循以下语法:

E1[tlo(n,E2) && C]

其中

  • E1 是任意非基础事件

  • tlo 是一个布尔时序逻辑运算符(afterbeforeatevery

  • n 是运算符的出现次数

  • E2 是运算符的基础事件

  • C 是一个可选条件表达式

事件表示法和条件表示法示例

表示法用法示例说明

事件

状态动作 (on after)

on after(5,CLK): temp = WARM;

temp 变量自状态激活后的 5 个 CLK 周期后变为 WARM

事件

转移

after(10,CLK)[temp == COLD]

状态激活 10 个 CLK 周期之后,如果 temp 变量为 COLD,则会发生转出关联状态的转移。

条件

转移

ON[after(5,CLK) && temp == COLD]

仅在广播 ON 事件且在状态激活 5 个 CLK 周期以后并且 temp 变量为 COLD 时,才会发生转出关联状态的转移。

注意

在状态动作中必须使用事件表示法,因为状态动作的语法不支持条件表示法。

用于绝对时间时序逻辑的运算符

对于绝对时间时序逻辑,请使用下表中所述的运算符。

运算符语法说明
after

after(n,sec)

after(n,msec)

after(n,usec)

n 是任意正数或表达式。secmsecusec 是表示自关联状态激活后已用仿真时间的关键字。

如果自关联状态激活以来已历时 n 个仿真时间单位,则返回 true。否则,运算符返回 false。指定仿真时间,单位为秒 (sec)、毫秒 (msec) 或微秒 (usec)。

每次关联状态重新激活时,secmsecusec 的计数器重置为 0。

before

before(n,sec)

before(n,msec)

before(n,usec)

n 是任意正数或表达式。secmsecusec 是表示自关联状态激活后已用仿真时间的关键字。

如果自关联状态激活以来历时少于 n 个仿真时间单位,则返回 true。否则,运算符返回 false。指定仿真时间,单位为秒 (sec)、毫秒 (msec) 或微秒 (usec)。

每次关联状态重新激活时,secmsecusec 的计数器重置为 0。

every

every(n,sec)

every(n,msec)

every(n,usec)

n 是任意正数或表达式。secmsecusec 是表示自关联状态激活后已用仿真时间的关键字。

自激活关联状态以来,每历时 n 个仿真时间单位就返回 true。否则,运算符返回 false。指定仿真时间,单位为秒 (sec)、毫秒 (msec) 或微秒 (usec)。

每次关联状态重新激活时,secmsecusec 的计数器重置为 0。

只有可作为 MATLAB® 对象执行的独立图才支持将 every 用作绝对时间时序逻辑运算符。

temporalCount

temporalCount(sec)

temporalCount(msec)

temporalCount(usec)

secmsecusec 是表示自关联状态激活后已用仿真时间的关键字。

计算并返回自关联状态激活后已用的仿真时间,以指定的秒数 (sec)、毫秒数 (msec) 或微秒数 (usec) 表示。

每次关联状态重新激活时,secmsecusec 的计数器重置为 0。

elapsed

elapsed(sec)

等效于 temporalCount(sec)。返回自关联状态激活后已用的仿真时间,以秒 (sec) 表示。

每次关联状态重新激活时,sec 的计数器重置为 0。

count

count(C)

在条件表达式 C 变为 true 后返回时钟时间计数。如果条件表达式变为 false,则 count 运算符会重置。如果 count 运算符用于状态中,则当进入包含该运算符的状态时,该运算符会重置。如果 count 运算符用在转移中,则当进入该转移的来源状态后,该运算符重置。

在 Simulink® 模型中,count 的值取决于步长大小。更改模型的求解器或步长大小会影响包含 count 运算符的 Stateflow® 图的结果。

duration

duration(C)

在条件表达式 C 变为 true 后返回秒数。如果条件表达式变为 false,则 duration 运算符会重置。如果 duration 运算符用于状态中,则当进入包含该运算符的状态时,该运算符会重置。如果 duration 运算符用在转移中,则当进入该转移的来源状态后,该运算符重置。

您可以使用引号将关键字 'sec''msec''usec' 括起来。例如,after(5,'sec') 等效于 after(5,sec)

注意

时序逻辑运算符将阈值 n 与整数类型的内部计数器进行比较。如果 n 是通过使用不作为 2 的整数幂的斜率或非零偏置定义的定点数,则由于舍入,比较可能会产生意外的结果。有关详细信息,请参阅Relational Operations for Fixed-Point Data

绝对时间时序逻辑示例

下面的示例说明了绝对时间时序逻辑在状态动作和转移中的运用。

运算符用法示例说明

after

状态动作 (on after)

on after(12.3,sec): temp = LOW;

自状态激活并执行 12.3 秒的仿真后,temp 变量变为 LOW

after

转移

after(8,msec)

自状态激活并执行 8 毫秒的仿真后,会发生转出关联状态的转移。

after

转移

after(5,usec)

自状态激活并执行 5 微秒的仿真后,会发生转出关联状态的转移。

before

转移

[temp > 75 && before(12.34,sec)]

如果变量 temp 超过 75,并且自状态激活后所经过的时间不到 12.34 秒,则会发生转出关联状态的转移。

temporalCount

状态动作 (exit)

exit: y = temporalCount(sec);

此动作对状态激活和反激活之间所经过的仿真时间进行计数并返回秒数。

定义时滞的示例

以下连续时间图定义了转移中的两个绝对时滞。

图执行包括以下步骤:

  • 当图唤醒时,状态 Input 先激活。

  • 仿真执行 5.33 毫秒后,会发生从 InputOutput 的转移。

  • 状态 Input 反激活,然后状态 Output 激活。

  • 仿真执行 10.5 秒后,会发生从 OutputInput 的转移。

  • 状态 Output 反激活,然后状态 Input 激活。

  • 在仿真结束之前,会重复步骤 2 到 5。

如果 Stateflow 图具有离散采样时间,则该图中的任何动作都会在该采样时间的整数倍时发生。例如,假设您更改配置参数,以便 Simulink® 求解器使用大小为 0.1 秒的固定步长。然后,从状态 Input 到状态 Output 的第一次转移发生在 t = 0.1 秒。发生此行为的原因在于求解器不会在正好 t = 5.33 毫秒时唤醒图。在这种情况下,求解器会在 0.1 秒的整数倍时唤醒图,例如 t = 0.0 秒和 0.1 秒时。

检测已用时间示例

在下面的模型中,Step 模块为图提供了一个单位阶跃输入。

图决定输入 u 何时等于 1:

  • 如果输入在 t = 2 秒之前等于 1,则发生从 StartFast 的转移。

  • 如果输入在 t = 2 秒和 t = 5 秒之间等于 1,则发生从 StartGood 的转移。

  • 如果输入在 t = 5 秒后等于 1,则发生从 StartSlow 的转移。

使能子系统中绝对时间时序逻辑的示例

您可以在位于条件执行子系统的 Stateflow 图中使用绝对时间时序逻辑。当该子系统被禁用时,该 Stateflow 图变为非活动图,当该 Stateflow 图处于休眠状态时,时序逻辑运算符会暂停。在重新启用该子系统并且该图唤醒前,该运算符不会继续对仿真时间进行计数。

此模型具有一个使能子系统,其 States when enabling 参数设置为 held

该子系统包含一个使用 after 运算符的 Stateflow 图。

Signal Builder 模块提供具有以下特征的输入信号:

  • 信号在 t = 0 时激活子系统。

  • 信号在 t = 2 时禁用子系统。

  • 信号在 t = 6 时重新激活子系统。

下图显示在激活状态(AB)下所经过的总时间。

当输入信号在时间 t = 0 激活子系统时,状态 A 将激活或变为启用状态。当状态激活时,所经过的时间会增加。但是,当子系统在时间 t = 2 被禁用时,Stateflow 图会进入休眠状态,状态 A 变为非激活。

对于 2 < t < 6 的情况,使能子系统中的状态所经过的时间会停在 2 秒处,因为没有任何状态处于激活状态。当 Stateflow 图在 t = 6 唤醒时,状态 A 再次变为激活,所经过的时间开始增加。从状态 A 到状态 B 的转移取决于状态 A 处于启用状态时所经过的时间,而不是取决于仿真时间。因此,状态 A 会保持激活,直到 t = 9,以使得该状态下所经过的时间总计为 5 秒。

当在 t = 9 时发生从 AB 的转移时,输出值 y 从 0 变为 1。

此模型行为只适用于 Enable 模块参数 States when enabling 设为 held 的子系统。如果该参数设为 reset,则当重新激活子系统时,Stateflow 图会完全重新初始化。换句话说,会执行默认转移,所有时序逻辑计数器都重置为 0。

这些语义也适用于 before 运算符。

绝对时间时序逻辑最佳实践

使用 after 运算符替换 at 运算符

如果将 at 运算符用于绝对时间时序逻辑,则在尝试进行模型仿真时会出现错误消息。请改用 after 运算符的外部自环转移。

假设您想使用转移 at(5.33, sec) 定义时滞。

将转移更改为 after(5.33, sec),如此图所示。

使用带有 after 运算符的外部自环转移替换 every 运算符

在 Stateflow 模型中,如果您将 every 运算符用于绝对时间时序逻辑,则在尝试进行模型仿真时会出现错误消息。请改用带有 after 运算符的外部自环转移。

假设您想要在 Stateflow 图执行期间每 2.5 秒为某个激活状态打印一条状态消息,如 Check_status 状态动作中所示。

将状态动作替换为外部自环转移,如下图所示。

同时,在状态中添加一个历史结点,以使 Stateflow 图在每次自环转移之前记住状态设置。请参阅Record State Activity by Using History Junctions

使用带离散采样时间的 Stateflow 图实现更加高效的代码生成

若离散图不在触发子系统或使能子系统内,则生成代码时使用整数计数器来跟踪时间,而不是使用 Simulink 提供的时间。从管理开销和内存方面来看,这一点可以实现更加高效的代码生成,而且可以让此代码用在软件在环 (SIL) 和处理器在环 (PIL) 仿真模式中。有关详细信息,请参阅SIL and PIL Simulations (Embedded Coder)。

另请参阅

| | | | | | |

相关主题