你可以看看Simulink万博1manbetx®引擎与s -函数的交互有两个方面:
过程的角度,即在模拟中引擎调用s函数的点。
数据透视,即发动机和s函数在模拟过程中如何交换信息。
下图显示了Simulink引擎在s函数中调用回调方法的顺序。万博1manbetx实心矩形表示总是在模型初始化期间或在每个时间步骤中发生的回调。虚线矩形表示在初始化和/或在模拟循环的某些或所有时间步骤中可能发生的回调。请参阅每个回调方法的文档,以确定引擎调用回调的确切环境。
请注意
流程视图图表示包含连续和离散状态的s函数的执行,支持过零检测,并驻留在使用可变步长求解器的模型中。不同的求解器省略了图中的某些步骤。为了更好地理解Simulink引擎如何执行特定的s -函数,请使用Simul万博1manbetxink调试器运行包含s -函数的模型。有关更多信息,请参见调试器介绍.
在下面的模型初始化循环中,Simulink引擎为即将到来的模拟配置s函数。万博1manbetx引擎总是执行所需的调用mdlInitializeSizes
而且mdlInitializeSampleTime
建立s函数的基本属性,包括输入输出端口、s函数对话框参数、工作向量、采样次数等。
引擎根据需要调用额外的方法来完成s函数的初始化。例如,如果s函数使用工作向量,则引擎调用mdlSetWorkWidths
.此外,如果mdlInitializeSizes
方法延迟设置输入和输出端口属性时,引擎调用完成端口初始化所需的任何方法,例如mdlSetInputPortWidth
,在信号传播时。的mdlStart
方法调用mdlCheckParameters
而且mdlProcessParameters
方法,如果s函数使用对话框参数。
请注意
的mdlInitializeSizes
当你在s函数块参数对话框中输入一个编译过的s函数的名称时,回调方法也会运行。
初始化后,Simulink引擎执行以下模拟循环。万博1manbetx如果模拟循环中断,无论是手动还是错误发生时,引擎直接跳转到mdlTerminate
方法。如果手动停止模拟,则引擎在调用之前首先完成当前时间步骤mdlTerminate
.
如果您的模型在模型层次结构的给定级别上包含多个S-Function块,那么引擎在处理下一个方法之前会为每个S-Function调用一个特定的方法。例如,引擎调用所有的mdlInitializeSizes
方法,然后调用mdlInitializeSampleTimes
方法。引擎使用块排序顺序来确定执行s函数的顺序。要了解引擎如何决定块执行顺序的更多信息,请参见控制和显示执行顺序.
如果你使用万博1manbetx仿真软件编码器™如果Simulink引擎不能为包含s -函数的模型生成代码,则不会执行上面概述的整个调用序列。万博1manbetx初始化继续进行,直到引擎到达mdlStart
方法。然后,引擎调用如下图所示的s函数方法,其中mdlRTW
方法是惟一的万博1manbetx仿真软件编码器产品。
如果s -函数驻留在一个有条件执行的子系统中,则生成的代码可以穿插调用mdlInitializeConditions
而且mdlStart
.考虑下面的Simulink模型。万博1manbetx
该模型包含两个nonvirtual子系统,名为Reset的有条件执行的启用子系统和名为atomic的原子子系统。每个子系统包含一个调用s函数的S-Function块dsfunc.c
,该模型模拟了一个具有两种状态的离散状态空间系统。使能的子系统复位功能在子系统启用时复位状态值,在子系统禁用时复位输出值。
使用通用实时(GRT)目标,生成模型范围的代码开始
函数调用开始
在调用模型范围之前,先获取两个子系统的函数MdlInitialize
函数,如下代码所示:
void MdlStart(void) {/* snip */ /*启动已启用的子系统:'/Reset' */ sfcndemo_enablesub_Reset_Start();/* Start for SubSystem: ' /Reset' */ /* Start for atomic SubSystem: ' / atomic ' */ sfcndemo_enablesub_Atomic_Start();/* end of Start for SubSystem: ' /Atomic' */ MdlInitialize();
的开始
函数调用子系统的InitializeConditions
功能:
void sfcndemo_enablesub_Reset_Start(void) {sfcndemo_enablesub_Reset_Init();/*剪切*/}
的MdlInitialize
函数,在MdlStart
的调用InitializeConditions
原子子系统的函数:
void MdlInitialize(void){/*初始化条件为原子子系统:'<根>/原子' */ sfcndemo_enablesub_Atomic_Init();}
因此,模型范围开始
函数交叉调用开始
而且InitializeConditions
两个子系统的函数和它们包含的s函数。
有关的更多信息万博1manbetx仿真软件编码器product和它如何与s函数相互作用,见s -函数和代码生成(万博1manbetx仿真软件编码器).
在外部模式下运行Simulink模型时,s函数万博1manbetx例程的调用顺序如下图所示。
引擎在呼叫mdlRTW
当它进入外部模式时一次,每次参数改变或单击时再次更新模型在建模选项卡。
请注意
看到外部模式通信(万博1manbetx仿真软件编码器)用于在外部模式下运行的要求。
s函数块具有输入和输出信号、参数和内部状态,以及其他一般工作区域。通常,块输入和输出写入和读取一个块I/O向量。输入也可以来自
外部输入通过根输入块
接地:输入信号未连接或接地
块输出也可以通过根Outport块转到外部输出。除了输入输出信号外,s函数还可以有
持续的状态
离散状态
其他工作领域,如实数、整数或指针工作向量
您可以通过使用s功能块参数对话框将参数传递给它们来参数化s功能块。
下图显示了这些不同类型数据之间的一般映射。
一个函数的mdlInitializeSizes
例程设置各种信号和向量的大小。在模拟循环期间调用的s函数方法可以确定信号的大小和值。
s函数方法可以通过两种方式访问输入信号:
通过指针
使用连续输入
在模拟循环过程中,使用访问输入信号
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,portIndex)
这将为带索引的输入端口返回指针数组portIndex
,在那里portIndex
从0开始。每个输入端口都有一个指针数组。要访问此数组的元素,必须使用
* uPtrs(元素)
下图描述了如何访问一个有两个输入的s函数的输入信号。
如上图所示,输入数组指针可以指向内存中不连续的位置。
您可以使用此代码检索输出信号。
real_T *y = ssGetOutputPortSignal(S,outputPortIndex);
一个函数的mdlInitializeSizes
方法可以指定其输入信号的元素必须占用连续的内存区域,使用ssSetInputPortRequiredContiguous
.如果输入是连续的,则可以使用其他方法ssGetInputPortSignal
访问输入。
本节介绍如何访问特定端口的所有输入信号,并将其写入输出端口。上图显示,指针的输入数组可以指向块I/O向量中的不连续项。特定端口的输出信号形成一个连续的矢量。因此,访问输入元素并将它们写入输出元素的正确方法(假设输入和输出端口具有相同的宽度)是使用这段代码。
int_T元素;int_T porttwidth = ssgetinputporttwidth (S,inputPortIndex);InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,inputPortIndex);real_T *y = ssGetOutputPortSignal(S,outputPortIdx);(元素= 0;元素< portWidth;{y[element] = *uPtrs[element];}
一个常见的错误是试图通过指针算术访问输入信号。例如,如果你要放置
real_T *u = *uPtrs;/*错误*/
就在初始化的下面uPtrs
并将上述循环的内部部分替换为
*y++ = *u++;/*错误*/
代码可以编译,但是MEX文件可能会使Simulink软件崩溃。万博1manbetx这是因为有可能访问无效内存(这取决于您如何构建模型)。当不正确地访问输入信号时,当进入s函数块的信号不是连续的时,就会发生崩溃。不连续信号数据发生在信号通过虚拟连接块(如Mux或Selector块)时。
为了验证您的s函数正确地访问宽输入信号,将一个复制信号传递到您的s函数的每个输入端口。为此,创建一个Mux块,其输入端口的数量等于进入s函数的所需信号的宽度。然后将驱动源连接到各个s函数输入端口,如下图所示。最后,使用这个输入信号运行s函数,以验证它不会崩溃并产生预期的结果。
二级MATLAB s函数|s函数生成器|功能|MATLAB函数