ControlledScenario_EventController.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. """
  2. In this scenario, the controller is a statchart that receives events at his input.
  3. The main semantic adaptation is getting the continuous armature signal coming from the power system,
  4. and converting it into an event.
  5. """
  6. import logging
  7. from bokeh.plotting import figure, output_file, show
  8. from case_study.units.adaptations.InacurateControllerArmatureAdaptation_Event import InacurateControllerArmatureAdaptation_Event
  9. from case_study.units.adaptations.PowerInputAdaptation_Event import PowerInputAdaptation_Event
  10. from case_study.units.ct_based.ObstacleFMU import ObstacleFMU
  11. from case_study.units.ct_based.PowerFMU import PowerFMU
  12. from case_study.units.ct_based.WindowFMU import WindowFMU
  13. from case_study.units.de_based.DriverControllerStatechartFMU_Event import DriverControllerStatechartFMU_Event
  14. from case_study.units.de_based.EnvironmentStatechartFMU_Event import EnvironmentStatechartFMU_Event
  15. NUM_RTOL = 1e-08
  16. NUM_ATOL = 1e-08
  17. l = logging.getLogger()
  18. l.setLevel(logging.DEBUG)
  19. cosim_step_size = 0.001
  20. num_internal_steps = 10
  21. stop_time = 10;
  22. environment = EnvironmentStatechartFMU_Event("env", NUM_RTOL, NUM_ATOL)
  23. controller = DriverControllerStatechartFMU_Event("controller", NUM_RTOL, NUM_ATOL)
  24. power = PowerFMU("power", NUM_RTOL, NUM_ATOL, cosim_step_size/num_internal_steps,
  25. J=0.085,
  26. b=5,
  27. K=1.8,
  28. R=0.15,
  29. L=0.036,
  30. V=12)
  31. armature_threshold = 20.0
  32. adapt_armature = InacurateControllerArmatureAdaptation_Event("arm_adapt", NUM_RTOL, NUM_ATOL, armature_threshold, True)
  33. adapt_power_input = PowerInputAdaptation_Event("power_adapt")
  34. window_radius = 0.017
  35. window = WindowFMU("window", NUM_RTOL, NUM_ATOL, cosim_step_size/num_internal_steps,
  36. J=0.085,
  37. r=window_radius,
  38. b = 150,
  39. c = 1e3) # c = 1e5 makes this an unstable system.
  40. obstacle = ObstacleFMU("obstacle", NUM_RTOL, NUM_ATOL, cosim_step_size/num_internal_steps,
  41. c=1e5,
  42. fixed_x=0.45)
  43. environment.enterInitMode()
  44. controller.enterInitMode()
  45. power.enterInitMode()
  46. adapt_armature.enterInitMode()
  47. adapt_power_input.enterInitMode()
  48. window.enterInitMode()
  49. obstacle.enterInitMode()
  50. # Solve initialisation.
  51. """
  52. The initialisation may impose a completely different order for the execution of the FMUs.
  53. In this case we know that there is no direct feed-through between the power input and its outputs,
  54. so we can safely set its initial state, get its output, and then compute all the other FMUs,
  55. before setting the new inputs to the power.
  56. """
  57. pOut = power.setValues(0, 0, {
  58. power.omega: 0.0,
  59. power.theta: 0.0,
  60. power.i: 0.0
  61. })
  62. pOut = power.getValues(0, 0, [power.omega, power.theta, power.i])
  63. window.setValues(0, 0, {window.omega_input: pOut[power.omega],
  64. window.theta_input: pOut[power.theta],
  65. window.theta: 0.0,
  66. window.omega: 0.0
  67. })
  68. wOut = window.getValues(0, 0, [window.tau, window.x])
  69. obstacle.setValues(0, 0, {obstacle.x: wOut[window.x]})
  70. oOut = obstacle.getValues(0, 0, [obstacle.F])
  71. adapt_armature.setValues(0, 0, {adapt_armature.armature_current: pOut[power.i],
  72. adapt_armature.out_event: "" })
  73. adaptArmOut = adapt_armature.getValues(0, 0, [adapt_armature.out_event])
  74. environment.setValues(0, 0, {environment.__current_state : "Neutral",
  75. environment.out_event : ""})
  76. envOut = environment.getValues(0, 0, [environment.out_event])
  77. # coupling equation for the input event of the controller
  78. controller_in = adaptArmOut[adapt_armature.out_event] + envOut[environment.out_event]
  79. if adaptArmOut[adapt_armature.out_event] != "" and envOut[environment.out_event] != "":
  80. controller_in = adaptArmOut[adapt_armature.out_event]
  81. controller.setValues(0, 0, {controller.in_event : controller_in,
  82. controller.__current_state: "Neutral",
  83. controller.out_event: ""})
  84. cOut = controller.getValues(0, 0, [controller.out_event])
  85. adapt_power_input.setValues(0, 0, {adapt_power_input.in_event : cOut[controller.out_event],
  86. adapt_power_input.out_down: 0.0,
  87. adapt_power_input.out_up: 0.0})
  88. adaptPowerOut = adapt_power_input.getValues(0, 0, [adapt_power_input.out_up, adapt_power_input.out_down])
  89. # Coupling equation for power
  90. power_tau = - ( wOut[window.tau] + window_radius * oOut[obstacle.F])
  91. # Finally set the other power inputs
  92. power.setValues(0, 0, {power.tau: power_tau,
  93. power.up: adaptPowerOut[adapt_power_input.out_up],
  94. power.down: adaptPowerOut[adapt_power_input.out_down]})
  95. environment.exitInitMode()
  96. controller.exitInitMode()
  97. power.exitInitMode()
  98. adapt_armature.exitInitMode()
  99. adapt_power_input.exitInitMode()
  100. window.exitInitMode()
  101. obstacle.exitInitMode()
  102. trace_i = [0.0]
  103. trace_omega = [0.0]
  104. trace_x = [0.0]
  105. trace_F = [0.0]
  106. times = [0.0]
  107. time = 0.0
  108. for step in range(1, int(stop_time / cosim_step_size) + 1):
  109. # Note that despite the fact that there is no feedthrough between
  110. # the inputs and the outputs of the power system,
  111. # the internal solver would still benefit from an up-to-date
  112. # value given for the inputs. However, that creates an algebraic loop,
  113. # so for now, we just get old values for the inputs.
  114. oOut = obstacle.getValues(step-1, 0, [obstacle.F])
  115. wOut = window.getValues(step-1, 0, [window.tau, window.x])
  116. adaptPowerOut = adapt_power_input.getValues(step-1, 0, [adapt_power_input.out_up, adapt_power_input.out_down])
  117. # Coupling equation for power
  118. power_tau = - ( wOut[window.tau] + window_radius * oOut[obstacle.F])
  119. # Finally set the other power inputs
  120. power.setValues(step, 0, {power.tau: power_tau,
  121. power.up: adaptPowerOut[adapt_power_input.out_up],
  122. power.down: adaptPowerOut[adapt_power_input.out_down]})
  123. power.doStep(time, step, 0, cosim_step_size)
  124. pOut = power.getValues(step, 0, [power.omega, power.theta, power.i])
  125. window.setValues(step, 0, {window.omega_input: pOut[power.omega],
  126. window.theta_input: pOut[power.theta],
  127. window.theta: 0.0,
  128. window.omega: 0.0
  129. })
  130. window.doStep(time, step, 0, cosim_step_size)
  131. wOut = window.getValues(step, 0, [window.tau, window.x])
  132. obstacle.setValues(step, 0, {obstacle.x: wOut[window.x]})
  133. obstacle.doStep(time, step, 0, cosim_step_size)
  134. oOut = obstacle.getValues(step, 0, [obstacle.F])
  135. adapt_armature.setValues(step, 0, {adapt_armature.armature_current: pOut[power.i]})
  136. adapt_armature.doStep(time, step, 0, cosim_step_size)
  137. adaptArmOut = adapt_armature.getValues(step, 0, [adapt_armature.out_event])
  138. environment.doStep(time, step, 0, cosim_step_size)
  139. envOut = environment.getValues(step, 0, [environment.out_event])
  140. # coupling equation for the input event of the controller
  141. controller_in = adaptArmOut[adapt_armature.out_event] + envOut[environment.out_event]
  142. if adaptArmOut[adapt_armature.out_event] != "" and envOut[environment.out_event] != "":
  143. controller_in = adaptArmOut[adapt_armature.out_event]
  144. controller.setValues(step, 0, {controller.in_event : controller_in})
  145. controller.doStep(time, step, 0, cosim_step_size)
  146. cOut = controller.getValues(step, 0, [controller.out_event])
  147. adapt_power_input.setValues(step, 0, {adapt_power_input.in_event : cOut[controller.out_event]})
  148. adapt_power_input.doStep(time, step, 0, cosim_step_size)
  149. adaptPowerOut = adapt_power_input.getValues(step, 0, [adapt_power_input.out_up, adapt_power_input.out_down])
  150. # Coupling equation for power
  151. power_tau = - ( wOut[window.tau] + window_radius * oOut[obstacle.F])
  152. # Finally set the other power inputs
  153. """
  154. The instruction below is not really needed, as power has already performed the step.
  155. However, we leave it here because in case an algebraic loop were being solved,
  156. this is where we would set the improved values for the power inputs,
  157. and check for convergence.
  158. """
  159. power.setValues(step, 0, {power.tau: power_tau,
  160. power.up: adapt_power_input.out_up,
  161. power.down: adapt_power_input.out_down})
  162. trace_omega.append(pOut[power.omega])
  163. trace_i.append(pOut[power.i])
  164. trace_x.append(wOut[window.x])
  165. trace_F.append(oOut[obstacle.F])
  166. time += cosim_step_size
  167. times.append(time)
  168. color_pallete = [
  169. "#e41a1c",
  170. "#377eb8",
  171. "#4daf4a",
  172. "#984ea3",
  173. "#ff7f00",
  174. "#ffff33",
  175. "#a65628",
  176. "#f781bf"
  177. ]
  178. output_file("./results.html", title="Results")
  179. p = figure(title="Plot", x_axis_label='time', y_axis_label='')
  180. p.line(x=times, y=trace_omega, legend="trace_omega", color=color_pallete[0])
  181. p.line(x=times, y=trace_i, legend="trace_i", color=color_pallete[1])
  182. show(p)
  183. output_file("./results_x.html", title="Results")
  184. p = figure(title="Plot", x_axis_label='time', y_axis_label='')
  185. p.line(x=times, y=trace_x, legend="trace_x", color=color_pallete[2])
  186. show(p)
  187. output_file("./results_F.html", title="Results")
  188. p = figure(title="Plot", x_axis_label='time', y_axis_label='')
  189. p.line(x=times, y=trace_F, legend="trace_F", color=color_pallete[3])
  190. show(p)