InacurateControllerArmatureAdaptation.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import logging
  2. import numpy
  3. from units.AbstractSimulationUnit import AbstractSimulationUnit, STEP_ACCEPT
  4. l = logging.getLogger()
  5. class InacurateControllerArmatureAdaptation(AbstractSimulationUnit):
  6. """
  7. This is the adaptation of the armature signal coming from the power system and into the controller statechart.
  8. It therefore gets a continuous input and outputs events.
  9. The input will be the armature continuous signal.
  10. The output will be the event "obj" whenever the absolute value of
  11. the armature signal exceeds a certain threshold.
  12. Note that we could have coded a generic signal crossing adaptation unit
  13. and there is a whole range of pathological cases that we are not dealing with now.
  14. For these, see the implementation of the AbstractZeroCrossingBlock
  15. of the DiracCBD Simulator
  16. The detailed behaviour of this block is as follows:
  17. ______________________________
  18. f = InacurateControllerArmatureAdaptation(...)
  19. f.enterInitMode()
  20. f.setValues(...,armature)
  21. The FMU records this value in its internal state.
  22. "" = f.getValues(...)
  23. The empty event is returned because at time t=0, there can be no crossing.
  24. f.exitInitMode()
  25. f.setValues(..., None)
  26. The FMU records the value as the current input in its internal state.
  27. f.doStep(..., H)
  28. The FMU checks whether the current input has crossed the given threshold,
  29. taking into account the previous value of the input,
  30. already stored in the internal state.
  31. The output value is then calculated and the current input moved into the internal state.
  32. "someReaction" = f.getValues(...)
  33. Gets the output event. Can either be absent, or the obj event.
  34. ______________________________
  35. """
  36. def __init__(self, name, num_rtol, num_atol, threshold, upward):
  37. self._num_rtol = num_rtol
  38. self._num_atol = num_atol
  39. assert upward, "Not implemented yet."
  40. self.__crossUpward = upward
  41. self.__threshold = threshold
  42. self.armature_current = "armature_current"
  43. self.out_event = "out_event"
  44. input_vars = [self.armature_current]
  45. state_vars = [self.out_event]
  46. algebraic_functions = {}
  47. AbstractSimulationUnit.__init__(self, name, algebraic_functions, state_vars, input_vars)
  48. def _isClose(self, a, b):
  49. return numpy.isclose(a,b, self._num_rtol, self._num_atol)
  50. def _biggerThan(self, a, b):
  51. return not numpy.isclose(a,b, self._num_rtol, self._num_atol) and a > b
  52. def _doInternalSteps(self, time, step, iteration, cosim_step_size):
  53. l.debug(">%s._doInternalSteps(%f, %d, %d, %f)", self._name, time, step, iteration, cosim_step_size)
  54. assert self._biggerThan(cosim_step_size, 0), "cosim_step_size too small: {0}".format(cosim_step_size)
  55. assert iteration == 0, "Fixed point iterations not supported yet."
  56. current_input = self.getValues(step, iteration, self._getInputVars())[self.armature_current]
  57. previous_input = self.getValues(step-1, iteration, self._getInputVars())[self.armature_current]
  58. output_event = ""
  59. l.debug("%s.previous_input=%f", self._name, previous_input)
  60. l.debug("%s.current_input=%f", self._name, current_input)
  61. if (not self._biggerThan(previous_input, self.__threshold)) \
  62. and self._biggerThan(current_input, self.__threshold) \
  63. and self.__crossUpward:
  64. output_event = "obj"
  65. l.debug("%s.output_event=%s", self._name, output_event)
  66. self.setValues(step, iteration, {self.out_event: output_event})
  67. l.debug("<%s._doInternalSteps() = (%s, %d)", self._name, STEP_ACCEPT, cosim_step_size)
  68. return (STEP_ACCEPT, cosim_step_size)