RealTime.rst 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. Realtime Simulation
  2. ===================
  3. Besides normal (as-fast-as-possible) simulation, it is also possible to simulate CBD models in realtime. Here, the
  4. time (and therefore `delta t` as well) will be interpreted as seconds and the simulator will wait **non-blocking**
  5. until the required time has passed. There are several supported backend that provide this functionality. These
  6. backends are based on the backends provided by PyPDEVS_.
  7. While there doesn't have to be feedback duing a simulation, the :func:`CBD.simulator.Simulator.setProgressBar`
  8. function provides a `tqdm progress bar <https://tqdm.github.io/>`_. When running long simulations, this might
  9. be a useful feature. Note that, when combined with a termination condition, the progress bar may yield inaccurate
  10. values.
  11. .. note::
  12. - When using progress bars, `tqdm <https://tqdm.github.io/>`_ must be installed.
  13. - In :doc:`LivePlot`, realtime simulation is used together with a variation of the :doc:`SinGen` example.
  14. .. note::
  15. Unlike PyPDEVS_, interrupt events are not possible. However, as can be seen in the :doc:`Dashboard`
  16. example, the :class:`CBD.lib.std.ConstantBlock` allows for altering the internal value it outputs
  17. **during** the simulation. This mechanism may be manipulated to allow for external interrupts if
  18. necessary.
  19. .. _PyPDEVS: https://msdl.uantwerpen.be/documentation/PythonPDEVS/realtime.html
  20. Example Model
  21. -------------
  22. To simplify the explanations of the following sections, we will be using the :doc:`SinGen` as a basis model.
  23. To recap:
  24. .. code-block:: python
  25. from CBD.Core import CBD
  26. from CBD.simulator import Simulator
  27. from CBD.lib.std import TimeBlock, GenericBlock
  28. from CBD.lib.endpoints import SignalCollectorBlock
  29. class SinGen(CBD):
  30. def __init__(self, name="SinGen"):
  31. CBD.__init__(self, name, input_ports=[], output_ports=[])
  32. # Create the blocks
  33. self.addBlock(TimeBlock("time"))
  34. self.addBlock(GenericBlock("sin", block_operator="sin"))
  35. self.addBlock(SignalCollectorBlock("collector"))
  36. # Connect the blocks
  37. self.addConnection("time", "sin")
  38. self.addConnection("sin", "collector")
  39. sinGen = SinGen("SinGen")
  40. sim = Simulator(sinGen)
  41. sim.setRealTime()
  42. .. note::
  43. Realtime simulation happens non-blocking. This means the :func:`CBD.simulator.Simulator.run` method will be called
  44. asynchronously. Additionally, simulation runs as a daemon thread, so exiting the main thread will automatically
  45. terminate the simulation. To keep the script alive until after the simulation, you can use:
  46. .. code-block:: python
  47. while sim.is_running():
  48. pass
  49. |
  50. Python Threading Backend
  51. ------------------------
  52. The threading (or Python) backend/platform will use the :mod:`threading` module for delaying the simulation steps.
  53. This is the default simulation backend.
  54. .. warning::
  55. Python threads can sometimes have a rather low granularity in CPython 2. So while we are simulating in soft
  56. realtime anyway, it is important to note that delays could potentially become significant.
  57. .. code-block:: python
  58. sim.setRealTimePlatformThreading()
  59. sim.setDeltaT(0.3)
  60. sim.run(100.0)
  61. # Keep it alive
  62. while sim.is_running(): pass
  63. print("FINISHED!")
  64. .. seealso::
  65. - :func:`CBD.simulator.Simulator.setRealTimePlatform`
  66. - :func:`CBD.simulator.Simulator.setRealTimePlatformThreading`
  67. - :func:`CBD.simulator.Simulator.is_running`
  68. TkInter Backend
  69. ---------------
  70. The `TkInter <https://docs.python.org/3/library/tkinter.html>`_ event loop can become quite complex, as it is
  71. required to interface to the GUI as wel as to the simulation. Luckily, this backend will wrap all the complexity
  72. into a white box. It is, however, required to define the GUI application and start the mainloop, but afterwards,
  73. all will be handled for you.
  74. .. code-block:: python
  75. import tkinter as tk
  76. root = tk.Tk()
  77. sim.setRealTimePlatformTk(root)
  78. sim.setDeltaT(0.3)
  79. sim.run(100.0)
  80. root.mainloop()
  81. print("FINISHED!")
  82. .. seealso::
  83. - :func:`CBD.simulator.Simulator.setRealTimePlatform`
  84. - :func:`CBD.simulator.Simulator.setRealTimePlatformTk`
  85. GameLoop Backend
  86. ----------------
  87. Whenever it is required to control the invocation of delays from another execution loop, like e.g. a gameloop,
  88. it is pertinent to make use of the `GameLoop` backend. Delays won't happen internally anymore, as they should be
  89. handled by the execution loop. By making use of the :func:`CBD.simulator.Simulator.realtime_gameloop_call`, the
  90. simulation can advance to the next timestep.
  91. .. code-block:: python
  92. sim.setRealTimePlatformGameLoop()
  93. sim.setDeltaT(0.3)
  94. sim.run(100.0)
  95. while sim.is_running():
  96. # do some fancy computations
  97. ...
  98. # do some rendering
  99. ...
  100. # advance the model's state
  101. sim.realtime_gameloop_call()
  102. print("FINISHED!")
  103. .. warning::
  104. The simulation is still variable on the time constraints of your current system. Use the
  105. :class:`CBD.realtime.threadingGameLoopAlt.ThreadingGameLoopAlt` instead to fully control the time yourself.
  106. In this case, the :func:`CBD.simulator.Simulator.realtime_gameloop_call` requires the simulation time to be
  107. passed as an argument.
  108. While this is an option, it is highly encouraged to use the other backends instead. The alternative gameloop
  109. runs on the bare bones of the simulator, making system invalidities possible when not fully understanding the
  110. simulator itself. Additionally, exploiting time in a simulation in this way is heavily discouraged and is
  111. considered to be a bad practice.
  112. .. seealso::
  113. - :func:`CBD.simulator.Simulator.setRealTimePlatform`
  114. - :func:`CBD.simulator.Simulator.setRealTimePlatformGameLoop`
  115. - :func:`CBD.simulator.Simulator.realtime_gameloop_call`
  116. - :class:`CBD.realtime.threadingGameLoopAlt.ThreadingGameLoopAlt`