文档

用于多速率多任务环境的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;}