Simulink 子系统语义
这组示例说明不同类型的 Simulink® 子系统,以及对这些子系统进行仿真时使用的语义。每个示例都提供了对模型的描述以及控制模型执行方式的诀窍。
示例是针对子系统类型提供的。
虚拟和非虚拟子系统
函数调用子系统
触发子系统
使能子系统
使能触发子系统
If Action 子系统和 Switch Case 执行子系统
While Iterator 子系统
For Each 子系统
For Iterator subsystems
打开模型。
open('SimulinkSubsystemSemantics.prj'); open_system('sl_subsys_semantics');
虚拟和非虚拟子系统概览
Simulink 软件有两类子系统。
虚拟子系统提供模型中的图形层次结构。虚拟子系统不影响模型执行。在模型执行期间,Simulink 引擎会扁平化所有虚拟子系统。
非虚拟子系统提供模型中的执行和图形层次结构。非虚拟子系统作为一个单元执行,称为原子执行。所有非虚拟子系统在 Simulink 画布中以粗边框显示。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/Virtual and nonvirtual subsystem overview');
要创建非虚拟子系统,请右键点击 Subsystem 模块并选择模块参数(子系统)。在“模块参数”对话框中,选择视为原子单元并点击应用。
虚拟子系统呈现的是扁平执行列表,而非虚拟子系统包括执行层次结构。要显示执行顺序,请在 Simulink 编辑器的调试选项卡上,选择叠加信息,然后点击执行顺序。
出现在 Simulink 画布上的执行顺序模块列表显示执行顺序。
“执行顺序模块列表”显示非虚拟子系统 Subsystem2
作为一个单元执行。
非虚拟子系统会在执行层次结构中导致代数环。更新图时,软件会发出存在代数环的警告。
set_param(gcs,'SimulationCommand','Update')
Warning: Model 'sl_subsys_overview' contains 1 algebraic loops.
函数调用子系统
Function-Call Subsystem 模块包含一个条件执行子系统,在每次控制端口接收到函数调用事件时,该子系统都会运行。函数调用子系统使用 Simulink 模块实现可调用的函数。Stateflow® Chart (Stateflow)、Function-Call Generator 模块、MATLAB Function 模块、S-Function 模块或 Hit Crossing 模块可以提供函数调用事件。
有关详细信息,请参阅Function-Call Subsystem。
这些示例说明函数调用子系统的有效和无效使用。
close_system('sl_subsys_overview',0) open_system('s_Function_call_subsystems')
嵌套函数调用
在此模型中,Chart 模块是执行函数 [d1,d2]=f()
的函数调用发起方。函数 f
又执行函数 g
。在调用 f
和 g
后,图使用由 f
和 g
计算的值 d1
和 d2
。
open_system('sl_subsys_fcncall1')
close_system('sl_subsys_fcncall1')
具有数据共享的嵌套函数调用
Chart 模块执行函数 [d1,d2]=f()
,f
又执行 g
。在调用 f
后,Chart 模块使用由 f
和 g
计算的值 d1
和 d2
。函数 f
和 g
通过信号 s(f/Out2 feeds g/In1)
共享数据。Simulink 将信号 s
视为数据存储。
open_system ('sl_subsys_fcncall2')
通常,函数调用子系统的输入必须在函数调用发起方(Chart 模块)之前执行,除非信号来自共同的函数调用发起方执行的模块。在此示例中,f()
是 g()
的函数调用发起方。但是,Chart 模块是 f()
的函数调用发起方,这使得 Chart 模块成为 f()
和 g()
的共同的函数调用发起方。
从这个意义上说,以下信号 s
可以被视为数据存储,f()
和 g()
可以按照 Chart 模块定义的任何给定顺序在该数据存储中读取和写入数据。
close_system('sl_subsys_fcncall2')
具有共同发起方的两个函数调用子系统之间的数据共享
在此模型中,d1
和 d2
是分别使用 g()
和 f()
计算的。Chart 模块使用 d1
和 d2
作为输入,并调用 g()
和 f()
。函数 f
和 g
通过信号 s
共享数据,换句话说,(f/Out1)
馈送 (g/In1)
。该模型将信号 s
视为数据存储。
open_system ('sl_subsys_fcncall3')
通常,函数调用子系统的输入必须在函数调用发起方(Chart 模块)之前执行,除非信号来自共同的函数调用发起方执行的模块。在此示例中,Chart 模块是 f()
和 g()
的共同的函数调用发起方。因此,可以将信号 s
视为数据存储。
close_system('sl_subsys_fcncall3')
包含具有数据共享的函数调用发起方的使能子系统
此使能子系统包含调用函数 f()
和 g()
的 Stateflow 图。模型 sl_subsys_fcncall4
中的使能子系统是 f()
和 g()
的共同的函数调用发起方,因此软件将信号 s
视为数据存储。
open_system ('sl_subsys_fcncall4')
close_system('sl_subsys_fcncall4')
具有 Merge 模块的函数调用子系统
此模型包含一个 Chart 模块,该模块执行两个函数调用。该模型使用 Merge 模块将多个信号映射到单个内存位置。信号 f/d1_out
和 g/d1_out
被合并到单个内存位置并作为 d1
反馈到 Chart 模块。信号 f/k_out
和 g/k_out
被合并到单个内存位置并反馈回 f/k_in
。通过将信号合并到单个内存位置并将它们反馈会 Chart 模块中,使 Chart 模块能够就如何计算值作出复杂的决定。
open_system ('sl_subsys_fcncall5')
close_system('sl_subsys_fcncall5')
函数调用子系统的多个发起方
此函数调用子系统由两个不同函数调用发起方 Chart1
和 Chart2
调用。Chart1/out1
和 Chart2/d1
之间的数据连接保证 Chart1
在 Chart2
之前执行。创建具有多个调用方的函数调用子系统时请务必小心。
例如,如果您删除 Chart1
和 Chart2
之间的数据连接,则您需要为 Chart1
和 Chart2
添加优先级以指定这些模块的相对执行顺序。否则会导致执行顺序具有多义性。
但是,软件不会对这种情况报错,因为这种情况可能对特定情形有效。例如,如果您从 f()
中删除所有状态,并删除连接 Chart1/out1
和 Chart2/d1
的线,则 Chart1
和 Chart2
的执行顺序并不重要。
open_system ('sl_subsys_fcncall6')
close_system('sl_subsys_fcncall6')
包含指定重置行为的函数调用子系统的使能子系统
此使能子系统包含两个函数调用子系统。左侧的函数调用子系统配置为在启用时保留其状态值,在禁用时保留其输出值。右侧的函数调用子系统配置为在启用时重置其状态值,在禁用时重置其输出值。
open_system ('sl_subsys_fcncall7')
close_system('sl_subsys_fcncall7')
函数调用子系统指定周期性执行
此 Stateflow 图调度模型中各函数调用子系统的执行顺序。然而,函数调用子系统在每个时间步只执行一次。函数调用不指定条件执行,而是控制子系统执行的相对顺序。当使用数据存储在子系统之间传输数据时,此设置非常有用,因为它可确保数据存储的正确读写序列。由于函数调用子系统旨在无条件执行,您应使用子系统中 Trigger 模块的采样时间参数指定其周期性采样时间。因此,在仿真期间,Simulink 引擎会验证周期函数调用子系统是否在每个时间步内严格执行一次。
此外,当生成代码时,函数调用子系统内部的历时由字面值(指定的固定采样时间)表示,而不是像函数调用子系统的标准那样由计时器维护和计算。因此,生成的代码效率明显更高。
要查看子系统的采样时间,请在 Simulink 编辑器中的调试选项卡上,选择信息 覆盖,然后点击颜色。
open_system ('sl_subsys_fcncall8')
函数调用子系统的采样时间颜色是红色而不是青色,这表明采样时间是周期性的而不是触发采样时间。如果函数调用连接互换,由于子系统中 Data Store Read 和 Data Store Write 模块之间的交互发生变化,结果会延迟一个时间步。
close_system('sl_subsys_fcncall8')
函数调用发起方发出激活和非激活事件
此 Stateflow 图指定将事件 activate
绑定到状态 ON
。当状态 ON
转移为激活时,由该事件启动的函数调用子系统 Integrate
被启用。此外,当状态转移为非激活时,由该事件启动的函数调用子系统被禁用。如果函数调用子系统配置为在启用时重置状态或在禁用时重置输出,则会发生此类动作。在此示例中,子系统分别在启用和禁用时重置其状态和输出。
open_system ('sl_subsys_fcncall9')
close_system('sl_subsys_fcncall9')
解释函数调用子系统的输出
1) 函数调用的返回值是从函数调用子系统的输出到其函数调用发起方的直接连接。例如,以下 Stateflow 图 Chart1
是执行函数 d1=f1()
的函数调用发起方。在调用 f1
后,该图使用由 f1
在同一时间步内计算的返回值 d1
。
2) 在第二个示例中,Unit Delay 模块的执行不是由 Chart2
触发的。因此,在执行 Chart2
期间,信号 d2
保持其来自调用 Unit Delay 的前一时间步的值。
open_system ('sl_subsys_fcncall10')
close_system('sl_subsys_fcncall10')
函数调用信号的分支
此 Stateflow 图在其输入信号 u
为 1 的时间间隔内启动周期为 1 的周期函数调用信号。对于每个函数调用,子系统的执行顺序依次是 f
、h
、g
。此执行顺序是在 Function-Call Split 模块上指定的顺序的结果,其中用点注释的端口先执行。
将此模型导出为 R2015b 之前的版本会导致错误,因为信号 b
被视为数据依存关系违规。
open_system ('sl_subsys_fcncall11')
此 Stateflow 图在其输入信号 u
为 1 的时间间隔内启动周期为 1 的周期函数调用信号。
对于每个函数调用,子系统 f1
在子系统 g1
之前执行。此执行顺序是在 Function-Call Split 模块上指定的顺序的结果,其中用点注释的端口先执行。
将此模型导出为 R2015b 之前的版本会导致错误,因为当子系统 f1
的 Inport 模块上的针对函数调用子系统输出的反馈信号锁存输入参数处于清除状态时,信号 b
被视为数据依存关系违规。
close_system('sl_subsys_fcncall11')
非法的函数调用子系统
此列表标识列出的非法函数调用子系统。在对应的模型子系统中解释了这些修复。
open_system('s_Function_call_subsystems')
具有多义性的执行顺序错误
涉及由函数调用发起方驱动的模块的数据依存关系违规
涉及两个函数调用子系统之间的模块的数据依存关系违规
由于修改函数调用输出的反馈而导致的多义性执行顺序错误
由于两个子系统之间修改了函数调用输出的反馈而导致多义性执行顺序错误
涉及 Merge 模块和 Stateflow 图的数据依存关系违规
涉及原子子系统和 Gain 模块的数据依存关系违规
函数调用子系统循环数据依存关系违规
间接数据依存关系违规
嵌套数据依存关系违规
函数调用子系统不正确地指定周期性执行
在调用的上下文中计算的函数调用子系统输入
涉及分支函数调用信号和连接函数调用子系统的模块的数据依存关系违规
close_system('s_Function_call_subsystems',0)
If Action 子系统和 Switch Case 执行子系统
当逻辑条件为 true 时,If Action 子系统在每个时间步执行。当一个信号具有一组指定的值之一时,Switch Case 执行子系统会执行。
有关详细信息,请参阅 If Action Subsystem 和 Switch Case Action Subsystem。
以下示例说明了如何使用 If Action 子系统和 Switch Case 执行子系统。
open_system('sl_subsys_semantics') open_system('sl_subsys_semantics/If Action and Switch Case Action subsystems')
close_system('sl_subsys_semantics/If Action and Switch Case Action subsystems')
触发子系统
触发子系统使您能够实现软件触发、硬件触发或两者的组合。您可以从 Simulink 库浏览器添加 Triggered Subsystem 模块。您也可以通过将 Trigger 模块放在 Subsystem 模块中来创建此子系统。
有关详细信息,请参阅Triggered Subsystem。
以下示例说明了如何使用触发子系统。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/Triggered subsystems')
软件触发在以下代码中定义:
if (trigger_signal_edge_detected) {
out(t) = f(in(t));
}
硬件触发在以下代码中定义:
if (trigger_signal_edge_detected) {
out(t) = f(in(t-h)); // h == last step size
}
触发子系统的每个输入端口配置输入是否应锁存。锁存输入为该输入端口提供硬件触发语义。软件用符号 <L>
标记锁存的输入端口。
close_system('sl_subsys_semantics/Triggered subsystems')
使能子系统
使能子系统允许您创建条件执行子系统,这些子系统仅在使能信号大于零时执行。使能子系统使您能够控制输出信号的初始值以及每次启用子系统时是否重置状态。
您可以从 Simulink 库浏览器添加 Enabled Subsystem 模块。您也可以通过将 Enable 模块放在 Subsystem 模块中来创建此子系统。
有关详细信息,请参阅Enabled Subsystem。
以下示例说明如何使用使能子系统。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/Enabled subsystems')
close_system('sl_subsys_semantics/Enabled subsystems')
Enabled and Triggered Subsystem
以下这些子系统说明了状态和输出端口重置的选项。当使能和触发条件都发生时,使能触发子系统会执行。
您可以从 Simulink 库浏览器添加 Enabled and Triggered Subsystem 模块。您也可以通过将 Enable 模块和 Trigger 模块放在一个 Subsystem 模块中来创建此子系统。
有关详细信息,请参阅Enabled and Triggered Subsystem。
此示例说明如何使用使能触发子系统。
open_system('sl_subsys_semantics') open_system('sl_subsys_enabtrig1.slx')
close_system('sl_subsys_enabtrig1.slx')
可重置子系统
可重置子系统允许您根据重置信号重置子系统内模块的状态。您可以从 Simulink 库浏览器添加 Resettable Subsystem 模块。
有关详细信息,请参阅Resettable Subsystem。
这些示例说明如何使用可重置子系统。
open_system('sl_subsys_semantics') open_system('sl_subsys_semantics/Resettable subsystems')
close_system('sl_subsys_semantics/Resettable subsystems')
For Each 子系统
For Each 子系统在一个仿真时间步内对输入信号或封装参数数组的每个元素或子数组重复执行。您可以从 Simulink 库浏览器中添加 For Each Subsystem 模块。您也可以通过在 Subsystem 模块中放置 For Each 模块来创建此模块。For Each 子系统对输入信号的单个元素或子数组重复该算法。For Each 子系统为子系统处理的每个元素或子数组保持单独的模块状态。
有关详细信息,请参阅 For Each Subsystem。
这些示例说明如何使用 For Each 子系统。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/For Each subsystems')
close_system('sl_subsys_semantics/For Each subsystems')
While Iterator 子系统
当逻辑条件为 true
时,While Iterator 子系统会在一个仿真时间步中重复执行。您可以从 Simulink 库浏览器添加 While Iterator Subsystem 模块。您也可以通过在 Subsystem 模块中放置 While Iterator 模块来创建此子系统。While Iterator 子系统在每个模型时间步上运行多次迭代。迭代次数由 while 迭代器条件控制。
While Iterator 子系统类似于函数调用子系统,因为它可以在给定时间步内运行任意次数的迭代。
While Iterator 子系统与函数调用子系统的不同之处在于它不包含单独的发起方,如 Stateflow 图。此外,While Iterator 子系统可以访问 While Iterator 模块选择生成的当前迭代编号。
有关详细信息,请参阅 While Iterator Subsystem。
这些示例说明如何使用 While Iterator 子系统。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/While Iterator subsystems')
close_system('sl_subsys_semantics/While Iterator subsystems')
For Iterator 子系统
For Iterator 子系统在一个仿真时间步内重复执行指定的迭代次数。您可以从 Simulink 库浏览器添加 For Iterator Subsystem 模块。您也可以通过在 Subsystem 模块中放置 For Iterator 模块来创建此子系统。For Iterator 子系统在每个模型时间步上运行固定次数的迭代。迭代次数可以是 For Iterator 子系统的外部输入,也可以在 For Iterator 模块内部指定。
For Iterator 子系统与 While Iterator 子系统非常相似,但前者在任一给定时间步上的迭代次数是固定的。
有关详细信息,请参阅 For Iterator Subsystem。
以下示例说明如何使用 For Iterator 子系统。
open_system('sl_subsys_semantics'); open_system('sl_subsys_semantics/For Iterator subsystems')
close_system('sl_subsys_semantics/For Iterator subsystems')