Rate Transition Blocks Stijn van Dooren IDSC, ETH Zürich September 22, 2016 Introduction Every Simulink R block has a sample time, whether it is explicitly defined or inherited. Simulink R allows you to create models employing multiple sample times. Using the default solver settings, your model will use multitasking if it contains two or more different rates. In a multitasking environment, the code assigns each block a task identifier (TID) to associate it with the task that executes at its sample rate. The sample rate of any block must be an integer multiple of the base (i.e. the fastest) sample rate. Blocks with the fastest sample rates are executed by the task with the highest priority, the next slowest blocks are executed by a task with the next lower priority, and so on. Time available in between the processing of high priority tasks is used for processing lower priority tasks. Figure 1 shows a graphical representation of this task handling. There are two possible periodic sample rate transitions that can exist within a model: • A faster block driving a slower block • A slower block driving a faster block If the model is simulated in Simulink R , all tasks are executed directly after each other. This means that there are no real-time constraints and no computational delays. A real-time operating system (such as dSPACE R ’s MicroAutoBox) differs from a Simulink R simulation in that the program must execute the code synchronously with real time. Every calculation results in some computational delay, which can cause problems, such as task overruns or data corruption. Task overruns can (and must) be avoided by making your code more computationally efficient (which is, however, not the topic of this chapter). To prevent possible errors in calculated data, you must control model execution at sample rate transitions using Rate Transition blocks. This section describes the problems that can occur, the various options for the Rate Transition blocks, how they function and what is recommended. 1 High priority Low priority t0 t1 t2 t3 t4 t5 Sample time Task execution Task execution start or end Task preemption by a higher priority task Preemption or continuation Task execution pending t Figure 1: Multitasking task handling. Data Transfer Problems If a faster block drives a slower block, you must take into account that execution of the slower block may span more than one execution period of the faster block. This means that the outputs of the fast block may change before the slower block has finished computing its outputs. Conversely, if a slower block drives a faster block, the faster task may execute a second time before the slower task has completed execution. In both situations, input or output data may be corrupted, causing loss of data integrity. Figure 2 illustrates a situation where this problem arises (between t0 and t1). You must also take into account that the execution time may vary, see Figure 2. For example, if a slower block drives a faster block, two situations are possible. When the slower task finishes execution before the next sample time of the faster block, its output can be used immediately (at t3). On the other hand, when the execution of the slower task takes longer and is preempted by the faster task (at t1), its output should be used one sample time later (at t2). Moreover, the execution time of the faster task can vary (at t4). Thus, if the duration and variation of execution times are unknown, the timing of data transfer is not predictable, and the data transfer is said to be nondeterministic. 2 0.01 s 0.02 s t0 t1 t2 t3 t4 t5 t Figure 2: Nondeterministic data transfer with loss of data integrity. Arrows indicate data transfer with corrupted data. Transition Handling Options There are two options that can be enabled or disabled in the Block Parameters of the Rate Transition block: • Ensure data integrity during data transfer • Ensure deterministic data transfer After updating the diagram, a label appears on the Rate Transition block that indicates the operation mode. These are listed in Table 1 and described in much more detail in the next section. If both options are enabled, the operation modes are ZOH for fast-to-slow transitions and 1/z for slow-to-fast transitions. The latter introduces latency of one sample period of the slower task, which is a drawback of this choice of settings. At IDSC, we generally find it more desirable not to have an additional delay than to have deterministic data transfer, although it really depends on the application. Our general recommendation is to disable the second option. In this case, a Buf or Db buf operation mode is used. Finally, it goes without saying that data integrity should be ensured at all times. Table 1: Rate Transition block operation modes. Label ZOH 1/z Buf Db buf Copy NoOp Mixed Operation Acts as a zero-order hold Acts as a unit delay Copies input to output under semaphore control Copies input to output using double buffers Unprotected copy of input to output Does nothing Expands to multiple blocks with different behaviors 3 Rate Transition block operation modes This section explains the functionality of each mode in much detail. This is done by providing comprehensible illustrations and analyzing generated code. ZOH For fast-to-slow transitions, the Rate Transition block will operate as a zero-order hold (ZOH) when the following options are used: 3 Ensure data integrity during data transfer 3 Ensure deterministic data transfer After updating the Simulink R diagram, the Rate Transition block will appear as in Figure 3. The task handling and data transfer are illustrated in Figure 4. The calculations of the rate transition (RT) are shown in yellow. They are executed at the sample rate of the slower block, but with the priority of the faster block. The arrows indicate the data transfer from the faster to the slower task. This rate transition acts as a zero-order hold element, because the output data of every second execution of the faster block is not transferred. Consequently, there are no arrows shown for the preemption (e.g. between t1 and t2), in contrast to Figure 2. Thus, both data integrity and deterministic data transfer are ensured. double ZOH double 1 1 In Sample Time 0.01 Out Sample Time 0.02 Rate Transition Figure 3: ZOH Rate Transition block in Simulink. 0.01 s RT RT RT 0.02 s t0 t1 t2 t3 t4 t5 t Figure 4: Task handling and fast-to-slow data transfer using ZOH. The generated code for the Rate Transition block is shown in Listing 1. There are two interrupt service routines (ISR), one for each task identifier (TID). These correspond to the fast and slow task in Figure 4, including the rate transition calculations. In 4 the first ISR, a flag named TIDO_1 switches between 0 and 1, which is responsible for the ZOH behavior. When this flag equals 1, i.e. only after the first execution of the fast task, the data is transferred to a temporary variable named RateTransition. In the second ISR, i.e. for the slow task, this variable is used as an input. 1 2 3 4 5 6 7 8 9 /* Model step function for TID0 */ void modelName_step0(void) /* Sample time: [0.01s, 0.0s] */ { /* Update the flag to indicate when data transfers from * Sample time: [0.01s, 0.0s] to Sample time: [0.02s, 0.0s] */ (modelName_M->Timing.RateInteraction.TID0_1)++; if ((modelName_M->Timing.RateInteraction.TID0_1) > 1) { modelName_M->Timing.RateInteraction.TID0_1 = 0; } 10 /* RateTransition: ’<Root>/Rate Transition’ incorporates: * Inport: ’<Root>/In Sample Time 0.01’ */ if (modelName_M->Timing.RateInteraction.TID0_1 == 1) { modelName_B.RateTransition = modelName_U.InSampleTime001; } 11 12 13 14 15 16 17 /* End of RateTransition: ’<Root>/Rate Transition’ */ 18 19 } 20 21 22 23 24 25 26 /* Model step function for TID1 */ void modelName_step1(void) /* Sample time: [0.02s, 0.0s] */ { /* Outport: ’<Root>/Out Sample Time 0.02’ */ modelName_Y.OutSampleTime002 = modelName_B.RateTransition; } Listing 1: Generated code for ZOH rate transition. 1/z For slow-to-fast transitions, the Rate Transition block will operate as a unit delay (1/z) at the slower sample rate when the following options are used: 3 Ensure data integrity during data transfer 3 Ensure deterministic data transfer After updating the Simulink R diagram, the Rate Transition block will appear as in Figure 5. The task handling and data transfer are illustrated in Figure 6. The calculations of the rate transitions (RT) are shown in yellow. The arrows indicate the data transfer from the slower to the faster task. This rate transition acts as a 5 unit delay, because the output data of the slower task is only used in the next slower period. This results in deterministic data transfer. Furthermore, every second time that the faster task is executed, the same data as for the first execution is used. Therefore, no data is transferred during the preemption (e.g. at t1) and so data integrity is ensured. double 1/z double 1 1 In Sample Time 0.02 Out Sample Time 0.01 Rate Transition Figure 5: Unit delay Rate Transition block in Simulink. 0.01 s RT RT 0.02 s RT RT t0 t1 RT t2 t3 RT t4 t5 t Figure 6: Task handling and slow-to-fast data transfer using a unit delay. The generated code for the Rate Transition block is shown in Listing 2. It is very similar to the generated code for the ZOH block, see Listing 1. The flag TIDO_1 is used to update the input to the fast task only in the first execution. A temporary variable named RateTransition_Buffer0 is used to safely transfer the data from the slow to the fast task. 1 2 3 4 5 6 7 8 9 /* Model step function for TID0 */ void modelName_step0(void) /* Sample time: [0.01s, 0.0s] */ { /* Update the flag to indicate when data transfers from * Sample time: [0.01s, 0.0s] to Sample time: [0.02s, 0.0s] */ (modelName_M->Timing.RateInteraction.TID0_1)++; if ((modelName_M->Timing.RateInteraction.TID0_1) > 1) { modelName_M->Timing.RateInteraction.TID0_1 = 0; } 10 11 12 13 14 /* RateTransition: ’<Root>/Rate Transition’ */ if (modelName_M->Timing.RateInteraction.TID0_1 == 1) { /* Outport: ’<Root>/Out Sample Time 0.01’ */ modelName_Y.OutSampleTime001 = modelName_DW.RateTransition_Buffer0; 6 } 15 16 /* End of RateTransition: ’<Root>/Rate Transition’ */ 17 18 } 19 20 21 22 23 24 25 26 27 /* Model step function for TID1 */ void modelName_step1(void) /* Sample time: [0.02s, 0.0s] */ { /* Update for RateTransition: ’<Root>/Rate Transition’ incorporates: * Update for Inport: ’<Root>/In Sample Time 0.02’ */ modelName_DW.RateTransition_Buffer0 = modelName_U.InSampleTime002; } Listing 2: Generated code for unit delay rate transition. Buf For fast-to-slow transitions, the Rate Transition block will operate as a buffer (Buf) when the following options are used: 3 Ensure data integrity during data transfer Ensure deterministic data transfer After updating the Simulink R diagram, the Rate Transition block will appear as in Figure 7, where the small red numbers in the top-right corners display the execution order. Some simple calculations and an integrator are added to facilitate the explanation. The task handling and data transfer are illustrated in Figure 8. After each execution of the faster task, the output is copied to a buffer. Subsequently, the calculations of the slower task are started. The output of the integrator is calculated before the rate transition code is executed. If these calculations are preempted by the faster task, the data transfer (i.e. the rate transition) of the slower task will take place after the next faster task (e.g. at t5). Therefore, the data transfer is nondeterministic. double 1 In Sample Time 0.01 0:4 double 2 Gain 0:5 double Buf 0:6 double 0:7 double 0.5 double 0:0 double K Ts z-1 Gain1 Rate Transition 0:2 double 0:8 0:3 double 5 5 Constant Constant1 Discrete-Time Integrator Figure 7: Buffer Rate Transition block in Simulink. 7 10:1 Out Sample Time 0.02 As soon as the calculations before the rate transition are finished, the data is loaded from the buffer under semaphore [1] control, but only with respect to the calculations of the rate transition. This means that a preemption by the faster task may still take place, but the data is not saved into the buffer (e.g. at t3). As a result, data integrity is ensured. 0.01 s RT 0.02 s RT RT RT RT t0 RT RT t1 t2 t3 t4 t5 t Figure 8: Task handling and fast-to-slow data transfer using a buffer. The generated code for the Rate Transition block is shown in Listing 3. The calculations of the Sum, Gain and Constant blocks happen before and after the rate transition for the faster and slower task, respectively. While this is trivial, it can also be seen that the semaphore control only applies to the calculations of the rate transition (i.e. writing and reading the buffer). In the faster task, data is only written to the buffer if the semaphore is not taken, whereas in the slower task, the semaphore is only set while reading the buffer. Consequently, the buffer will often be filled unnecessarily (e.g. between t1 and t2). The calculations of the integrator, or, in general, of any block with some internal state(s), happen before the rate transition in the slower task. If these lines of code are interrupted, then the buffer is read one faster time step later. Therefore, the data transfer is non-deterministic. If, however, the slower task only contains algebraic blocks, then the buffer is read at the very beginning of the slower ISR, and one might argue that the data transfer is deterministic. But, even in that case the line of code that sets the semaphore (line 33) could be interrupted. 1 2 3 4 /* Model step function for TID0 */ void modelName_step0(void) /* Sample time: [0.01s, 0.0s] */ { real_T rtb_Sum; 5 6 7 8 9 10 /* Sum: ’<Root>/Sum’ incorporates: * Constant: ’<Root>/Constant’ * Gain: ’<Root>/Gain’ * Inport: ’<Root>/In Sample Time 0.01’ */ 8 rtb_Sum = modelName_P.Gain_Gain * modelName_U.InSampleTime001 + modelName_P.Constant_Value; 11 12 13 /* RateTransition: ’<Root>/Rate Transition’ */ if (!(modelName_DW.RateTransition_semaphoreTaken != 0)) { modelName_DW.RateTransition_Buffer0 = rtb_Sum; } 14 15 16 17 18 /* End of RateTransition: ’<Root>/Rate Transition’ */ 19 20 } 21 22 23 24 25 /* Model step function for TID1 */ void modelName_step1(void) /* Sample time: [0.02s, 0.0s] */ { real_T rtb_RateTransition; 26 /* Outport: ’<Root>/Out Sample Time 0.02’ incorporates: * DiscreteIntegrator: ’<Root>/Discrete-Time Integrator’ */ modelName_Y.OutSampleTime002 = modelName_DW.DiscreteTimeIntegrator_DSTATE; 27 28 29 30 31 /* RateTransition: ’<Root>/Rate Transition’ */ modelName_DW.RateTransition_semaphoreTaken = 1; rtb_RateTransition = modelName_DW.RateTransition_Buffer0; modelName_DW.RateTransition_semaphoreTaken = 0; 32 33 34 35 36 /* Update for DiscreteIntegrator: ’<Root>/Discrete-Time Integrator’ incorporates: * Constant: ’<Root>/Constant1’ * Gain: ’<Root>/Gain1’ * Sum: ’<Root>/Sum1’ */ modelName_DW.DiscreteTimeIntegrator_DSTATE += (modelName_P.Gain1_Gain * rtb_RateTransition - modelName_P.Constant1_Value) * modelName_P.DiscreteTimeIntegrator_gainval; 37 38 39 40 41 42 43 44 45 } Listing 3: Generated code for buffer rate transition. Db buf For slow-to-fast transitions, the Rate Transition block will operate as a double buffer (Db buf) when the following options are used: 3 Ensure data integrity during data transfer Ensure deterministic data transfer 9 After updating the Simulink R diagram, the Rate Transition block will appear as in Figure 9. The task handling and data transfer are illustrated in Figure 10. After each execution of the slower task, the data is written to one of two buffers. The faster task then reads the data from this buffer. In the meantime, new data from a subsequent execution of the slower task is safely written to another buffer. When this data transfer is finished, the buffer index is changed, and the new data can be used by the faster task. When this happens depends on the duration of the calculations (e.g. see Figure 10), so that the data transfer is not necessarily deterministic. However, the use of two buffers ensures data integrity. double Db_buf double 1 1 In Sample Time 0.02 Out Sample Time 0.01 Rate Transition Figure 9: Double buffer Rate Transition block in Simulink. 0.01 s 0.02 s RT t0 RT t1 t2 t3 RT t4 t5 t Figure 10: Task handling and slow-to-fast data transfer using a double buffer. The generated code for the Rate Transition block is shown in Listing 4. Suppose the buffer index ActiveBufIdx equals 0. Then, the input data for the faster task is read from the first buffer. After the slower task is completed, the data is written into the second buffer (ActiveBufIdx == 0 → true1 or 1) and the buffer index is set to 1 by using the same conditional statement. 1 2 3 4 5 6 7 8 9 /* Model step function for TID0 */ void modelName_step0(void) /* Sample time: [0.01s, 0.0s] */ { /* Outport: ’<Root>/Out Sample Time 0.01’ incorporates: * RateTransition: ’<Root>/Rate Transition’ */ modelName_Y.OutSampleTime001 = modelName_DW.RateTransition_Buffer[modelName_DW.RateTransition_ActiveBufIdx]; } 10 1 Originally, the Boolean data type was not defined in the C programming language. 10 11 12 13 14 15 16 17 18 19 20 21 /* Model step function for TID1 */ void modelName_step1(void) /* Sample time: [0.02s, 0.0s] */ { /* Update for RateTransition: ’<Root>/Rate Transition’ incorporates: * Update for Inport: ’<Root>/In Sample Time 0.02’ */ modelName_DW.RateTransition_Buffer[modelName_DW.RateTransition_ActiveBufIdx == 0] = modelName_U.InSampleTime002; modelName_DW.RateTransition_ActiveBufIdx = (int8_T) (modelName_DW.RateTransition_ActiveBufIdx == 0); } Listing 4: Generated code for double buffer rate transition. Copy and NoOp The Rate Transition block will just copy input to output (Copy or NoOp) when both options are disabled: Ensure data integrity during data transfer Ensure deterministic data transfer The task handling and data transfer are illustrated in Figure 2. As already mentioned in the section there, data integrity and deterministic data transfer are not ensured. The generated code for both the Copy and NoOp Rate Transition blocks is identical and is shown in Listing 5 for a fast-to-slow transition. 1 2 3 4 5 /* Model step function for TID0 */ void modelName_step0(void) /* Sample time: [0.01s, 0.0s] */ { /* (no output/update code required) */ } 6 7 8 9 10 11 12 13 14 /* Model step function for TID1 */ void modelName_step1(void) /* Sample time: [0.02s, 0.0s] */ { /* Outport: ’<Root>/Out Sample Time 0.02’ incorporates: * Inport: ’<Root>/In Sample Time 0.01’ */ modelName_Y.OutSampleTime002 = modelName_U.InSampleTime001; } Listing 5: Generated code for Copy and NoOp rate transition. 11 Mixed If the input and output to the Rate Transition block are vectors or buses with elements that differ in sample time, the Rate Transition block will expand to multiple blocks with different behaviors. An example is shown in Figure 11. double 1 In1 Sample Time 0.01 double sig1 Mixed double 2 In2 Sample Time 0.02 <sig1> 1 Out1 Sample Time 0.1 double sig2 Rate Transition <sig2> 2 Out2 Sample Time 0.01 Figure 11: Mixed Rate Transition block in Simulink. References [1] Wikipedia. Semaphore (programming). https://en.wikipedia.org/wiki/ Semaphore_(programming). Accessed: 2015-08-21. 12