Generating Code for Export
Setting Up the Model for Export in MapleSim
Exported Code Flowchart
Intermediate Step Handling
MapleSim provides a variety of ways to obtain and run stand-alone C code. Access to the basic C code, and the ability to compile and run it in Maple, is available in the core product. Extensions of this code are available for a variety of software tools as additional Connector toolboxes. Although the final target for the C code may differ, the fundamental structure of the exported code is the same. The goal of this document is to provide a high-level overview of the code export process and its associated options.
For details generating C code using the Code Generation app, see Generating and Exporting C Code from a Model in Chapter 5 of the MapleSim User's Guide. For information on the API command to generate C code from a model, see MapleSim[LinkModel][GetCompiledProc].
The basic structure for exporting models is the subsystem. This defines the signals that are input and output from the generated code (Figure 1). When generating code for a subsystem, any included ports must be real input or real output ports. The slight exception to this rule concerns generating code for the top-level system. In this case, the system is considered to have no inputs, but all probed values are considered outputs (Figure 2).
In addition to inputs and outputs, generated code may have user-modifiable parameters defined for it. By default, not all parameters are selected to be modifiable in the exported code. In general, the fewer parameters left modifiable, the less time it will take to generate the code and the faster the exported code will run. By default, only parameters defined on the subsystem being exported are selected to be modifiable in the generated code. For example, if generating code for the RLC subsystem in Figure 3, only the parameters R, L, and C will default to being modifiable in the exported code.
It is important to note that not all parameters may be selected as modifiable in the generated code. Parameters that change the structure of the equations (for example, add or remove variables from the system) are automatically removed from the list of parameters that can be exported. This is true even if the parameters are defined on the exported subsystem.
MapleSim’s exported code performs a simplified version of the initializations done directly in MapleSim. Specifically, it requires an initial, consistent set of initial conditions from which it can move to the requested initial conditions. Since MapleSim’s exported code obtains its initial conditions from an initialized MapleSim model, it follows that code may only be exported for subsystems that are part of a model that can be simulated (or, at least, initialized). If you are unable to run or initialize your model in MapleSim, you will not be able to export code for that model or any of its subsystems. It also follows that any direct effects of parameters on initial conditions are ignored in the exported code, since the exported set of consistent initial conditions are purely numeric values.
The flowchart in Figure 4 outlines the basic integration scheme used by MapleSim’s exported fixed-step solvers. When code is exported without an embedded solver this integration scheme may be slightly different. However, regardless of how the overall integration is handled, the handling of Constraint Projection and the Event Iterations is performed essentially as shown in the diagram.
Integrating a set of differential-algebraic equations (DAEs) with standard ordinary differential equation (ODE) integrators requires some mechanism of ensuring the algebraic constraints are satisfied throughout the integration. One method of doing this is called constraint projection.
As its name suggests, constraint projection "projects" the computed ODE solution back onto the constraint manifold using a relaxed Newton projection. Several projection iterations may be required to satisfy the constraints. Each projection iteration brings the solution closer to the constraint manifold. The process ends when the desired accuracy is achieved or some other exit condition is met. MapleSim allows two options to control how constraint projection is performed in the exported code:
coniter — the maximum allowed number of constraint projection iterations. The value of coniter can be reduced to make the solution process faster, but less accurate.
contol — the maximum allowed (normalized) constraint error. Increasing the value of contol can allow for systems with particularly sensitive constraints (or large fixed-time steps) to simulate, but will result in less accurate simulations.
Unlike constraint projection, constraint stabilization does not directly enforce the algebraic constraints during the simulation. The advantage to this approach is that you are solving a pure set of ODEs rather than DAEs—skipping the time required to perform costly projections. This can result in significant speed increases in the code execution. The disadvantage of this approach is that you may have constraint drift (since the constraints are not directly solved), the system being solved is not identical to the original system (it’s modified to include the stabilization), and most constraint stabilization techniques require additional, non-physical, parameters to be set.
In MapleSim, you have the option of applying Baumgarte constraint stabilization to any exported code. This method is essentially equivalent to adding proportional-derivative (PD) control on the constraint error during integration. This option is specified as follows:
baumgarte — a list containing the derivative (alpha) and proportional (beta) gains applied to the constraint error during simulation in the form [alpha, beta].
Baumgarte constraint stabilization can be used in together with constraint projection. This can sometimes reduce the number of required projection iterations.
An event is a continuous condition that can trigger a change in the system’s discrete variables. In MapleSim, event triggers are represented as expressions that change sign (go from positive to negative or vice versa) to indicate that an event has occurred. For this reason, they are sometimes referred to as zero-crossings.
After an event has been detected, the system enters what is referred to as an "event iteration loop." Here, the continuous and discrete states can repeatedly update one another until a steady-state is reached. More specifically, re-evaluating the continuous states with updated discrete states can change the continuous states, resulting in a subsequent change to the discrete states. This process continues until the discrete and continuous states stop changing or some other exit condition is met.
Event handling in MapleSim’s internal engine is a complicated process that involves a variety of heuristics and algorithms. A simplified version of this event handling is embedded in MapleSim’s exported C code and is shown in the box labeled "Event Iteration" in Figure 4.
MapleSim provides three options to control the event iteration process in the exported code:
evtiter — controls the maximum number of event iterations allowed before the integrator throws an error. This value is required as it is possible to construct a faulty model for which event iteration does not terminate.
evthyst — controls the width of the event hysteresis band used for events. Setting this to a larger value can speed up simulation by ignoring repeated "touch-conditions" (the event is triggered, but the discrete variable does not change) or chatter (bouncing back and forth between different event triggers), at the risk of missing events. Setting this to a value of zero disables hysteresis entirely.
evtproj — specifies whether constraint projection should occur during the event iteration. Specifying 'false' will result in a faster integration, but may cause an event failure or integration failure (if the events significantly change the solution so that the constraint projection one step later cannot compensate).
When errors occur during the execution of the exported code, execution is halted and an error message indicating the category of execution failure is reported. A summary of these messages is given in .
index-1 variable/derivative evaluation failure
event iteration limit is exceeded
an undefined value is encountered during event processing
fatal constraint projection failure
invalid configuration (or encountered terminate)
However, some export targets have additional options that allow for extended error handling. In these cases the code can allow execution to continue, recovering from the errors in the following ways:
If error code 1 is encountered (externally triggered), the code immediately reinitializes, and proceeds with normal execution.
If error codes 2, 4, 5, or 6 are encountered, the code will either immediately reinitialize (going back to a consistent, error-free state) and proceed with normal execution, or it will hold the last error-free state (until a manual reinitialization is triggered). Choosing to hold the last state or immediately reinitialize is a user-defined option.
If error code 3 is encountered, the code will try and select the lowest energy-level solution (computed as the 2-norm of the index-1 variables) from the last three event iterations. The error code reported will be -3, indicating that a full reinitialization was not performed.
When using the extended error handling options, the code will automatically add an input to allow the triggering of a reinitialization of the code, as well as an output indicating which error codes (if any) were encountered during code execution.
Generally, when integrating with a fixed-step solver, all events (or zero-crossings) are processed at the end of the step in which they are encountered. This differs from variable-step solvers which adjust the integrator’s step-size in order to ensure that events are processed at the precise time the event is triggered.
Depending on the sensitivity of the system and the size of the fixed-step, this delay in the event processing can result in highly inaccurate simulation results. It can also lead to problems during the overall event handling that can cause the code to enter invalid system configurations, halting code execution.
Some MapleSim targets allow fixed-step code to be generated with an option to perform "intermediate steps" between the fixed-step integrators time steps in order to more accurately manage the event execution.
The "Intermediate Step Handling" block (the green block in Figure 4) shows how this approach works. Essentially, it allows the integrator to approximate where events occur between steps. Consider a fixed time step with events occurring as shown:
If intermediate steps are not used, events A, B, and C will be processed at t+dt (the end of the step). However, with intermediate steps, the exported code will take an internal step at the approximate time of event A. If event B is close enough to event A (within the tolerance specified by the option), the internal step will instead be taken at the approximate time of event B. After completing the event iteration for this internal step, the algorithm will again check if there are any remaining events before t+dt.
In this case, the events fired in the first intermediate step have resulted in a new zero-crossing occurring prior to the end of the step. Assuming more than two intermediate steps are allowed, the algorithm will now take an internal step from ti to the approximated time of event D.
This process will continue until no more events are found between the last intermediate step and the t+dt, or the number of intermediate steps has been exceeded.
Generating and Exporting C Code from a Model in Chapter 5 of the MapleSim User's Guide
Download Help Document