Code Generation
As a separately licensed feature, PLECS can generate C code from a simulation model to facilitate real-time simulations. Code generation is subject to certain limitations, which are described in the first section of this chapter. The next two sections describe how the code generation capabilities are used within PLECS Standalone and PLECS Blockset, respectively.
Code Generation for Physical Systems
As described earlier in this manual, PLECS models physical systems using piecewise linear state-space equations that can be described using multiple sets of state-space matrices. For details see Physical Model Equations.
During normal simulations, PLECS calculates new sets of state-space matrices on the fly as the individual switching components change their states. This is not possible in the generated C code because the algorithms for calculating the matrices are proprietary and because the calculation would simply be too time consuming under real-time constraints.
When generating code for a physical model, PLECS therefore embeds the matrices for all combinations of switch states that it expects to encounter during the execution of a simulation run. In general this means that for a system with \(n\) switch elements \(2^n\) sets of state-space matrices are calculated and embedded into the generated C code. The actual number can be reduced by eliminating impossible combinations. For instance, the Triple Switch blocks internally consists of 3 switch elements but it still only accounts for 3 instead of \(2^3\) combinations because one and only one switch will conduct at any time. Even so, systems with many switches will lead to large source and executable files and long compile times.
Maximum Number of Switches
The number of ideal switch elements is limited to 16 or 32 per physical domain depending on the integer word size. This is due to the fact that the switch states of a physical domain are stored internally in a single unsigned integer variable. Note that some components, such as the Triple Switch, internally consist of more than one switch element.
Handling Naturally Commutated Devices
Switched physical models are difficult to handle in real-time simulations if the natural switching instants can occur between two time steps. This is the case for naturally commutated components where switching events are triggered by internal quantities of the physical model. Examples of such components are the diode (which turns on when the voltage becomes positive and turns off when the current becomes negative) or the mechanical friction components (which start slipping when the torque resp. force exceeds a certain level and become stuck when the speed becomes zero).
During normal simulations, PLECS handles such non-sampled switching events using an interpolation scheme (see Interpolation of Non-Sampled Switching Events). This is not practical under real-time constraints because the computation time required for the interpolation is several times larger than that of an ordinary simulation step. In real-time simulations, PLECS will therefore defer the switching to the immediately following time step. Note that this reduces the accuracy compared to a normal simulation.
Switching Algorithm
A further difficulty with naturally commutated devices is that their conduction state is usually influenced by the conduction states of other switches. During normal simulations, PLECS solves this problem by iteratively toggling the conduction states of naturally commutated switches within one simulation step until the boundary conditions of all switches are satisfied (see the description of the Switch Manager in section Physical Model Equations).
When generating code for a physical model, PLECS lets you choose between two switching algorithms, Iterative and Direct Look-up. You can specify the algorithm individually for each physical model using special Model Settings blocks that are connected to individual physical models, see Rotational Model Settings and Translational Model Settings. The default switching algorithm and the algorithm for all electrical systems is Direct Look-up.
- Iterative
PLECS generates code that implements an iterative switching method as described above. As a consequence of the iteration, simulation steps, in which a switching occurs, require more computation time than simulation steps without switching events. This is usually undesirable in real-time simulations because the longest execution time determines the feasible sample rate.
- Direct Look-up
Alternatively, PLECS can generate code that determines the proper switch conduction states directly as functions of the current physical model states and inputs and the gate signals of externally controlled switches. In order to generate these direct look-up functions, PLECS must analyze all possible transitions between all possible combinations of conduction states. This increases the computation time of the code generation process but yields nearly uniform execution times of simulation steps with or without switching events.
In order to reduce the number of possible combinations of switch conduction states and thus the code generation time and the code size, PLECS introduces the condition that naturally commutated devices (e.g. diodes or IGBTs) can only conduct if their current is non-zero. As a consequence, a diode may block even though the voltage is forward-biased if there is another blocking switch connected in series that prevents the current from flowing through the diode. This can produce unexpected voltage waveforms even though otherwise the model behaves correctly.
Consider the simple circuit shown below in Fig. 118. Two diodes are connected in series but opposing each other so that no current can flow regardless of the polarity of the source voltage:
Fig. 118 Simulation of a circuit with two opposing diodes
In the two graphs, the bold lines show the results from a normal simulation. When the source voltage is positive, D1 conducts and D2 blocks, and hence the voltage across D1 is zero and the voltage across D2 equals the negative source voltage. As the source voltage becomes negative, D1 block and D2 conducts, and accordingly the voltage across D1 equals the source voltage and the voltage across D2 is zero.
The dotted stairstep lines show the results from generated code using the iterative switching method. As can be seen, the diodes behave in the same way as in the normal simulation. In the generated code using the direct look-up method shown with continuous stairstep lines, however, both diodes block at all times because no current can ever flow through either of them. Accordingly, the source voltage always divides evenly across the two diodes.
Ideal and Non-Ideal Switch Models in Electric Circuits
PLECS includes two different switch modeling options when generating code for selected electrical switches.
- Ideal switch model
Ideal switches provide an ideal short or open circuit between its two electrical terminals. The ideal switch model adds one or more switching elements to the electrical system, increasing the total number of switching combinations and state-space matrices as described previously.
- Non-ideal switch model
A fixed-value resistor in parallel with a controlled current source represents the switching element. The state-space matrices do not change if a non-ideal switch is open or closed because the non-ideal switch resistance is constant. Therefore, non-ideal switches do not increase the total number of switching combinations and are suitable for models with large numbers of switches.
Each non-ideal switch includes an internal logic that models forced and natural commutation behavior. The switch state determines the controlled current source’s update rule. When the switch is closed, the current update rule drives the voltage across the switching element to zero. The update rule for an open switch drives the current through the device to zero.
The update rules do not result in an ideal short or open circuit. Rather, a closed non-ideal switch behaves like a small inductor and an open non-ideal switch a small capacitor with additional series damping elements. The non-ideal switch resistance and the discretization step size determine the effective inductance and capacitance of the switch. The Non-ideal switch resistance (code generation) parameter in the Simulation Parameters menu (see PLECS Blockset Parameters and PLECS Standalone Parameters) sets the resistance.
The non-zero impedance of an open-circuit non-ideal switch will result in a leakage current through the open switch. In AC systems the leakage current may be unacceptably large at the fundamental frequency. Certain electrical switches, like the Breaker component, offer the capability to increase the effective switch impedance at a defined frequency, thereby blocking a specific AC component of the current through the switch.
Unsupported Components
PLECS currently does not support code generation for the following components:
PLECS also does not support code generation for models that contain algebraic loops.
Code Generation with PLECS Standalone
PLECS Standalone produces C code in an embedded format, generating entry point functions that must be called from a main application. The following functions are generated:
void model_initialize(double time)This function should be called once at the beginning of a simulation to initialize the internal data structures and the start value of the global clock for components that depend on the absolute time.
void model_step()
void model_step(int task_id)This function should be called at every simulation step to advance the model by one step. The second form is used if the multi-tasking mode is enabled (see Scheduling) and the model has more than one task.
void model_output()
void model_output(int task_id)This function calculates the outputs of the current simulation step. It should be called at every simulation step before the
model_updatefunction. The second form is used if the multi-tasking mode is enabled.void model_update()
void model_update(int task_id)This function updates the internal states of the current simulation step. It should be called at every simulation step after the
model_outputfunction. The second form is used if the multi-tasking mode is enabled.void model_terminate()This function should be called at the end of a simulation to release resources that were acquired at the beginning of or during a simulation.
The prefix model is replaced by a model-specific string.
The model_output and model_update functions are only generated if the corresponding option is set in the target specific settings (see Target). In this case, the model_step function is not generated.
If a runtime error occurs during the execution of any of the three functions above, the variable const char * model_errorStatus points to a string with the error message. It is initialized with NULL.
Generating Code
To generate code, choose Coder options… from the Coder menu. This menu only appears if you have a license for the PLECS Coder.
Fig. 119 Coder Options dialog window
The left hand side of the dialog window shows a tree view of the model and the code-generation subsystem that it contains. Intermediate subsystems that have not been enabled for code generation appear as disabled entries that cannot be selected.
To enable a subsystem for code generation, select the subsystem, then choose Execution settings… from the Edit > Subsystem menu or the block’s context menu. In the Subsystem Settings dialog check the option Enable code generation. Note that it is not possible to enable code generation for a subsystem that is contained by or that itself contains other subsystems that enable code generation. Checking this option implicitly also checks the option Treat as atomic unit and unchecks the option Minimize occurrence of algebraic loops. For more information on these options see Virtual and Atomic Subsystems.
The right hand side of the dialog window shows a tabbed dialog with the code generation options for the system that is selected in the tree view. To generate code for the currently selected system, click on the Build button at the bottom of the right hand side.
Code generation can also be initiated in an Octave simulation script or via the RPC interface using the commands
plecs('codegen', 'path', optStruct, 'outputDir')
or
plecs.codegen('path', optStruct, 'outputDir')
respectively, where path is a model name or a subsystem path. The parameters optStruct and outputDir are optional.
If optStruct is provided, it is expected to be a struct as described in Scripted Simulation and Analysis Options. This enables you e.g. to generate code for different parameter values without having to modify the model file.
If outputDir is provided, the generated files will be placed in this folder instead of the folder that is specified in the model.
General
- Discretization method
This parameter specifies the algorithm used to discretize the physical model equations (see Physical Model Discretization).
- Floating point format
This parameter specifies the default data type (
floatordouble) that is used for floating point variables in the generated code.- Usage of absolute time
This setting allows you to specify the diagnostic action to be taken if PLECS generates code for a component that depends on the absolute time. In order to minimize round-off errors, PLECS generates code to calculate the absolute time using a signed 64-bit integer tick counter. If a simulation runs for an infinite time, this tick counter will eventually reach its maximum value, where it is halted to avoid problems that might occur if the counter was wrapped to the (negative) minimum value, such as a Step block resetting to its initial value. To put things into perspective, assuming a step size of 1 \(\mu\)s this would occur after 292,271 years.
Depending on this setting, PLECS will either ignore this condition or it will issue a warning or error message that indicates the components that use the absolute time.
- Base name
This parameter allows you to specify a custom prefix used to name the generated files and the exported symbols such as the interface functions or the input, output and parameter structs. By default, i.e. if you clear this field, the base name is derived from the model or subsystem name.
- Output directory
This parameter allows you to specify, where the generated files are stored. This can be an absolute path or a relative path with respect to the location of the model file. The default path is a directory
model_codegennext to the model file.
Parameter Inlining
These two settings specify how PLECS handles tunable parameters in the generated code.
- Default behavior
This setting specifies whether PLECS inlines the parameter values as numeric constants directly into the code (
Inline parameter values) or generates a data structure from which the values are read (Keep parameters tunable).Inlining parameter values reduces the code size and increases the execution speed. However, changing an inlined parameter value requires regenerating and recompiling the code. On the other hand, the values of tunable parameters can be changed at execution time without recompiling the code.
- Exceptions
For the components listed here, the opposite of the default behavior applies. If the default behavior is to inline all parameter values, the components listed here will keep their parameters tunable and vice versa. To add components to this list, simply drag them from the schematic into the list. Use the Remove
button to remove components from the list. To view the selected component in the schematic editor, click the Show component
button.
Note
Physical component parameters that affect the physical model equations, such as resistances or inductances, cannot be kept tunable, because changing such parameters in general requires a recalculation of the complete equation system. You can, however, keep the parameters of source blocks tunable.
Target
On this tab you can select a code generation target and configure target-specific settings. By default, only the Generic target is available. For information on how to install additional code generation targets, see Coder Configuration.
The Generic target has the following settings.
- Generate separate output and update functions
If you choose this option, the
model_stepfunction is replaced by the two functionsmodel_outputandmodel_update. Choose this option when you need access to the outputs as early as possible during task execution (e.g. to transfer the values to an analog or digital output, update a logger, start a DMA transfer, etc.).
Scheduling
- Tasking mode
This parameter allows you to choose between the single-tasking and multi-tasking modes.
- Discretization step size
This parameter specifies the base sample time of the generated code and is used to discretize the physical model equations (see Physical Model Discretization) and continuous state variables of control blocks.
- Task configuration
If you choose the multi-tasking mode, the dialog will show a table that lets you define a set of tasks. A task has a Task name and a Sample time that must be an integer multiple of the base sample time. The value
0is replaced with the base sample time itself. If the selected target supports multi-core processing, a task is also associated with a Core. If the selected target has multiple processors, a task is also associated with a CPU. The radio buttons in the Default column specify the default task (see below).Each task must have a unique name, and the core/sample time pairs must also be unique. Note that the task set must comprise a base task that is associated with the base sample time and core 0 (if applicable). For this reason, these columns in the first row are locked.
To assign a block or a group of blocks to a task, copy a Task Frame into the schematic, open the Task Frame dialog to choose the desired task, and drag the frame around the blocks. Blocks that are not enclosed by a Task Frame are scheduled in the default task.
Note that blocks do not need to have the same sample time as the task that they are assigned to; the block sample time can be continuous or an integer multiple of the task sample time.
- Thermal model task
In multi-tasking mode you can choose to execute all thermal model calculations in a dedicated task, typically on a separate core with a slower sample time in order to allow for the longer computation time for the calculation of switch losses. This asynchronous execution mode is supported only for power modules in
Sub-cycle averageconfiguration.To configure a dedicated thermal model task, select its name in the combo box. The default setting,
use native task, means that a thermal model is executed according to the Task Frame configuration synchronously with an associated electrical model.
External Mode
This tab is enabled only if you have selected a target that supports external mode operation and if the corresponding target setting is enabled. External mode operation enables you to
Capture data on a target device and show them in Scope, XY Plot and Display blocks in the model on the host computer.
Change values of tunable parameters (see Parameter Inlining) in the model on the host computer and upload the changed values to an application running on a target device.
Task Transitions in Multi-Tasking Mode
If a block in one task receives one or more input signals from a block in another task, PLECS automatically inserts code to ensure that the signal data is transferred in a safe manner.
Task Transitions on the Same Core
If the source task is faster than the destination task and the sample time of the destination task is an integer multiple of the sample time of the source task (i.e. if the destination task is executed at instants at which the source task is also executed), PLECS inserts code equivalent to a Zero Order Hold that operates with the slower sample time.
If the source task is slower than the destination task and the sample time of the source task is an integer multiple of the sample time of the destination task (i.e. if the source task is executed at instants at which the destination task is also executed), PLECS inserts code equivalent to a Delay that operates with the slower sample time.
In all other cases, PLECS uses a double buffer with a semaphore to transfer the data.
The insertion of a Zero Order Hold or a Delay ensures that data is always exchanged in a deterministic manner. The drawback is that it introduces latency. If this is not desired, you can insert a Task Transition block in front of the receiving block inside the destination task. This causes PLECS to transfer the data using a double buffer instead.
Task Transitions Between Different Cores
For task transitions between different cores, the write operation in the source task can occur simultaneously with the read operation in the destination task. PLECS uses a double buffer with two semaphores to guarantee that simultaneous read and write operations never access the same buffer.
Task Transitions Between Different CPUs
For task transitions between different CPUs, PLECS delegates the data transfer to external functions that must be provided by the target framework.
Simulating a Subsystem in CodeGen Mode
Enabling a subsystem for code generation also enables the Simulation Mode parameter in the Execution Settings dialog (see the Subsystem block). When this parameter is set to Normal, which is the default, the subsystem is simulated like a normal atomic subsystem. When the parameter is set to CodeGen, PLECS will automatically generate code for the subsystem and use the compiled code instead of the model representation when you start a simulation.
In connection with the “Traces” feature of the scopes (see Adding Traces), this allows you to easily verify the fidelity of the generated code against a normal simulation.
Code Generation with PLECS Blockset
Standalone Code Generation
PLECS Blockset can generate C code in the same format as PLECS Standalone, and you can choose to generate code for a complete Circuit block or for an individual subsystem. To generate code, choose Coder options… from the Coder menu. This menu only appears if you have a license for the PLECS Coder. For details on the coder options dialog please refer to the previous section Code Generation with PLECS Standalone.
Code generation can also be initiated via the MATLAB commands
plecs('codegen', path)
plecs('codegen', path, outputDir)
If outputDir is provided, the generated files will be placed in this folder instead of the folder that is specified in the model.
Integration with Simulink Coder
In addition, PLECS Blockset fully integrates with Simulink Coder (formerly Real-Time Workshop) to generate C code for your simulation model. Whenever you start a build process from within Simulink, PLECS automatically generates the code for a circuit block and inserts it at the appropriate places into the code generated by Simulink Coder.
Note
Scopes that are placed in PLECS schematics are not updated during a simulation using code generation. To view the simulation results, all scopes must be placed in the Simulink model.
Simulink Coder Options
The code generation options for the Simulink Coder are configured on the Simulink Coder pane of the PLECS simulation parameters.
- Code generation target
This parameter specifies the code generation target (see Code Generation Targets). The default,
auto, means that PLECS selects the target depending on the Simulink Coder target.- Inline circuit parameters for RSim target
Specifies for the RSim target whether component parameters should be evaluated at compile time and inlined into the code (
on) or evaluated at run time (off). See also Tunable Circuit Parameters in Rapid Simulations.- Generate license-free code (requires PLECS Coder license)
If this option is checked, PLECS will attempt to check-out a PLECS Coder license at build time and, if successful, will generate code for the RSim target that will run without requiring a PLECS license. Otherwise, the generated executable will require a PLECS license at run time.
- Show code generation progress
If this option is checked, PLECS opens a dialog window during code generation that shows the progress of the code generation process. You can abort the process by clicking the Cancel button or closing the dialog window.
Code Generation Targets
PLECS can generate code for two different Simulink Coder targets: the Rapid Simulation target (or RSim target) and the Real-Time target. These two targets are described in detail in the following two sections. The table below highlights the differences between the targets.
RSim Target |
Real-Time Target |
|
|---|---|---|
Purpose |
Rapid, non-real-time simulations. |
Real-time simulations. |
Technique |
A compressed description of the circuit schematic is embedded in the code and interpreted at run time. |
Signal and state-space equations are inlined as ANSI C code. |
Limitations |
None |
Limited support for naturally commutated devices and non-linear components. |
Inlining |
Parameters may be declared tunable, so that they are evaluated at run time. |
All parameters are inlined, i.e. evaluated at compile time and embedded into the generated code. |
Deployment |
Requires distribution of the PLECS RSim module. |
Generated code does not have external dependencies. |
Licensing |
If a PLECS Coder license is available at build time, the generated code will run without a license. Otherwise, a PLECS license is required at run time. |
Requires a PLECS Coder license at build time. |
By default, PLECS automatically selects the appropriate target depending on the target settings of Simulink Coder. To overrule this selection, open the PLECS simulation parameters, and on the Advanced pane change the setting Target to either RSim or RealTime.
Real-Time Target
The Real-Time Target is selected by default when you generate code using any of the real-time targets of Simulink Coder. Code generation for the Real-Time target requires a separate license for the PLECS Coder for PLECS Blockset.
For a detailed description of the code generation process for physical systems and its current limitations see Code Generation for Physical Systems.
Rapid Simulation Target
The RSim target is selected by default when you run a simulation using Simulink’s Rapid Accelerator mode or when you generate an executable using the RSim target or the S-Function target of Simulink Coder. The resulting code links against the RSim module of PLECS, a shared library which is part of the standard installation.
Deploying Rapid Simulation Executables
To deploy the generated executable you need to copy the appropriate shared library file onto the target computer. The following table lists the library files for the supported platforms.
Platform |
Library Files |
|---|---|
Windows 64-bit |
|
Mac Intel 64-bit |
|
Linux 64-bit |
|
The library file must be copied into the same directory as the executable. Alternatively, you can define the appropriate environment variable for your target computer such that it includes the directory where you have installed the library file.
Licensing Protocols for the PLECS RSim Module
Depending on the build settings the RSim module may check out a PLECS license for the duration of execution. It uses the environment variable PLEXIM_LICENSE_FILE to locate the license file. If the module is unable to check out a PLECS license, it issues an error message and stops the simulation.
Tunable Circuit Parameters in Rapid Simulations
By default, PLECS evaluates the parameters of all circuit components at compile time and inlines them into the circuit description. However, for certain applications - such as rapid simulations on different parameter sets or parameterized S-Functions - it is desirable that the parameters be evaluated at simulation start instead. This can be achieved by declaring the circuit parameters tunable.
To declare circuit parameters tunable,
Mask the PLECS Circuit block and define all parameters that you wish to keep tunable as mask variables. Mask variables can either be mask parameters (that appear in the parameter dialog) or variables defined in the mask initialization commands. For more information see Customizing the Circuit Block.
On the Advanced pane of the PLECS simulation parameters, uncheck the option Inline circuit parameters for RSim target.
Include the variable names in the list of tunable model parameters. Please see the Simulink Coder User’s Guide for details.
Limitations on Tunable Circuit Parameters
If you declare circuit parameters tunable, the RSim module uses its own parser to evaluate parameter expressions at simulation start; it currently cannot handle mask initialization commands. You will receive runtime errors if your circuit contains masked subsystems using mask initialization commands, or if a parameter expression contains a MATLAB function call.
Other limitations apply due to the way the Simulink Coder handles tunable parameters:
Circuit parameters must be double-precision, 2-dimensional, non-sparse arrays.
The first four characters of the parameter names must be unique.