States and Events
The role of continuous-time states and event handling are important aspects of modeling. How this is handled in System Modeler is described in the following, along with a few general things to keep in mind when working with System Modeler.
States
In System Modeler, a state is a variable that has been selected by System Modeler to be calculated by numerical integration. For this to happen, System Modeler must have an equation for the derivative of the variable. However, not all variables where the derivative occurs in the model become states. For simulation stability purposes, System Modeler chooses a certain number of variables to be states. These variables can, in some sense, be viewed as the variables that drive the simulation.
The variables that do occur differentiated but are not selected as states will have their actual values calculated through other means than numerical integration. System Modeler can also, during the translation of the model, introduce new derivatives that were not present in the original model, and it is possible that the newly differentiated variables will be chosen as states.
System Modeler uses a technique called index reduction to obtain ordinary differential equations that can be integrated using well-established numerical methods. This involves differentiating a select set of equations. Which equations are differentiated can be seen by turning on the logging of index reduction in the Options under Translation. You can also turn on the logging of the selected states in the same window. The index reduction log and selected states log can be seen in the Build Log tab in Simulation Center.
Dynamic State Selection
Sometimes System Modeler is not able to find a suitable set of states during the model translation. In that case, it will select a couple of candidate states and will decide during simulation time which variable should be a state. This means that one state can be used for some part of the simulation and another state for another part of the simulation. This is called dynamic state selection. The candidate variables that dynamic state selection can choose between are called dynamic states, and states that are not dynamic are called static states.
For some models, dynamic state selection is necessary; an example is the model Pendulum. For other models, System Modeler might use dynamic state selection even though it is not necessary. For such models, you can give System Modeler a hint about what to pick with the stateSelect attribute explained in the following.
model Pendulum
parameter Real m = 1;
parameter Real L = 1;
parameter Real g = 9.82;
Real vx;
Real vy;
Real F;
Real x(start = L / sqrt(2));
Real y(start = L / sqrt(2));
equation
m * der(vx) = -(x / L) * F;
m * der(vy) = -(y / L) * F - m * g;
x * x + y * y = L * L;
der(x) = vx;
der(y) = vy;
end Pendulum;
If you have logging of selected states turned on, the log will include the dynamic state candidates separately from the static states and will tell you how many actual states are chosen from the candidates. In the Pendulum model, System Modeler selects one state from the candidates vy and vx and one state from the candidates y and x.
If you turn on the Debug Output for Dynamic state changes in the Simulation Center options, you can see when the model switches states during simulation. The messages are printed in the Simulation Log tab. You can see that the states selected for the model Pendulum switch several times during a 10-second simulation.
StateSelect Attribute
If you know a certain variable would be good as a static state, you can add stateSelect=StateSelect.always as a modifier to the variable declaration. This will make System Modeler select this variable as a static state without doing some checks. In the model ForceState, System Modeler needs to select one state and StateSelect.always is used to force System Modeler to select x.
model ForceState
Real x(stateSelect = StateSelect.always);
Real y;
initial equation
y = 1.0;
equation
x - y = sin(time);
der(x) + der(y) = 1.0;
end ForceState;
You can also add stateSelect=StateSelect.prefer to give System Modeler a hint that some variable probably would be a good state. It can also be used to trim down dynamic state candidates. If you have a model utilizing dynamic state selection, but it selects from a too large a set of candidates, you can make the set smaller by setting StateSelect.prefer on the variables it should choose from.
Reinit Operator
The reinit operator can be used inside a when equation to change the value of a state when the when condition occurs. A simple example is shown in the model Sawtooth. Because the variable being reinitialized needs to be a state, such a variable has an implicit setting of StateSelect.always.
model Sawtooth
Real x;
initial equation
x = 0.0;
equation
der(x) = 1.0;
when sample(1.0, 1.0) then
reinit(x, 0.0);
end when;
end Sawtooth;
Events
An event is generated during simulation, for example, when the Boolean expression of an if equation changes its value. When an event occurs, the solver stops and iterates to find the exact point in time of the event. These iterations can take some time and it is advised to try to minimize them if possible.
One method to avoid unnecessary iterations is to use the built-in operator noEvent in order to give a hint to the solver that event generation is not needed.
model EventTest
Real x1;
Real x2;
equation
x1 = if time < 3 then time else 3 "Event generated at time = 3";
x2 = noEvent(if time < 5 then 4 else 5) "No event generated at time = 5";
annotation(experiment(Interval = 2));
end EventTest;
The noEvent operator can also be used to protect against illegal evaluation. In the following example, sin(x)/x is calculated. To guard against division by zero, noEvent is used around abs(x)>0 to make sure that sin(x)/x is not evaluated if x=0.
model GuardEval
Real x;
Real y;
equation
x = time - 1;
y = if noEvent(abs(x) > 0) then sin(x) / x else 1;
end GuardEval;
General Advice
Following is a collection of general tips that may prove useful to avoid some common problems.
- Debugging equation-based languages is a different task compared to algorithm-based languages, since it is not possible to add break points, solve step by step, etc. Therefore, try to build up your model step by step, i.e. make small tests of partial systems of your complete model. If an error occurs, it will be a lot easier to locate if the model is small.
- Use the Validate Class feature, described here, when creating components. If a component validation is successful, it is more likely that the component will work together with other components. A complete component should always return an equal number of variables and equations from the validation. Note that a partial model naturally often returns a different number of equations than variables.
- If a simulation takes a long time, it could be due to a large number of events. The number of events can be found in the simulation log after a simulation is finished. If possible, try to reduce the number of events by using the noEvent operator (see preceding explanation) or try to change your model. Note that when modeling sampled systems, an event is generated at each sample time, which is normal.
- Try to avoid the simulation output setting All solver steps when simulating a well-known system, as this setting could drastically reduce the simulation performance for larger systems. When the model behavior is known, it is recommended to use the Interval length or Number of intervals settings instead.