用于多速率多任务环境的s -函数
关于用于多速率多任务环境的S-Functions
s函数可用于具有多个采样率的模型,并可部署在多任务目标环境中。同样,s函数本身也可以有多个运行速率。代码生成器使用称为。的方法为多速率多任务模型生成代码率分组。在为基于ert的目标生成的代码中,速率分组生成单独的模型
_step
模型中基本速率任务和每个子速率任务的函数。尽管速率分组是仅在ERT目标中发现的代码生成特性,但是s -函数在编写代码时可以在其他上下文中使用它,如下所述。
S-Functions中的速金宝app率分组支持
要利用速率分组,如果还没有内联多速率s函数,则必须这样做。您需要遵循特定的目标语言编译器协议来利用速率分组。对TLC进行编码以利用速率分组并不妨碍内联s函数在GRT中正常工作。同样,即使您不使内联s -函数符合速率分组,它们仍然会生成有效的ERT代码。但是,如果您这样做,它们将为多速率模型生成更有效的代码。
有关目标语言编译器代码的说明和示例,说明如何创建和升级s函数以生成符合速率分组的代码,请参见速率分组遵从性和兼容性问题(嵌入式编码)。
对于每个不符合速率分组的多速率s函数,代码生成器在构建时发出以下警告:
警告:Simuli金宝appnk编码器:多速率块'/S-Function'的输出函数代码由样本命中率检查保护,而不是被速率分组。这将为块使用的所有速率生成相同的代码,可能会生成死代码。为了避免死代码,必须更新块的TLC文件。
你还会在为每个不兼容的s函数生成的代码中发现如下注释:
/*由于multirate块/S-Function的输出函数不是速率分组,下面的代码可能包含不可达的代码块。为了避免这种情况,您必须更新块TLC文件。* /
在这些警告中,单词“更新函数”取代了“输出函数”。
创建多任务,多速率,基于端口的采样时间s函数
下面的说明说明了如何在多速率s函数中支持数据确定性和数据完整性。金宝app它们不包括不存在决定论和完整性的情况。金宝app支持基于帧的处理不会影响需求。
请注意
慢速率必须是最快速率的倍数。当连接的两个速率不是倍数或速率不是周期性时,这些指令不适用。
正确处理快到慢转换的规则
对于输入,多速率s函数应该遵守的规则是
应该只以与输入端口采样时间相关联的速率读取输入。
通常,将输入数据写入
DWork
,和DWork
然后可以以较慢的(下游)速率访问。
可以在输入速率的每个采样点读取输入并写入DWork
记忆,但是这个DWork
内存不能被较慢的速率直接访问。DWork
将以慢速读取的内存必须仅在有特殊样本命中。当这个输入端口速率和它所连接的速率都有一个命中时,就会发生一个特殊的样本命中。根据它们的要求和设计,算法可以在多个位置处理数据。
对于输出,多速率s函数应该遵守的规则是
输出不应该由分配给输出端口的速率以外的速率写入,除非在下面描述的优化情况下。
当输出端口的采样率达到时,应该始终写入输出。
如果满足这些条件,S-Function块可以指定输入端口和输出端口都可以是本地的和可重用的。
当只需要对数据进行少量处理或不需要对数据进行处理时,可以包含优化。在这种情况下,当有一个特殊的样本命中时,输入率代码可以直接写入输出(而不是使用DWork)。但是,如果这样做,则必须将输出端口声明为全球和没有可重用。这种优化减少了一个memcpy
但确实引入了对速度较快的不均匀处理要求。
无论是否使用这种优化,从较慢的速率来看,最近的输入数据都是较快和较慢的速率都有命中时的值(也可能是较早的输入数据,具体取决于算法)。较慢速率的后续步骤和相关的输入数据更新不会被较慢速率看到,直到发生慢速率的下一个命中。
快到慢速率转换的伪代码示例
下面的伪代码抽象了应该如何编写C MEX代码来处理从快到慢的转换,用0.1秒的输入速率驱动1秒的输出速率来说明。在内联代码时也可以采用类似的方法。该块具有以下特点:
文件:
sfun_multirate_zoh.c
方程:Y = u(tslow)
输入:本地和可重用
输出:本地和可重用
DirectFeedthrough:是的
输出fcn if (ssIsSampleHit(".1")) {if (ssIsSepcialSampleHit("1")) {DWork = u;}} if (ssIsSampleHit("1")) {y = DWork;}
简单算法的另一种稍微优化的方法:
输入:本地和可重用
输出:全局的,不可重用的,因为它需要在特殊的样本命中之间持久化
DirectFeedthrough:是的
输出fcn if (ssIsSpecialSampleHit(" .1")) {if (ssIsSpecialSampleHit("1")) {y = u;}}
添加一个简单算法的例子:
文件:
sfun_multirate_avg.c
;方程:Y =平均值(u)
输入:本地和可重用
输出:本地和可重用
DirectFeedthrough:是的
(假设
DWork [0:10]
和DWork [mycounter]
初始化为0)OutputFcn if (ssIsSampleHit(".1")){/*一般来说,对'u'的处理可以在这里完成,它在每次快速命中时运行。*/ DWork[DWork[mycounter]++] = u;通常,DWork[0:10]上的处理可以在这里完成,但它确实导致更快的速率具有不统一的处理需求(每10次命中,需要运行更多代码)。*/ DWork[10] = sum(DWork[0:9])/10;DWork[mycounter] = 0;}} if (ssIsSampleHit("1")) {/* DWork[10]上的处理可以在输出之前在这里完成。此代码在每次执行较慢的任务时运行。*/ y = DWork[10];}
正确处理从慢到快转换的规则
当输出速率大于输入速率时,只能以与输入端口采样时间相关的速率读取输入,并遵循以下规则:
总是从更新函数中读取输入。
在读取输入时不使用特殊的样本命中检查。
将输入写入DWork。
当两个速率之间有一个特殊的样本命中率时,将DWork复制到输出函数中的第二个DWork中。
在每次达到输出采样率时,将第二个DWork写入输出。
块可以请求将输入端口设置为本地,但不能设置为可重用。输出端口可以设置为本地和可重用。
在快到慢转换的情况下,输入不应该由指定给输入端口的速率以外的速率读取。类似地,写入输出的速率不应该与分配给输出端口的速率不同。
当实现的算法只需要以慢速运行时,可以进行优化。在这种情况下,您只使用一个DWork。输入仍然写入更新函数中的DWork。当两个速率之间有一个特殊的样本命中率时,输出函数将相同的DWork直接复制到输出。在这种情况下,必须将输出端口设置为全局且不可重用。这种优化减少了一个memcpy
每个特殊样本命中的操作。
在这两种情况下,快速率计算操作的数据总是延迟的,也就是说,这些数据来自慢速率代码的前一步。
从慢到快速率转换的伪代码示例
下面的伪代码抽象了s函数处理从慢到快转换所需做的事情,用1秒的输入速率驱动0.1秒的输出速率来说明。该块具有以下特点:
文件:
sfun_multirate_delay.c
方程:Y = u(tslow-1)
输入:设置为本地,如果输出/更新组合(ERT)将为本地,否则将为全局。设置为不可重用,因为在更新函数运行之前需要保留输入。
输出:本地和可重用
DirectFeedthrough:不
输出fcn if (ssIsSpecialSampleHit(" .1") {if (ssIsSpecialSampleHit("1") {DWork[1] = DWork[0];} y = DWork[1];} UpdateFcn if (ssIsSampleHit("1")) {DWork[0] = u;}
一些算法可以使用另一种优化方法:
输入:设置为本地,如果输出/更新组合(ERT)将为本地,否则将为全局。设置为不可重用,因为在更新函数运行之前需要保留输入。
输出:全局的,不可重用的,因为它需要在特殊的样本命中之间持久化。
DirectFeedthrough:不
输出fcn if (ssIsSpecialSampleHit("1") {if (ssIsSpecialSampleHit("1") {y = DWork;}} UpdateFcn if (ssIsSampleHit("1")) {DWork = u;}
添加一个简单算法的例子:
文件:
sfun_multirate_modulate.c
方程:Y = sin(tfast) + u(tslow-1)
输入:设置为本地,如果输出/更新组合(ERT功能)将是本地的,否则将是全局的。设置为不可重用,因为在更新函数运行之前需要保留输入。
输出:本地和可重用
DirectFeedthrough:不
OutputFcn if (ssIsSampleHit(".1") {if (ssIsSpecialSampleHit("1"){/*这里不太可能进行处理。它导致更快的速度具有不统一的处理要求(每10次命中,需要运行更多代码)。*/ DWork[1] = DWork[0];} /*处理速度快*/ y = sin(ssGetTaskTime(".1")) + DWork[1];} UpdateFcn if (ssIsSampleHit("1")){/*对'u'的处理可以在这里完成。在快速利率看到它之前,有一个慢利率周期的延迟。*/ DWork[0] = u;}