Main Content

Control Data Transfer Behavior By Configuring Rate Transitions

This example shows how you can control data transfer behavior for a multirate, multitasking model by using the Rate Transition block. When you manually insert a Rate Transition block on a data transfer signal line, you can adjust block parameter settings that control whether generated code maintains data integrity and achieves determinism to best meet application requirements.

Multirate Multitasking Example Model

Open the example mode MultirateMultitaskingRateTransitions.

open_system('MultirateMultitaskingRateTransitions')

The example model includes six Rate Transition blocks.

  • DetAndIntegF2S is configured to maintain data integrity and achieve determinism for fast-to-slow rate transitions.

  • DetAndIntegS2F is configured to maintain data integrity and achieve determinism for slow-to-fast rate transitions.

  • IntegOnlyF2S is configured to preserve data integrity only for fast-to-slow transitions.

  • IntegOnlyS2F is configured to preserve data integrity only for slow-to-fast transitions.

  • NoneF2S is configured such that the code generator does not produce code for fast-to-slow transitions.

  • NoneS2F is configured such that the code generator does not produce code for slow-to-fast transitions.

The example model is also configured for the code generator to separate Rate Transition block code from algorithm code. For more information, see Control Format and Placement of Rate Transition Block Code and Data (Embedded Coder) (Embedded Coder).

The following sections describe the block configuration and data transfer behavior for each scenario and show relevant generated code.

Data Integrity and Determinism for Fast-to-Slow Transitions

Input sample time: 1/2000 second

Parameter settings for Rate Transition block DetAndIntegF2S:

  • Ensure data integrity during data transfer is selected.

  • Ensure deterministic data transfer (maximum delay) is selected.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/1000.

Data Transfer behavior:

  • Block output is used as a persistent data buffer.

  • The faster rate task writes data to the block output buffer at a slower rate.

  • Data as seen by the slower rate task is the value when the faster and slower rate tasks last executed.

  • Subsequent steps by the faster rate task (and associated data updates) while the slower rate task is running are not seen by the slower rate task.

Data Integrity and Determinism for Slow-to-Fast Transitions

Input sample time: 1/1000 second

Parameter settings for Rate Transition block DetAndIntegS2F:

  • Ensure data integrity during data transfer is selected.

  • Ensure deterministic data transfer (maximum delay) is selected.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/2000.

Data Transfer behavior:

  • Uses two persistent data buffers, an internal buffer and the block output buffer.

  • The faster rate task copies data that is in the internal buffer to the block output buffer at the slower rate.

  • The slower rate task writes data to the internal buffer at the slower rate.

  • Data that the faster rate task sees is delayed. That is, the data is from the previous step of the slower rate task.

Data Integrity Only for Fast-to-Slow Transitions

Input sample time: 1/2000 second

Parameter settings for Rate Transition block IntegOnlyF2S:

  • Ensure data integrity during data transfer is selected.

  • Ensure deterministic data transfer (maximum delay) is cleared.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/1000.

Data Transfer behavior:

  • The block output is used as a persistent data buffer.

  • A flag indicates when data is being read from the block output buffer. If data is not being read, the faster rate task writes data to the buffer.

  • The flag is set and data is copied from the buffer to the output at the slower rate. Then, the flag is cleared. This copy operation is an additional data copy compared to the DetAndIntegF2S block.

  • The data, as seen by the slower rate task, can be from a more recent step of the faster rate task compared to when the slower rate task and faster rate tasks executed.

Data Integrity Only for Slow-to-Fast Transitions

Input sample time: 1/1000 second

Parameter settings for Rate Transition block IntegOnlyS2F:

  • Ensure data integrity during data transfer is selected.

  • Ensure deterministic data transfer (maximum delay) is cleared.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/2000.

Data Transfer behavior:

  • Uses two persistent internal data buffers.

  • Data in one of the buffers is copied to the block output buffer at the faster rate.

  • The slower rate task writes data to the other internal buffer at the slower rate. Then, the active buffer is switched.

  • The data, as seen by the faster rate task, can be more recent than for the deterministic case. When the slower and faster rate tasks have their hits, the faster rate task sees a previous value from the slower rate task. Subsequent steps for the faster rate task might see an updated value when the slower rate task updates the nonactive buffer and switches the active buffer flag.

No Rate Transition Block Code for Fast-to-Slow Transitionss

Input sample time: 1/2000 second

Parameter settings for Rate Transition block IntegOnlyS2F:

  • Ensure data integrity during data transfer is cleared.

  • Ensure deterministic data transfer (maximum delay) is cleared.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/1000.

Data Transfer behavior:

The code generator does not produce code for the Rate Transition block.

No Rate Transition Block Code for Slow-to-Fast Transitions

Input sample time: 1/1000 second

Parameter settings for Rate Transition block IntegOnlyS2F:

  • Ensure data integrity during data transfer is cleared.

  • Ensure deterministic data transfer (maximum delay) is cleared.

  • Output port sample time options is set to Specify.

  • Output port sample time is set to 1/2000.

Data Transfer behavior:

The code generator does not produce code for the Rate Transition block.

Generate and Review Code

Generate code for the model.

slbuild('MultirateMultitaskingRateTransitions');
### Searching for referenced models in model 'MultirateMultitaskingRateTransitions'.
### Total of 1 models to build.
### Starting build procedure for: MultirateMultitaskingRateTransitions
### Successful completion of build procedure for: MultirateMultitaskingRateTransitions

Build Summary

Top model targets:

Model                                 Build Reason                                         Status                        Build Duration
=======================================================================================================================================
MultirateMultitaskingRateTransitions  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 33.458s 

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

The code generator places the rate transition state data in its own structure in the file MultirateMultitaskingRateTransitions_rtb.h.

currentDir = pwd;
hfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw',...
    'MultirateMultitaskingRateTransitions_rtb.h');
coder.example.extractLines(hfile,'typedef struct {','} RTB', 1, 1);
typedef struct {
  real_T DetAndIntegS2F_Buffer0[20];   /* '<Root>/DetAndIntegS2F' */
  real_T DetAndIntegS2F_Buffer1[20];   /* '<Root>/DetAndIntegS2F' */
  volatile real_T IntegOnlyS2F_Buffer[40];/* '<Root>/IntegOnlyS2F' */
  real_T DetAndIntegF2S_Buffer[20];    /* '<Root>/DetAndIntegF2S' */
  volatile real_T IntegOnlyF2S_Buffer0[20];/* '<Root>/IntegOnlyF2S' */
  volatile int8_T IntegOnlyS2F_ActiveBufIdx;/* '<Root>/IntegOnlyS2F' */
  volatile int8_T IntegOnlyF2S_semaphoreTaken;/* '<Root>/IntegOnlyF2S' */
} RTB;

The file MultirateMultitaskingRateTransitions_rtb.h also declares rate transition get and set functions.

hfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw',...
    'MultirateMultitaskingRateTransitions_rtb.h');
coder.example.extractLines(hfile,'extern void MultirateMul_DetAndIntegS2F_get',...
    'extern void MultirateMulti_IntegOnlyS2F_set', 1, 1);
extern void MultirateMul_DetAndIntegS2F_get(real_T DetAndIntegS2F_value[20]);
extern void MultirateMulti_IntegOnlyS2F_get(real_T IntegOnlyS2F_value[20]);
extern void MultirateMul_DetAndIntegF2S_set(const real_T DetAndIntegF2S_value[20]);
extern void MultirateMulti_IntegOnlyF2S_set(const real_T IntegOnlyF2S_value[20]);
extern void MultirateMul_DetAndIntegF2S_get(real_T DetAndIntegF2S_value[20]);
extern void MultirateMulti_IntegOnlyF2S_get(real_T IntegOnlyF2S_value[20]);
extern void MultirateMul_DetAndIntegS2F_set(const real_T DetAndIntegS2F_value[20]);
extern void MultirateMulti_IntegOnlyS2F_set(const real_T IntegOnlyS2F_value[20]);

The rate transition get and set functions, which contain the Rate Transition block code, are defined in the file MultirateMultitaskingRateTransitions_rtb.c.

cfile=fullfile(currentDir, 'MultirateMultitaskingRateTransitions_ert_rtw',...
    'MultirateMultitaskingRateTransitions_rtb.c');
coder.example.extractLines(cfile,...
    '/* RateTransition function MultirateMul_DetAndIntegS2F_get',...
    '* File trailer for generated code',1,0); 
/* RateTransition function MultirateMul_DetAndIntegS2F_get */
extern void MultirateMul_DetAndIntegS2F_get(real_T DetAndIntegS2F_value[20])
{
  /* RateTransition: '<Root>/DetAndIntegS2F' */
  if (rtM->Timing.RateInteraction.TID0_1 == 1) {
    memcpy(&rtRTB.DetAndIntegS2F_Buffer1[0], &rtRTB.DetAndIntegS2F_Buffer0[0],
           20U * sizeof(real_T));
  }

  memcpy(&DetAndIntegS2F_value[0], &rtRTB.DetAndIntegS2F_Buffer1[0], 20U *
         sizeof(real_T));

  /* End of RateTransition: '<Root>/DetAndIntegS2F' */
}

/* RateTransition function MultirateMulti_IntegOnlyS2F_get */
extern void MultirateMulti_IntegOnlyS2F_get(real_T IntegOnlyS2F_value[20])
{
  int32_T i;
  int32_T tmp;

  /* RateTransition: '<Root>/IntegOnlyS2F' */
  tmp = rtRTB.IntegOnlyS2F_ActiveBufIdx * 20;
  for (i = 0; i < 20; i++) {
    IntegOnlyS2F_value[i] = rtRTB.IntegOnlyS2F_Buffer[i + tmp];
  }

  /* End of RateTransition: '<Root>/IntegOnlyS2F' */
}

/* RateTransition function MultirateMul_DetAndIntegF2S_set */
extern void MultirateMul_DetAndIntegF2S_set(const real_T DetAndIntegF2S_value[20])
{
  /* RateTransition: '<Root>/DetAndIntegF2S' */
  if (rtM->Timing.RateInteraction.TID0_1 == 1) {
    memcpy(&rtRTB.DetAndIntegF2S_Buffer[0], &DetAndIntegF2S_value[0], 20U *
           sizeof(real_T));
  }

  /* End of RateTransition: '<Root>/DetAndIntegF2S' */
}

/* RateTransition function MultirateMulti_IntegOnlyF2S_set */
extern void MultirateMulti_IntegOnlyF2S_set(const real_T IntegOnlyF2S_value[20])
{
  int32_T i;

  /* RateTransition: '<Root>/IntegOnlyF2S' */
  if (rtRTB.IntegOnlyF2S_semaphoreTaken == 0) {
    for (i = 0; i < 20; i++) {
      rtRTB.IntegOnlyF2S_Buffer0[i] = IntegOnlyF2S_value[i];
    }
  }

  /* End of RateTransition: '<Root>/IntegOnlyF2S' */
}

/* RateTransition function MultirateMul_DetAndIntegF2S_get */
extern void MultirateMul_DetAndIntegF2S_get(real_T DetAndIntegF2S_value[20])
{
  /* RateTransition: '<Root>/DetAndIntegF2S' */
  memcpy(&DetAndIntegF2S_value[0], &rtRTB.DetAndIntegF2S_Buffer[0], 20U * sizeof
         (real_T));
}

/* RateTransition function MultirateMulti_IntegOnlyF2S_get */
extern void MultirateMulti_IntegOnlyF2S_get(real_T IntegOnlyF2S_value[20])
{
  int32_T i;

  /* RateTransition: '<Root>/IntegOnlyF2S' */
  rtRTB.IntegOnlyF2S_semaphoreTaken = 1;
  for (i = 0; i < 20; i++) {
    IntegOnlyF2S_value[i] = rtRTB.IntegOnlyF2S_Buffer0[i];
  }

  rtRTB.IntegOnlyF2S_semaphoreTaken = 0;

  /* End of RateTransition: '<Root>/IntegOnlyF2S' */
}

/* RateTransition function MultirateMul_DetAndIntegS2F_set */
extern void MultirateMul_DetAndIntegS2F_set(const real_T DetAndIntegS2F_value[20])
{
  /* RateTransition: '<Root>/DetAndIntegS2F' */
  memcpy(&rtRTB.DetAndIntegS2F_Buffer0[0], &DetAndIntegS2F_value[0], 20U *
         sizeof(real_T));
}

/* RateTransition function MultirateMulti_IntegOnlyS2F_set */
extern void MultirateMulti_IntegOnlyS2F_set(const real_T IntegOnlyS2F_value[20])
{
  int32_T i;

  /* RateTransition: '<Root>/IntegOnlyS2F' */
  for (i = 0; i < 20; i++) {
    rtRTB.IntegOnlyS2F_Buffer[i + (rtRTB.IntegOnlyS2F_ActiveBufIdx == 0) * 20] =
      IntegOnlyS2F_value[i];
  }

  rtRTB.IntegOnlyS2F_ActiveBufIdx = (int8_T)(rtRTB.IntegOnlyS2F_ActiveBufIdx ==
    0);

  /* End of RateTransition: '<Root>/IntegOnlyS2F' */
}

/*

For this rate-based model, the code generator produces two model entry-point step functions, one for each sample rate. The generated entry-point function for the faster sample rate (1/2000 second) includes rate transition code that:

  1. For data integrity only data transfers, sets up the flag Timing.RateInteraction.TID0_1 for monitoring when data is being read from the persistent block output buffer.

  2. For data integrity and determinism and data integrity only slow-to-fast data transfers, calls functions MultirateMul_DetAndIntegS2F_get and MultirateMul_IntegOnlyS2F_get to read data from internal buffers rtY.Out and rtY.Out2.

  3. For slow-to-fast data transfers for which no Rate Transition code exists, calls memcpy to copy data to output buffer rtDW.OutportBufferForOut3.

  4. For data integrity and determinism and data integrity only fast-to-slow data transfers, calls functions MultirateMul_DetAndIntegF2S_set and MultirateMul_IntegOnlyF2S_set to write data to internal buffers rtU.In1 and rtU.In2.

currentDir = pwd;
cfile=fullfile(currentDir,'MultirateMultitaskingRateTransitions_ert_rtw','MultirateMultitaskingRateTransitions.c');
coder.example.extractLines(cfile,'/* Model step function for TID0',...)
    '/* Model step function for TID1',1,0);
/* Model step function for TID0 */
void MultirateMultitaskingRateTransitions_step0(void) /* Sample time: [0.0005s, 0.0s] */
{
  /* Update the flag to indicate when data transfers from
   *  Sample time: [0.0005s, 0.0s] to Sample time: [0.001s, 0.0s]  */
  (rtM->Timing.RateInteraction.TID0_1)++;
  if ((rtM->Timing.RateInteraction.TID0_1) > 1) {
    rtM->Timing.RateInteraction.TID0_1 = 0;
  }

  /* Outport: '<Root>/Out1' incorporates:
   *  RateTransition: '<Root>/DetAndIntegS2F'
   */
  MultirateMul_DetAndIntegS2F_get(rtY.Out1);

  /* RateTransition: '<Root>/IntegOnlyS2F' */
  MultirateMulti_IntegOnlyS2F_get(rtY.Out2);

  /* Outport: '<Root>/Out3' incorporates:
   *  RateTransition: '<Root>/NoneS2F'
   */
  memcpy(&rtY.Out3[0], &rtDW.OutportBufferForOut3[0], 20U * sizeof(real_T));

  /* RateTransition: '<Root>/DetAndIntegF2S' incorporates:
   *  Inport: '<Root>/In1'
   */
  MultirateMul_DetAndIntegF2S_set(rtU.In1);

  /* RateTransition: '<Root>/IntegOnlyF2S' incorporates:
   *  Inport: '<Root>/In2'
   */
  MultirateMulti_IntegOnlyF2S_set(rtU.In2);
}

The generated entry-point function for the slower sample rate (1/1000 second) includes rate transition code that does the following:

  1. For data integrity and determinism and data integrity only fast-to-slow data transfers, declares variables rtb_DetAndIntegF2S and rtbIntegOnlyF2S to represent persistent Rate Transition block output buffers.

  2. For data integrity and determinism and data integrity only fast-2-slow data transfers, calls functions MultirateMul_DetAndIntegF2S_get and MultirateMul_IntegOnlyF2S_get to read data from output buffers rtb_DetAndIntegF2S and rtbIntegOnlyF2S.

  3. Processes the algorithm subsystem code, updating input data for the discrete integrator by copying data in buffers rtb_DetAndIntegF2S, rtbIntegOnlyF2S, and rtU.In3[i] to rtDW.Integrator1_PREV_U[i], rtDW.Integrated2_PREV_U[i], and rtDW.Integrator3_PREV_U[i].

  4. For data integrity and determinism and data integrity only slow-to-fast data transfers, incorporates the signal conversion of the subsystem output by calling MultirateMul_DetAndIntegS2F_set and MultirateMul_IntegOnlyS2F_set.

cfile=fullfile(currentDir,...
    'MultirateMultitaskingRateTransitions_ert_rtw',...
    'MultirateMultitaskingRateTransitions.c');
coder.example.extractLines(cfile,'/* Model step function for TID1',...)
    'rtDW.Integrator1_SYSTEM_ENABLE = 0U;',1,0);
/* Model step function for TID1 */
void MultirateMultitaskingRateTransitions_step1(void) /* Sample time: [0.001s, 0.0s] */
{
  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;

  /* RateTransition: '<Root>/DetAndIntegF2S' */
  MultirateMul_DetAndIntegF2S_get(rtb_DetAndIntegF2S);

  /* RateTransition: '<Root>/IntegOnlyF2S' */
  MultirateMulti_IntegOnlyF2S_get(rtb_IntegOnlyF2S);

  /* FunctionCallGenerator: '<Root>/FcnCall Generator' incorporates:
   *  SubSystem: '<Root>/Algorithm'
   */
  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;

  /* DiscreteIntegrator: '<S1>/Integrator1' */
  tmp = 0.001 * (real_T)Algorithm_ELAPS_T;
  for (i = 0; i < 20; i++) {
    /* DiscreteIntegrator: '<S1>/Integrator1' */
    if (rtDW.Integrator1_SYSTEM_ENABLE == 0) {
      /* DiscreteIntegrator: '<S1>/Integrator1' */
      rtDW.Integrator1_DSTATE[i] += tmp * rtDW.Integrator1_PREV_U[i];
    }

    /* DiscreteIntegrator: '<S1>/Integrator2' */
    if (rtDW.Integrator2_SYSTEM_ENABLE == 0) {
      /* DiscreteIntegrator: '<S1>/Integrator2' */
      rtDW.Integrator2_DSTATE[i] += tmp * rtDW.Integrator2_PREV_U[i];
    }

    /* End of DiscreteIntegrator: '<S1>/Integrator2' */

    /* DiscreteIntegrator: '<S1>/Integrator3' */
    Integrator3_DSTATE = rtDW.Integrator3_DSTATE[i];
    if (rtDW.Integrator3_SYSTEM_ENABLE == 0) {
      /* DiscreteIntegrator: '<S1>/Integrator3' */
      Integrator3_DSTATE += tmp * rtDW.Integrator3_PREV_U[i];
    }

    /* DiscreteIntegrator: '<S1>/Integrator3' */
    rtDW.Integrator3_DSTATE[i] = Integrator3_DSTATE;

    /* SignalConversion generated from: '<S1>/Out3' */
    rtDW.OutportBufferForOut3[i] = Integrator3_DSTATE;

    /* Update for DiscreteIntegrator: '<S1>/Integrator1' */
    rtDW.Integrator1_PREV_U[i] = rtb_DetAndIntegF2S[i];

    /* Update for DiscreteIntegrator: '<S1>/Integrator2' */
    rtDW.Integrator2_PREV_U[i] = rtb_IntegOnlyF2S[i];

    /* Update for DiscreteIntegrator: '<S1>/Integrator3' incorporates:
     *  Inport: '<Root>/In3'
     *  RateTransition: '<Root>/NoneF2S'
     */
    rtDW.Integrator3_PREV_U[i] = rtU.In3[i];
  }

  /* Update for DiscreteIntegrator: '<S1>/Integrator1' */

See Also

Topics