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:
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.For data integrity and determinism and data integrity only slow-to-fast data transfers, calls functions
MultirateMul_DetAndIntegS2F_get
andMultirateMul_IntegOnlyS2F_get
to read data from internal buffersrtY.Out
andrtY.Out2
.For slow-to-fast data transfers for which no Rate Transition code exists, calls
memcpy
to copy data to output bufferrtDW.OutportBufferForOut3
.For data integrity and determinism and data integrity only fast-to-slow data transfers, calls functions
MultirateMul_DetAndIntegF2S_set
andMultirateMul_IntegOnlyF2S_set
to write data to internal buffersrtU.In1
andrtU.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:
For data integrity and determinism and data integrity only fast-to-slow data transfers, declares variables
rtb_DetAndIntegF2S
andrtbIntegOnlyF2S
to represent persistent Rate Transition block output buffers.For data integrity and determinism and data integrity only fast-2-slow data transfers, calls functions
MultirateMul_DetAndIntegF2S_get
andMultirateMul_IntegOnlyF2S_get
to read data from output buffersrtb_DetAndIntegF2S
andrtbIntegOnlyF2S
.Processes the algorithm subsystem code, updating input data for the discrete integrator by copying data in buffers
rtb_DetAndIntegF2S
,rtbIntegOnlyF2S
, andrtU.In3[i]
tortDW.Integrator1_PREV_U[i]
,rtDW.Integrated2_PREV_U[i]
, andrtDW.Integrator3_PREV_U[i]
.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
andMultirateMul_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' */