ContinuousTime.rst 4.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. Continuous Time Simulation
  2. ==========================
  3. Given that continuous time simulation will always have to be discretized when
  4. executed, it is important to ask *how* this discretization happens. In the
  5. :doc:`SinGen` example, this was done by reducing the delta inbetween multiple
  6. steps. However, this may compute too often for what is required in a given
  7. simulation. Assume we have the following data (from a sine wave):
  8. .. figure:: ../_figures/stepsize/sine.png
  9. :width: 600
  10. Fixed Step Size
  11. ---------------
  12. With the previously discussed technique, the data could be plot using a fixed
  13. step size, where the new data is being computed every :code:`dt` time. The
  14. smaller this :code:`dt` value is, the more precise the plot. Below, the same
  15. function has been plot twice, for :code:`dt = 0.5` and :code:`dt = 0.1`, where
  16. the marked points on the plot highlight *when* the data has been recomputed. It
  17. is clear from these plots that a smaller step size identifies more accurate
  18. results.
  19. .. figure:: ../_figures/stepsize/sine-5.png
  20. :width: 600
  21. .. figure:: ../_figures/stepsize/sine-1.png
  22. :width: 600
  23. This behaviour is the default in the simulator. This can be explicitly set as follows
  24. (assuming :code:`sim` is the simulator object):
  25. .. code-block:: python
  26. sim.setDeltaT(0.5)
  27. This was done for academic reasons, as it is much easier to explain CBDs with a
  28. fixed step size, as compared to varying step sizes. By default, the :code:`dt` is
  29. set to 1.
  30. Manipulating the Clock
  31. ----------------------
  32. To maintain the block structure of the simulator, the simulation clock
  33. (see :class:`CBD.lib.std.Clock`) is implemented as an actual block. If this clock is
  34. not used in the model to simulate, the simulator will automatically add a fixed-rate
  35. clock, given the :code:`dt` information, as explained above. This can also be done
  36. manually via calling :func:`CBD.Core.CBD.addFixedRateClock`. The clock will actually
  37. be used to compute the simulation time. The :class:`CBD.lib.std.TimeBlock` outputs the
  38. current simulation time and can therefore be used to access the current time without
  39. the need for the actual clock. However, blocks that depend on the :code:`dt` value
  40. either need to be linked to a Clock block, or should have an input that yields the
  41. correct value; i.e., a :class:`CBD.lib.std.ConstantBlock`.
  42. Adaptive Step Size
  43. ------------------
  44. Adaptive step size (or variable step size) is a simulation method in which the delta
  45. changes throughout the simulation time. The clock-as-a-block structure allows the
  46. variation of the :code:`dt`, as is required for adaptive step size. This can be done
  47. manually by computing some simulation outputs, or via RK-preprocessing.
  48. .. note::
  49. Runge-Kutta preprocessing is only available if there are one or more instances of
  50. :class:`CBD.lib.std.IntegratorBlock` in the original model. Also make sure not to
  51. use a flattened model to prevent errors.
  52. The :class:`CBD.preprocessing.rungekutta.RKPreprocessor` transforms the original CBD
  53. model into a new block diagram that applies the Runge-Kutta algorithm with error
  54. estimation. The full family of Runge-Kutta algorithms can be used as long as they are
  55. representable in a Butcher tableau. Take a look at
  56. :class:`CBD.preprocessing.butcher.ButcherTableau` to see which algorithms are automatically
  57. included.
  58. For instance, to apply the Runge-Kutta Fehlberg method for 4th and 5th order to ensure
  59. adaptive step size of a CBD model called :code:`sinGen`, the following code can be used:
  60. .. code-block:: python
  61. from CBD.preprocessing.butcher import ButcherTableau as BT
  62. from CBD.preprocessing.rungekutta import RKPreprocessor
  63. # Add a clock to the model, or RK will not work, 1e-4 is the starting delta
  64. sinGen.addFixedRateClock("clock", 1e-4)
  65. tableau = BT.RKF45()
  66. RKP = RKPreprocessor(tableau, atol=2e-5, hmin=0.1, safety=.84)
  67. newModel = RKP.preprocess(oldModel)
  68. .. warning::
  69. Notice how the :code:`preprocess` method returns a new model that must be used in the simulation.
  70. Make sure to refer to this model when reading output traces or changing constants (see also
  71. :doc:`Dashboard`).
  72. .. warning::
  73. To obtain a block from the original model, the path :code:`RK.RK-K_0.block_name` could be used. However,
  74. because of the way RK works, it is perfectly possible there are multiple copies in the transformed model.
  75. It is discouraged to use the internal blocks for signal information. Therefore, please only read data
  76. from the output ports and not from blocks in the model itself. This is an unfortunate side-effect
  77. of "transforming" the model to comply to adaptive step size simulation.