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.
This example shows how to simplify modeling of vectorized algorithms. Using For Each subsystem blocks simplifies a model where three input signals are filtered by three identical Transfer Fcn blocks. This example also shows how to add more control to the filters by changing their coefficients for each iteration of the subsystem.
This model uses identical Transfer Fcn blocks to independently process each element of the input sine wave signal. A Vector Concatenate block concatenates the resulting output signals. This repetitive process is graphically complex and difficult to maintain. Also, adding another element to the signal requires significant reworking of the model.
You can simplify this model by replacing the repetitive operations with a single For Each Subsystem block.
The For Each subsystem contains a For Each block and a model representing the algorithm of the three blocks it replaces by way of the Transfer Fcn block. The For Each block specifies how to partition the input signal vector into individual elements and how to concatenate the processed signals to form the output signal vector. Every block that has a state maintains a separate set of states for each input element processed during a given execution step.
For this example, the input signal is selected for partitioning. The Partition Dimension and the Partition Width parameters on the For Each block are both set to 1 for the input.
You can scale up this approach to add more signals without having to change the model significantly. This approach is considered easily scalable and graphically simpler.
This example shows how to model parameter variation in an algorithm. It uses the For Each Subsystem partitioning model from Vectorize Algorithms Using For Each Subsystems and creates different filters for each input signal while retaining model simplicity. You do this by feeding an array of filter coefficients to the For Each subsystem as a mask parameter marked for partitioning. In each iteration of the For Each subsystem, a partition of the filter coefficients is fed to the Transfer Fcn block.
Open the model ex_ForEachSubsystem_Partitioningex_ForEachSubsystem_Partitioning. Create a mask for the For Each Subsystem block and add an editable mask parameter. Set the name to FilterCoeffs and the prompt to Filter Coefficient Matrix. For information on how to add a mask parameter, see Define mask parameters.
Open the For Each subsystem. Inside the subsystem, open the For Each block dialog box.
In the Parameter Partition tab, select the check box next to the FilterCoeffs parameter to enable partitioning of this parameter. Keep the Partition Width and Partition Dimension parameters at their default value of 1.
Double-click the For Each Subsystem block and enter your filter coefficient matrix, having one row of filter coefficients for each input signal. For example, enter [0.0284 0.2370 0.4692 0.2370 0.0284; -0.0651 0 0.8698 0 -0.0651; 0.0284 -0.2370 0.4692 -0.2370 0.0284] to implement different fourth-order filters for each input signal.
In the For Each subsystem, double-click the Transfer Fcn block and enter FilterCoeffs for the Denominator Coefficients parameter. This setting causes the block to get its coefficients from the mask parameter.
The For Each subsystem slices the input parameter into horizontal partitions of width 1, which is equivalent to one row of coefficients. The parameter of coefficients transforms from a single array:
into three rows of parameters:
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 inputs. 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 the same. 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 then 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 box 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 function has an input parameter NumIters that indicates the number of independent scalars that each For Each Subsystem is to processes. 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 block. Again, using the Build button to generate the code provides code reuse of a single function.
Inherited from the driving block