Repeatedly perform algorithm on each element or subarray of input signal and concatenate results
The For Each Subsystem block is useful in modeling scenarios where you need to repeat the same algorithm for individual elements (or subarrays) of an input signal. The set of blocks within the subsystem represents the algorithm applied to a single element (or subarray) of the original signal. The For Each block inside the subsystem allows you to configure the decomposition of the subsystem inputs into elements (or subarrays), and to configure the concatenation of the individual results into output signals.
Inside this subsystem, each block that has states maintains separate sets of states for each element or subarray that it processes. Consequently, the operation of this subsystem is similar in behavior to copying the contents of the subsystem for each element in the original input signal and then processing each element using its respective copy of the subsystem.
An additional benefit of the For Each Subsystem is that, for certain models, it improves the code reuse in Simulink® Coder™ generated code. Consider a model containing two reusable Atomic Subsystems with the same scalar algorithm applied to each element of the signal. If the input signal dimensions of these subsystems are different, Simulink Coder generated code includes two distinct functions. You can replace these two subsystems with two identical For Each Subsystems that are configured to process each element of their respective inputs using the same algorithm. For this case, Simulink Coder generated code consists of a single function parameterized by the number of input signal elements. This function is invoked twice — once for each unique instance of the For Each Subsystem in the model. For each of these cases, the input signal elements have different values.
The For Each Subsystem block has these limitations, which you can work around.
|You cannot log any signals in the subsystem.||Pull the signal outside the subsystem using an output port for logging.|
|You cannot log the states of the blocks in the model in array format. Also, you cannot log the states of the blocks in the subsystem, even if you are using structure format.||Save and restore the simulation state (SimState).|
|Reusable code is generated for two For Each Subsystems with identical contents if their input and output signals are vectors ( 1-D or 2-D row or column vector). For n-D input and output signals, reusable code is generated only when the dimension along which the signal is partitioned is the highest dimension.||Permute the signal dimensions to transform the partition dimension and the concatenation dimension to the highest nonsingleton dimension for n-D signals.|
The For Each Subsystem block does not support the following features:
You cannot include the following blocks or S-functions inside a For Each Subsystem:
Data Store Memory, Data Store Read, or Data Store Write blocks inside the subsystem
The From Workspace block if the input is a Structure with Time that has an empty time field.
The To Workspace and To File data saving blocks
Model Reference block with simulation mode set to 'Normal'
For a complete list of the blocks that support the For Each Subsystem, type showblockdatatypetable at the MATLAB® command line.
You cannot use the following kinds of signals:
Test-pointed signals or signals with an external storage class inside the system
Frame signals on subsystem input and output boundaries
Function-call signals crossing the boundaries of the subsystem
Creation of a linearization point inside the subsystem
Setting the initial state of blocks inside the model if the format of the data is in either of the following formats:
Structure that includes data for a block inside of the For Each subsystem
Propagating the Jacobian flag for the blocks inside the subsystem. You can check this condition in MATLAB using J.Mi.BlockAnalyticFlags.jacobian, where J is the Jacobian object. To verify the correctness of the Jacobian of the For Each Subsystem, perform the following steps
Look at the tag of the For Each Subsystem Jacobian. If it is "not_supported", then the Jacobian is incorrect.
Move each block out of the For Each Subsystem and calculate its Jacobian. If any block is "not_supported" or has a warning tag, the For Each Subsystem Jacobian is incorrect.
You cannot perform the following kinds of code generation:
Generation of a Simulink Coder S-function target
Simulink Coder code generation under both of the following conditions:
A Stateflow® or MATLAB Function block resides in the subsystem.
This block tries to access global data outside the subsystem, such as Data Store Memory blocks or Simulink.Signal objects of ExportedGlobal storage class.
HDL code generation
PLC code generation
The For Each Subsystem block supports both C-MEX S-functions and Level-2 MATLAB S-functions, provided that the S-function supports multiple execution instances using one of the following techniques:
A C-MEX S-function must declare ssSupportsMultipleExecInstances(S, true) in the mdlSetWorkWidths method.
A Level-2 MATLAB S-function must declare 'block.SupportsMultipleExecInstances = true' in the Setup method.
If you use the above specifications:
Do not cache run-time data, such as DWork and Block I/O, using global or persistent variables or within the userdata of the S-function.
Every S-function execution method from mdlStart up to mdlTerminate is called once for each element processed by the S-function, when it is in a For Each Subsystem. Consequently, you need to be careful not to free the same memory on repeated calls to mdlTerminate. For example, consider a C-MEX S-function that allocates memory for a run-time parameter within mdlSetWorkWidths. The memory only needs to be freed once in mdlTerminate. As a solution, set the pointer to be empty after the first call to mdlTerminate.
The For Each Subsystem block accepts real or complex signals of the following data types:
For more information, see Data Types Supported by Simulink in the Simulink documentation.
The following model uses an FIR filter to independently process each element of the input sine wave signal, in an identical manner. The model uses Selector blocks and three identical subsystems: Subsystem, Subsystem1, and Subsystem2. A Vector Concatenate block concatenates the resulting vectors. This repetitive process is graphically complex and difficult to maintain. Also, adding another element to the signal requires a significant rework of the model.
Each subsystem contains an identical FIR filter that accepts a different set of input coefficients. For example, Subsystem2 contains the following blocks:
You can simplify this model by replacing the repetitive operations with a single For Each Subsystem block.
This subsystem contains a For Each block and a model representing the identical algorithm of the three subsystems that it replaces. The For Each block specifies how to partition the input signal into individual elements and how to concatenate the processed signals to form output signals. Also, every block that has state maintains a separate set of states for each input element processed during a given execution step.
For this example, both the input signal and the input coefficients are selected for partitioning. The partition dimension and the partition width are both set to 1 for both inputs.
Therefore, the For Each block slices the input signals into horizontal partitions of width 1. The input signal of coefficients transforms from a single array,
into three signals,
To match the output signal dimension to the input signal dimension, set the concatenation dimension equal to the partition dimension. (The output signal dimension and the input signal dimension do not have to match, but matching them makes it easier to compare the input and output.)
The intent is for the three subsystems — Vector SS1, Vector SS2, and Vector SS3 — to apply the same processing to each scalar element of the vector signal at their respective input. Because these three subsystems perform the same processing, it is desirable for them to produce a single shared Output (and Update) function for all three subsystems in the code generated for this model. For example, the Vector SS3 subsystem contains the following blocks:
To generate a single shared function for the three subsystems, the configuration of the partitioning they perform on their input signals must be identical. For Vector SS1 and Vector SS3, this configuration is straightforward because you can set the partition dimension and width to 1. However, in order for Vector SS2 to also partition its input signal along dimension 1, you must insert a Math Function block to transpose the 1-by-8 row vector into an 8-by-1 column vector. You can subsequently convert the output of the subsystem back to a 1-by-8 row vector using a second Math Function block set to the transpose operator.
If you use the Build button on the Code Generation pane of the Configuration Parameters dialog to generate code, the resulting code uses a single Output function. This function is shared by all three For Each Subsystem instances.
/* * Output and update for iterator system: * '<Root>/Vector SS1' * '<Root>/Vector SS2' * '<Root>/Vector SS3' */ void VectorProcessing(int32_T NumIters, const real_T rtu_In1, real_T rty_Out1, rtDW_VectorProcessing *localDW)
The functions has an input parameter NumIters that indicates the number of independent scalars which each For Each Subsystem is to process. This function is called three times with the parameter NumIters set to 10, 8, and 7 respectively.
The remaining two subsystems in this model show how reusable code can also be generated for matrix signals that are processed using the For Each Subsystem. Once again, a Build provides code reuse of a single function.
Inherited from the driving block