Main Content

处理速率转换

速率转换

一个模型中可以存在两种周期性采样率转换:

  • 较快模块驱动较慢模块

  • 较慢模块驱动较快模块

下列各节仅涉及具有零偏移的周期性采样时间的模型。其他考虑因素适用于涉及异步任务的多速率模型。有关如何为异步多任务生成代码的详细信息,请参阅异步支持

在多任务和伪多任务系统中,不同的采样率可能导致模块以错误的顺序执行。为防止计算的数据中出现错误,您必须控制在发生这些转换时的模型执行。连接较快和较慢模块时,您或 Simulink® 引擎必须在它们之间添加 Rate Transition 模块。“快到慢”转换如下图所示。

Conceptual diagram that shows fast-to-slow rate transitions

“慢到快”转换如下图所示。

Conceptual diagram that shows slow-to-fast rate transitions

注意

尽管 Rate Transition 模块提供的功能是 Unit Delay 模块(用于慢到快转换)和 Zero-Order Hold 模块(用于快到慢转换)的超集,但您还是应该使用 Rate Transition 模块而不是这两个模块。

数据传输问题

Rate Transition 模块处理与以不同速率运行的各模块之间的数据传输相关联的数据完整性和确定性问题。

  • 数据完整性:当模块的输入在该模块执行期间发生更改时,就会出现数据完整性问题。数据完整性问题可能由抢占引起。

    以下列情形为例:

    • 一个较快模块向一个较慢模块提供输入。

    • 较慢模块从较快模块读取输入值 V1,并使用该值开始计算。

    • 然而,较快模块的另一次执行(该执行用来计算新输出值 V2)抢占了上述计算。

    • 这就会出现数据完整性问题:当较慢模块恢复执行时,它将继续其计算,但现在使用的是“新”输入值 V2

    这样的数据传输被称为不受保护的传输。实时模式下较快到较慢的转换显示了一个不受保护的数据传输。

    受保护的数据传输中,会保存较快模块的输出 V1,直到较慢模块完成执行。

  • 确定性非确定性数据传输:在确定性数据传输中,数据传输的时间是完全可预测的,因为这是由模块的采样率决定的。

    非确定性数据传输的时间取决于数据的可用性、模块的采样率以及接收模块相对于驱动模块开始执行的时间。

您可以使用 Rate Transition 模块来保护应用程序中的数据传输并使其具有确定性。在大多数应用中,这些特性都被认为是令人满意的。但是,Rate Transition 模块支持还支持一些灵活的选项,您可以为了降低延迟而适当牺牲数据完整性和确定性。下一节概述了这些选项。

数据传输假设

在处理任务之间的数据传输时,代码生成器将作以下假设:

  • 在单个读取任务和单个写入任务之间发生数据转移。

  • 以字节为单位的变量的读取或写入是原子级别的。

  • 当两个任务通过数据转移进行交互时,只有其中一个任务可以抢占另一个任务。

  • 对于周期性任务,速率较快的任务比速率较慢的任务具有更高优先级;速率较快的任务会抢占速率较慢的任务。

  • 所有任务都在单个处理器上运行。不允许分时。

  • 进程不会崩溃或重新启动(特别是在任务之间传输数据时)。

Rate Transition 模块选项

Rate Transition 模块有几个参数与它在代码生成中用于实时执行时相关,如下所述。有关完整的模块描述,请参阅 Rate Transition

Rate Transition 模块处理周期性转换(快速到慢速和慢速到快速)和异步转换。在具有不同采样率的两个模块之间插入 Rate Transition 模块时,该模块会针对转换类型自动配置其输入和输出采样率;您不需要指定转换是慢速到快速还是快速到慢速(对于异步任务,则是低到高还是高到低优先级)。

在配置 Rate Transition 模块时,您必须做出的关键决策是选择要在两种速率之间使用哪种数据传输机制。进行选择时,您需要综合考虑安全性、内存使用量和性能。如下图中的 Rate Transition 模块参数对话框所示,数据传输机制由两个选项控制。

Block Parameters dilog box for Rate Transition block

  • 确保数据传输的数据完整性:选中此参数时,数据在不同速率之间传输时仍能保持自身的完整性(数据传输受保护)。清除此参数时,数据可能无法保持其完整性(数据传输不受保护)。默认情况下,参数确保数据传输的数据完整性处于选中状态。

  • 确保确定性数据传输(最大延迟):对于零偏移或快速率是慢速率倍数的周期性任务,支持此参数。如果选中此参数,Rate Transition 模块的行为类似于 Zero-Order Hold 模块(适用于快速到慢速转换)或 Unit Delay 模块(适用于慢速到快速转换)。Rate Transition 模块以完全可预测的方式控制数据传输的时间。如果清除此参数,则数据传输是非确定性的。默认情况下,对于偏移为零的周期性速率之间的转换,确保确定性数据传输(最大延迟) 处于选中状态;而对于异步转换,则不能选择此选项。

Rate Transition 模块提供了三种关于数据传输的操作模式。按照安全级别顺序:

  • 受保护/确定性(默认):这是最安全的模式。此模式的缺点是:在慢速到快速的周期性速率转换情况下,它将为系统带来确定性延迟。对于这种情况,Rate Transition 模块带来的延迟是较慢任务的一个采样周期。对于快速到慢速的周期性速率转换情况,Rate Transition 模块不会带来额外的延迟。

  • 受保护/非确定性:在此模式下,对于慢速到快速的周期性速率转换,数据完整性由在不同速率之间传输的双缓冲数据机制来保护。对于快速到慢速的周期性速率转换,使用信号量标志。Rate Transition 模块的下游模块使用来自 Rate Transition 模块的驱动模块的最新可用数据。最大延迟小于或等于较快任务的一个采样周期。

    此模式的缺点是它具有非确定性时间。此模式的优点是低延迟。

  • 未受保护/非确定性:对于任务关键型应用程序,不推荐使用此模式。此模式的延迟与受保护/非确定性模式相同,但内存要求降低,因为不需要双缓冲和信号量。也就是说,在此模式下,Rate Transition 模块仅传递信号;它的作用只是通知您存在速率转换(并且可能导致生成的代码计算出不正确的答案)。但是,选择此模式产生的代码量最少。

    注意

    在不受保护的模式(确保数据传输的数据完整性处于选中状态)下,Rate Transition 模块的作用只是允许模型中存在速率转换。

Rate Transition 模块和连续时间

Rate Transition 模块的输出端口的采样时间在子时间步内只能是离散或固定采样时间。这意味着当 Rate Transition 模块从其目标模块继承连续采样时间时,它会将继承的采样时间视为在子时间步中是固定的。因此,Rate Transition 模块的输出函数仅在主时间步运行。如果目标模块采样时间是连续的,则 Rate Transition 模块的输出采样时间是基本速率采样时间(如果求解器采用定步长)或零阶保持连续采样时间(如果求解器采用变步长)。

自动速率转换

在图更新过程中,Simulink 引擎可检测到多任务模型中不匹配的速率转换,并自动插入 Rate Transition 模块来处理此问题。要启用此功能,请选中模型配置参数自动处理数据传输的速率转换。默认情况下,此参数处于清除状态。选中此参数时:

  • Simulink 将处理周期性采样时间和异步任务之间的速率转移。

  • Simulink 将在模块图中插入隐藏的 Rate Transition 模块。

  • 代码生成器为自动插入的 Rate Transition 模块生成代码。此代码与针对手动插入的 Rate Transition 模块生成的代码相同。

  • 对于周期性任务和异步任务,自动插入的 Rate Transition 模块在受保护模式下运行。您无法更改此行为。对于周期性任务,自动插入的 Rate Transition 模块按照模型配置参数确定性数据传输指定的确定性级别运行。默认设置为尽可能,此设置将根据一个整数倍数来确定相关周期性采样时间之间的数据传输。有关详细信息,请参阅Deterministic data transfer。要使用其他模式,您必须手动插入 Rate Transition 模块并设置其模式。

例如,在此模型中,SineWave2 的采样时间为 2,SineWave3 的采样时间为 3。

Model that shows a Sine Wave block with a sample time setting of 2 and a Sine Wave block with a sample time setting of 3

如果您选择模型配置参数自动处理数据传输的速率转换,Simulink 将在每个 Sine Wave 模块和 Product 模块之间插入一个 Rate Transition 模块。插入的模块具有参数值以协调 Sine Wave 模块采样时间。

如果模型中的输入端口和输出端口数据采样率不构成倍数关系,则 Simulink 会插入一个 Rate Transition 模块,其采样率是两个速率的最大公约数 (GCD)。如果该模型中没有其他模块包含此新速率,则在仿真期间会发生错误。在这种情况下,必须手动插入 Rate Transition 模块。

可视化插入的 Rate Transition 模块

如果您选择了模型配置参数自动处理数据传输的速率转换,Simulink 将在转移速率不匹配的路径中插入 Rate Transition 模块。这些模块默认情况下处于隐藏状态。要可视化插入的模块,请更新图。模型中将出现标记,指出 Simulink 在编译阶段插入 Rate Transition 模块的位置。例如,在此模型中,编译模型时在两个 Sine Wave 模块与 Multiplexer 和 Integrator 之间插入了三个 Rate Transition 模块。ZOH 和 DbBuf 标记指示了这些模块。

Model showing badges for auto-inserted Rate Transition blocks for paths that have mismatched transition rates

您可以显示或隐藏标记。打开调试选项卡。在叠加信息/采样时间库的诊断部分中,选中或清除自动速率转换

要配置隐藏的 Rate Transition 模块以使这些模块可见,请右键点击标记,然后点击插入 Rate Transition 模块

Model view showing auto-inserted Rate Transition blocks for paths that have mismatched transition rates

当您显示隐藏的 Rate Transition 模块之后:

  • 您可以看到插入的 Rate Transition 模块的类型以及该模块在模型中的位置。

  • 您可以设置模块参数初始条件

  • 您可以更改有关速率转换的模块参数设置。

通过更新图来验证您对模型所做的更改。

Updated version of model

Displaying inserted Rate Transition blocks is not compatible with export-function models.

有关 Rate Transition 模块类型的详细信息,请参阅 Rate Transition

周期性采样率转换

下列各节描述周期性采样率转换需要使用 Rate Transition 模块的情况。这些部分中的讨论和时序图基于以下假设:Rate Transition 模块在其默认(受保护/确定性)模式下使用。模型配置参数确保数据传输的数据完整性确保确定性数据传输(最大延迟) 处于选中状态。这些设置用于自动插入的 Rate Transition 模块。

Simulink 模型中较快到较慢的转换

在较快模块驱动具有直接馈通的较慢模块的模型中,首先计算较快模块的输出。在较慢模块不执行的仿真间隔中,仿真进度较快,因为要执行的模块较少。下图说明了这种情况。

Conceptual diagram that shows what occurs when a faster block drives a slower block that has direct feedthrough

Simulink 仿真不实时执行,这意味着它不受实时约束的限制。仿真会等待或前进到任何完成仿真流所需的任务。采样时间步之间的实际时间间隔可能有所不同。

实时模式下较快到较慢的转换

在较快模块驱动较慢模块的模型中,由于较慢模块的执行时间可能会是执行多个较快模块所需的时间,您必须对此予以补偿。这意味着较快模块的输出可能会在较慢模块完成计算其输出之前发生变化。下图显示了出现此问题的情况(T = 采样时间)。请注意,较低优先级的任务在完成之前被较高优先级的任务抢占。

Timing diagram that shows what happens when a faster block drives a slower block and you have to compensate for when the slower block spans multiple execution periods of the faster block

在上图中,较快模块在较慢模块完成执行之前又执行了一次。这可能会导致不可预测的结果,因为慢任务的输入数据发生了更改。在这种情况下,数据可能无法保持其完整性。

为避免这种情况,Simulink 引擎必须保持 1 秒(较快)模块的输出,直到 2 秒(较慢)模块完成执行。为此,需要在 1 秒模块和 2 秒模块之间插入一个 Rate Transition 模块。较慢模块的输入在模块执行过程中不会发生变化,从而保持了数据的完整性。

Conceptual diagram showing how Simulink holds outputs of a faster block until a slower block finishes executing to maintain data integrity

假设 Rate Transition 模块在其默认(受保护/确定性)模式下使用。

Rate Transition 模块以较慢模块的采样率执行,但以较快模块的优先级执行。

Timing diagram showing how a Rate Transition block executes at the sample rate of a slower block, but with the priority of a faster block

如果您添加 Rate Transition 模块,该模块将在 2 秒模块之前执行(其优先级较高),其输出值在 2 秒模块执行(以较慢采样率执行)时将保持不变。

Simulink 模型中较慢到较快的转换

在较慢模块驱动较快模块的模型中,Simulink 引擎会再次首先计算驱动模块的输出。在只有较快模块执行的采样间隔期间,仿真进度较快。

下图显示了执行顺序。

Conceptual diagram that shows what occurs when a slower block drives a faster block

从上图可以看出,Simulink 引擎可以有效地对具有多个采样率的模型进行仿真。但是,Simulink 仿真不能实时运行。

以实时方式进行较慢到较快的转换

在较慢模块驱动较快模块的模型中,生成的代码为较快模块指定的优先级高于较慢模块。这意味着较快模块在较慢模块之前执行,此时需要特别注意避免不正确的结果。

Timing diagram showing how when a slower block drivers a faster block, generated code assigns the faster block a higher priority than the slower block so the faster block executes before the slower block

此时序图说明了两个问题:

  • 较慢模块的执行时间跨越较快模块的多个执行时间间隔。在这种情况下,较快任务在较慢任务完成执行之前又执行了一次。这意味着较快任务的输入在某段时间可能包含不正确的值。

  • 较快模块在较慢模块之前执行(与 Simulink 仿真操作方向相反)。在这种情况下,1 秒模块会先执行;但是较快任务的输入尚未计算出来。这可能导致不可预测的结果。

为消除这些问题,必须在较慢模块和较快模块之间插入一个 Rate Transition 模块。

Conceptual diagram showing the results of inserting a Rate Transition block between slower and faster blocks to eliminate scheduling issues

假设 Rate Transition 模块在其默认(受保护/确定性)模式下使用。

下图显示添加 Rate Transition 模块后产生的时序。

Timing diagram that shows benefits of inserting Rate Transition blocks

此图中关于转换的三个关键点(请参见带圆圈的数字):

  1. Rate Transition 模块输出在 1 秒任务中运行,但以慢速(2 秒)运行。Rate Transition 模块的输出为 1 秒任务模块馈送数据。

  2. Rate Transition 更新使用 2 秒任务的输出来更新其内部状态。

  3. 1 秒任务中的 Rate Transition 输出使用已在 2 秒任务中更新过的 Rate Transition 的状态。

第一个问题得到解决,因为 Rate Transition 模块以较慢速率和较慢模块的优先级进行更新。在较慢模块完成执行后,将读取 Rate Transition 模块的输入(它是较慢模块的输出)。

第二个问题得到解决,因为 Rate Transition 模块以较慢速率执行,并且其输出在它所驱动的较快模块进行计算期间不会发生变化。Rate Transition 模块的输出部分以较慢模块的采样率执行,但以较快模块的优先级执行。由于 Rate Transition 模块驱动较快模块并且具有相同的优先级,因此它在较快模块之前执行。

注意

Rate Transition 模块的使用改变了模型。与不使用 Rate Transition 模块的输出相比,较慢模块的输出现在延迟了一个时间步。

使用 volatile 关键字保护数据完整性

当您选择模型配置参数确保数据传输的数据完整性时,为 Rate Transition 模块生成的代码将定义全局缓冲区和信号量,并使用它们来保护传输数据的完整性。

特别是对于多任务应用程序,数据传输中涉及的任务(速率)可能会在编译器无法预料的时间写入传输的数据、缓冲区和信号量。为了防止编译器以损害传输数据完整性的方式优化程序集代码,代码生成器将关键字 volatile 应用于缓冲区和信号量。代码生成器不会将 volatile 应用于表示传输数据的全局变量,因为 volatile 缓冲区和信号量通常会提供足够的保护。

使用 Embedded Coder®,您可以通过将内置自定义存储类 volatile 应用于 Rate Transition 模块的输入,将 Volatile 显式应用于传输的数据。例如,您可以使用此方法来帮助保护外部代码与生成的代码共享的数据的完整性。

或者,为保护外部代码与生成的代码共享的数据,您可以编写自己的 C 函数,以受保护的方式读写数据。然后,您可以将自定义存储类 GetSet 应用于模型中的数据,这会使生成的代码调用您的函数而不是直接访问数据。

有关应用 volatile 的详细信息,请参阅Protect Global Data with const and volatile Type Qualifiers。有关 GetSet 的详细信息,请参阅Access Data Through Functions with Storage Class GetSet

从算法代码和数据中分离 Rate Transition 模块代码和数据

您可以指定代码生成器是将它为 Rate Transition 模块生成的代码和数据内联到模型代码中,还是将代码和数据放入模型代码调用的单独的函数中。您可以通过选择Rate Transition 模块代码参数对此进行控制。通过将 Rate Transition 模块代码及数据与算法代码及数据分离,您能够对 Rate Transition 模块代码和算法代码独立地进行分析、优化和测试。默认情况下,Rate Transition 模块代码设置为内联到算法代码和数据中。您可以将代码和数据分开,以便生成的代码包含 model_step 函数调用的单独 getset 函数以及专用的状态数据结构体。生成的代码还包含 model_initialize 函数调用的单独 startinitialize 函数。

示例模型

打开示例模型 MultirateMultitaskingRateTransitions。这种多速率、多任务模型包含几个在不同模式下运行的 Rate Transition 模块。

model = 'MultirateMultitaskingRateTransitions';
open_system(model);

set_param(model,'SystemTargetFile','ert.tlc');
set_param(model,'GenerateComments', 'Off');

将 Rate Transition 模块的代码分离出来

在“配置参数”对话框中,Rate Transition 模块代码参数设置为 Function。为模型生成代码。代码位于文件 MultirateMultitaskingRateTransitions.cMultirateMultitaskingRateTransitions.h 中。

slbuild(model);
### Starting build procedure for: MultirateMultitaskingRateTransitions
### Successful completion of build procedure for: MultirateMultitaskingRateTransitions

Build Summary

Top model targets built:

Model                                 Action                        Rebuild Reason                                    
======================================================================================================================
MultirateMultitaskingRateTransitions  Code generated and compiled.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 14.063s
currentDir = pwd;
hfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw','MultirateMultitaskingRateTransitions.h');
coder.example.extractLines(hfile,'typedef struct {','} DW;', 1, 1);
typedef struct {
  real_T OutportBufferForOut3[20];
  real_T Integrator1_DSTATE[20];
  real_T Integrator2_DSTATE[20];
  real_T Integrator3_DSTATE[20];
  real_T Integrator1_PREV_U[20];
  real_T Integrator2_PREV_U[20];
  real_T Integrator3_PREV_U[20];
  uint32_T Algorithm_PREV_T;
  struct {
    uint_T Algorithm_RESET_ELAPS_T:1;
  } bitsForTID1;

  uint8_T Integrator1_SYSTEM_ENABLE;
  uint8_T Integrator2_SYSTEM_ENABLE;
  uint8_T Integrator3_SYSTEM_ENABLE;
} DW;

对于 Rate Transition 模块,状态数据不在全局状态结构体 DW_MultirateMultitaskingRateTransitions_T. 中。此数据在文件 MultirateMultitaskingRateTransitions_rtb.h 中它自己的结构体中。

以下代码包含在文件 MultirateMultitaskingRateTransitions.c 中。

cfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw','MultirateMultitaskingRateTransitions.c');
coder.example.extractLines(cfile,'void MultirateMultitaskingRateTransitions_step0','void MultirateMultitaskingRateTransitions_terminate(void)', 1, 0);
void MultirateMultitaskingRateTransitions_step0(void)
{
  (rtM->Timing.RateInteraction.TID0_1)++;
  if ((rtM->Timing.RateInteraction.TID0_1) > 1) {
    rtM->Timing.RateInteraction.TID0_1 = 0;
  }

  MultirateMul_DetAndIntegS2F_get(rtY.Out1);
  MultirateMulti_IntegOnlyS2F_get(rtY.Out2);
  memcpy(&rtY.Out3[0], &rtDW.OutportBufferForOut3[0], 20U * sizeof(real_T));
  MultirateMul_DetAndIntegF2S_set(rtU.In1);
  MultirateMulti_IntegOnlyF2S_set(rtU.In2);
}

void MultirateMultitaskingRateTransitions_step1(void)
{
  real_T rtb_DetAndIntegF2S[20];
  real_T rtb_IntegOnlyF2S[20];
  real_T Integrator3_DSTATE;
  real_T tmp;
  int32_T i;
  uint32_T Algorithm_ELAPS_T;
  MultirateMul_DetAndIntegF2S_get(rtb_DetAndIntegF2S);
  MultirateMulti_IntegOnlyF2S_get(rtb_IntegOnlyF2S);
  if (rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T) {
    Algorithm_ELAPS_T = 0U;
  } else {
    Algorithm_ELAPS_T = rtM->Timing.clockTick1 - rtDW.Algorithm_PREV_T;
  }

  rtDW.Algorithm_PREV_T = rtM->Timing.clockTick1;
  rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T = false;
  tmp = 0.001 * (real_T)Algorithm_ELAPS_T;
  for (i = 0; i < 20; i++) {
    if (rtDW.Integrator1_SYSTEM_ENABLE == 0) {
      rtDW.Integrator1_DSTATE[i] += tmp * rtDW.Integrator1_PREV_U[i];
    }

    if (rtDW.Integrator2_SYSTEM_ENABLE == 0) {
      rtDW.Integrator2_DSTATE[i] += tmp * rtDW.Integrator2_PREV_U[i];
    }

    Integrator3_DSTATE = rtDW.Integrator3_DSTATE[i];
    if (rtDW.Integrator3_SYSTEM_ENABLE == 0) {
      Integrator3_DSTATE += tmp * rtDW.Integrator3_PREV_U[i];
    }

    rtDW.Integrator3_DSTATE[i] = Integrator3_DSTATE;
    rtDW.OutportBufferForOut3[i] = Integrator3_DSTATE;
    rtDW.Integrator1_PREV_U[i] = rtb_DetAndIntegF2S[i];
    rtDW.Integrator2_PREV_U[i] = rtb_IntegOnlyF2S[i];
    rtDW.Integrator3_PREV_U[i] = rtU.In3[i];
  }

  rtDW.Integrator1_SYSTEM_ENABLE = 0U;
  rtDW.Integrator2_SYSTEM_ENABLE = 0U;
  rtDW.Integrator3_SYSTEM_ENABLE = 0U;
  MultirateMul_DetAndIntegS2F_set(rtDW.Integrator1_DSTATE);
  MultirateMulti_IntegOnlyS2F_set(rtDW.Integrator2_DSTATE);
  rtM->Timing.clockTick1++;
}

void MultirateMultitaskingRateTransitions_initialize(void)
{
  rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T = true;
  rtDW.Integrator1_SYSTEM_ENABLE = 1U;
  rtDW.Integrator2_SYSTEM_ENABLE = 1U;
  rtDW.Integrator3_SYSTEM_ENABLE = 1U;
}

MultirateMultitaskingRateTransitions_step0MultirateMultitaskingRateTransitions_step1 函数包含对 get set 函数的调用。这些函数包含 Rate Transition 模块代码。这些函数定义位于文件 MultirateMultitaskingRateTransitions_rtb.c 中。

为 Rate Transition 模块生成内联代码

在“配置参数”对话框中,将Rate Transition 模块代码参数设置为 Inline。为模型生成代码。代码位于文件 MultirateMultitaskingRateTransitions.cMultirateMultitaskingRateTransitions.h 中。

set_param(model,'RateTransitionBlockCode','Inline');
slbuild(model)
### Starting build procedure for: MultirateMultitaskingRateTransitions
### Successful completion of build procedure for: MultirateMultitaskingRateTransitions

Build Summary

Top model targets built:

Model                                 Action                        Rebuild Reason                   
=====================================================================================================
MultirateMultitaskingRateTransitions  Code generated and compiled.  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 13.128s

以下代码现在位于文件 MultirateMultitaskingRateTransitions.h 中。

hfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw','MultirateMultitaskingRateTransitions.h');
coder.example.extractLines(hfile, 'typedef struct {', '} DW;', 1, 1);
typedef struct {
  real_T Integrator1_DSTATE[20];
  real_T Integrator2_DSTATE[20];
  real_T Integrator3_DSTATE[20];
  real_T DetAndIntegS2F_Buffer0[20];
  volatile real_T IntegOnlyS2F_Buffer[40];
  real_T DetAndIntegF2S_Buffer[20];
  volatile real_T IntegOnlyF2S_Buffer0[20];
  real_T Integrator1_PREV_U[20];
  real_T Integrator2_PREV_U[20];
  real_T Integrator3_PREV_U[20];
  uint32_T Algorithm_PREV_T;
  struct {
    uint_T Algorithm_RESET_ELAPS_T:1;
  } bitsForTID1;

  volatile int8_T IntegOnlyS2F_ActiveBufIdx;
  volatile int8_T IntegOnlyF2S_semaphoreTaken;
  uint8_T Integrator1_SYSTEM_ENABLE;
  uint8_T Integrator2_SYSTEM_ENABLE;
  uint8_T Integrator3_SYSTEM_ENABLE;
} DW;

对于 Rate Transition 模块,状态数据不在全局状态结构体 DW_MultirateMultitaskingRateTransitions_T 中。这些数据在文件 MultirateMultitaskingRateTransitions_rtb.h 内专门的结构体中。

以下代码现在位于文件 MultirateMultitaskingRateTransitions.c 中。

cfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw','MultirateMultitaskingRateTransitions.c');
coder.example.extractLines(cfile,'void MultirateMultitaskingRateTransitions_step0','void MultirateMultitaskingRateTransitions_terminate(void)', 1, 0);
void MultirateMultitaskingRateTransitions_step0(void)
{
  int32_T i;
  int32_T i_0;
  (rtM->Timing.RateInteraction.TID0_1)++;
  if ((rtM->Timing.RateInteraction.TID0_1) > 1) {
    rtM->Timing.RateInteraction.TID0_1 = 0;
  }

  if (rtM->Timing.RateInteraction.TID0_1 == 1) {
    memcpy(&rtY.Out1[0], &rtDW.DetAndIntegS2F_Buffer0[0], 20U * sizeof(real_T));
  }

  i = rtDW.IntegOnlyS2F_ActiveBufIdx * 20;
  for (i_0 = 0; i_0 < 20; i_0++) {
    rtY.Out2[i_0] = rtDW.IntegOnlyS2F_Buffer[i_0 + i];
  }

  if (rtM->Timing.RateInteraction.TID0_1 == 1) {
    memcpy(&rtDW.DetAndIntegF2S_Buffer[0], &rtU.In1[0], 20U * sizeof(real_T));
  }

  if (rtDW.IntegOnlyF2S_semaphoreTaken == 0) {
    for (i = 0; i < 20; i++) {
      rtDW.IntegOnlyF2S_Buffer0[i] = rtU.In2[i];
    }
  }
}

void MultirateMultitaskingRateTransitions_step1(void)
{
  real_T rtb_IntegOnlyF2S[20];
  real_T Integrator1_DSTATE;
  real_T Out3;
  real_T tmp;
  int32_T i;
  uint32_T Algorithm_ELAPS_T;
  rtDW.IntegOnlyF2S_semaphoreTaken = 1;
  for (i = 0; i < 20; i++) {
    rtb_IntegOnlyF2S[i] = rtDW.IntegOnlyF2S_Buffer0[i];
  }

  rtDW.IntegOnlyF2S_semaphoreTaken = 0;
  if (rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T) {
    Algorithm_ELAPS_T = 0U;
  } else {
    Algorithm_ELAPS_T = rtM->Timing.clockTick1 - rtDW.Algorithm_PREV_T;
  }

  rtDW.Algorithm_PREV_T = rtM->Timing.clockTick1;
  rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T = false;
  tmp = 0.001 * (real_T)Algorithm_ELAPS_T;
  for (i = 0; i < 20; i++) {
    Integrator1_DSTATE = rtDW.Integrator1_DSTATE[i];
    if (rtDW.Integrator1_SYSTEM_ENABLE == 0) {
      Integrator1_DSTATE += tmp * rtDW.Integrator1_PREV_U[i];
    }

    rtDW.Integrator1_DSTATE[i] = Integrator1_DSTATE;
    if (rtDW.Integrator2_SYSTEM_ENABLE == 0) {
      rtDW.Integrator2_DSTATE[i] += tmp * rtDW.Integrator2_PREV_U[i];
    }

    if (rtDW.Integrator3_SYSTEM_ENABLE != 0) {
      Out3 = rtDW.Integrator3_DSTATE[i];
    } else {
      Out3 = tmp * rtDW.Integrator3_PREV_U[i] + rtDW.Integrator3_DSTATE[i];
    }

    rtY.Out3[i] = Out3;
    rtDW.Integrator1_PREV_U[i] = rtDW.DetAndIntegF2S_Buffer[i];
    rtDW.Integrator2_PREV_U[i] = rtb_IntegOnlyF2S[i];
    rtDW.Integrator3_DSTATE[i] = Out3;
    rtDW.Integrator3_PREV_U[i] = rtU.In3[i];
    rtDW.DetAndIntegS2F_Buffer0[i] = Integrator1_DSTATE;
  }

  rtDW.Integrator1_SYSTEM_ENABLE = 0U;
  rtDW.Integrator2_SYSTEM_ENABLE = 0U;
  rtDW.Integrator3_SYSTEM_ENABLE = 0U;
  for (i = 0; i < 20; i++) {
    rtDW.IntegOnlyS2F_Buffer[i + (rtDW.IntegOnlyS2F_ActiveBufIdx == 0) * 20] =
      rtDW.Integrator2_DSTATE[i];
  }

  rtDW.IntegOnlyS2F_ActiveBufIdx = (int8_T)(rtDW.IntegOnlyS2F_ActiveBufIdx == 0);
  rtM->Timing.clockTick1++;
}

void MultirateMultitaskingRateTransitions_initialize(void)
{
  rtDW.bitsForTID1.Algorithm_RESET_ELAPS_T = true;
  rtDW.Integrator1_SYSTEM_ENABLE = 1U;
  rtDW.Integrator2_SYSTEM_ENABLE = 1U;
  rtDW.Integrator3_SYSTEM_ENABLE = 1U;
}

代码内联在函数 MultirateMultitaskingRateTransitions_step0MultirateMultitaskingRateTransitions_step1 中。

关闭模型

bdclose(model);

限制

代码生成器不会将那些具有可变大小信号或位于 For Each Subsystem 模块内的 For Rate Transition 模块的代码和数据分离出来。

另请参阅

相关主题