| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- Continuous Time Simulation
- ==========================
- Given that continuous time simulation will always have to be discretized when
- executed, it is important to ask *how* this discretization happens. In the
- :doc:`SinGen` example, this was done by reducing the delta inbetween multiple
- steps. However, this may compute too often for what is required in a given
- simulation. Assume we have the following data (from a sine wave):
- .. figure:: ../_figures/stepsize/sine.png
- :width: 600
- Fixed Step Size
- ---------------
- With the previously discussed technique, the data could be plot using a fixed
- step size, where the new data is being computed every :code:`dt` time. The
- smaller this :code:`dt` value is, the more precise the plot. Below, the same
- function has been plot twice, for :code:`dt = 0.5` and :code:`dt = 0.1`, where
- the marked points on the plot highlight *when* the data has been recomputed. It
- is clear from these plots that a smaller step size identifies more accurate
- results.
- .. figure:: ../_figures/stepsize/sine-5.png
- :width: 600
- .. figure:: ../_figures/stepsize/sine-1.png
- :width: 600
- This behaviour is the default in the simulator. This can be explicitly set as follows
- (assuming :code:`sim` is the simulator object):
- .. code-block:: python
- sim.setDeltaT(0.5)
- This was done for academic reasons, as it is much easier to explain CBDs with a
- fixed step size, as compared to varying step sizes. By default, the :code:`dt` is
- set to 1.
- Manipulating the Clock
- ----------------------
- To maintain the block structure of the simulator, the simulation clock
- (see :class:`CBD.lib.std.Clock`) is implemented as an actual block. If this clock is
- not used in the model to simulate, the simulator will automatically add a fixed-rate
- clock, given the :code:`dt` information, as explained above. This can also be done
- manually via calling :func:`CBD.Core.CBD.addFixedRateClock`. The clock will actually
- be used to compute the simulation time. The :class:`CBD.lib.std.TimeBlock` outputs the
- current simulation time and can therefore be used to access the current time without
- the need for the actual clock. However, blocks that depend on the :code:`dt` value
- either need to be linked to a Clock block, or should have an input that yields the
- correct value; i.e., a :class:`CBD.lib.std.ConstantBlock`.
- Adaptive Step Size
- ------------------
- Adaptive step size (or variable step size) is a simulation method in which the delta
- changes throughout the simulation time. The clock-as-a-block structure allows the
- variation of the :code:`dt`, as is required for adaptive step size. This can be done
- manually by computing some simulation outputs, or via RK-preprocessing.
- The :class:`CBD.preprocessing.rungekutta.RKPreprocessor` transforms the original CBD
- model into a new block diagram that applies the Runge-Kutta algorithm with error
- estimation. The full family of Runge-Kutta algorithms can be used as long as they are
- representable in a Butcher tableau. Take a look at
- :class:`CBD.preprocessing.butcher.ButcherTableau` to see which algorithms are automatically
- included.
- For instance, to apply the Runge-Kutta Fehlberg method for 4th and 5th order to ensure
- adaptive step size of a CBD model called :code:`sinGen`, the following code can be used:
- .. code-block:: python
- from CBD.preprocessing.butcher import ButcherTableau as BT
- from CBD.preprocessing.rungekutta import RKPreprocessor
- tableau = BT.RKF45()
- RKP = RKPreprocessor(tableau, atol=2e-5, hmin=0.1, safety=.84)
- newModel = RKP.preprocess(sinGen)
- Notice how the :code:`preprocess` method returns a new model that must be used in the simulation.
- Make sure to refer to this model when reading output traces or changing constants (see
- :doc:`Dashboard`). Note that this will only work if one or more :code:`CBD.lib.std.IntegratorBlock`
- are used (otherwise, the original model will be returned). To obtain a block from the original
- model, the path :code:`RK.RK-K_0.block_name` should be used. However, it is perfectly possible there
- are multiple variations in the transformed model. Hence, it is highly encouraged to only read data
- from the output ports and not from blocks in the model itself. This is an unfortunate side-effect
- of "transforming" the model to comply to adaptive step size simulation.
|