Jelajahi Sumber

statechart with in/out signals generic and first FMU

Cláudio Gomes 8 tahun lalu
induk
melakukan
685a034749

+ 10 - 0
SemanticAdaptationForFMI/FMIAbstraction/src/abstract_units/AbstractSimulationUnit.py

@@ -131,6 +131,16 @@ class AbstractSimulationUnit(object):
                     self._printState(step, iteration, self.__algebraic_functions.keys()))
         
         l.debug("<__computeOutputs()")
+    
+    def _ZOHOldValues(self, step, iteration):
+        l.debug(">_ZOHOldValues(%d, %d)", step, iteration)
+        assert iteration == 0, "Not supported yet."
+        if step>0:
+            for state_var in self._getStateVars():
+                if step == len(self.__state[state_var]):
+                    l.debug("Applying ZOH to %s...", state_var)
+                    self.__state[state_var].append([self.__state[state_var][step-1][-1]])
+        l.debug("<_ZOHOldValues(%d, %d)", step, iteration)
         
     def __setDefaultValues(self, values):
         Utils.copyMapToStateTrace(self.__state, 0, 0, values)

+ 189 - 0
SemanticAdaptationForFMI/FMIAbstraction/src/abstract_units/StatechartSimulationUnit_CTInOut.py

@@ -0,0 +1,189 @@
+'''
+Created on Jan 13, 2016
+
+@author: claudio gomes
+'''
+import logging
+
+import numpy
+
+from abstract_units.AbstractSimulationUnit import AbstractSimulationUnit, \
+    STEP_ACCEPT, INIT_MODE
+
+
+l = logging.getLogger()
+
+class StatechartSimulationUnit_CTInOut(AbstractSimulationUnit):
+    
+    TRIGGER_AFTER = "After"
+    TRIGGER_INPUT = "Input"
+    TRIGGER_DEFAULT = "Default"
+    
+    """
+    This class represents a generic statechart FMU which receives a continuous
+    signal as input and outputs a continuous signal.
+    
+    The output signal is defined according to values that are computed from the
+    current state, just like the modelica Stategraph library.
+    
+    The transitions can be taken according to conditions evaluated on the value
+    of the input signals. For now, the only condition allowed is a crossing of
+    the signal in the upward direction.
+    
+    The transitions have assignment actions that change the values of the
+    output. It is not possible for a transition to affect a signal that is used
+    as a trigger condition in some other transition. There are input variables
+    for that. The outputs that are not assignment by the transitions keep the
+    same value as before.
+    
+    Example interaction:_______________
+    sFMU = StatechartSimulationUnit_CTInOut(...)
+        At this point, the sFMU is not even in the initial state
+    sFMU.enterInitMode()
+        At this point the statechart moves into the initial state. If there are
+        default transitions to be taken at this stage, they are taken. Any
+        values that are assigned by these transitions will also be defined, so
+        that in the next move, values can already be taken out of the
+        statechart.
+    sFMU.setValues(t=0, ...,x=v)
+        This tells the FMU that signal x has value v at time 0.
+    v = sFMU.getValues(t=0, ...)
+        At time 0 there can be no crossings so no transition of that kind is taken. 
+        If there are other kinds of     conditions on signals, then these would be evaluated here and possibly
+        taken.
+        If transitions set the output values, then at this point they can
+        already be read.
+    sFMU.exitInitMode()
+    
+    sFMU.setValues(t>0, ..., x=v)
+        This tells the FMU that the signal x(t) = v. As with the initialisation
+        model, transitions will be marked to be taken at time t, is not NOT the current time of the FMU.
+    sFMU.doStep(t>0..., H)
+        Notice that the FMU is still at time t, and that this functions tells
+        him to move to t+H. If there is any after transition that happens
+        between t an t+H, then that transition is taken. This includes the
+        recursive computation of executing all default transitions and other
+        after transitions that may be enabled in between. Then, if there are no
+        more after transitions that happen between t and t+H, the internal clock
+        is advanced to t+H and all the transitions that become enabled by the
+        input values are taken, as well as any default transitions until nothing
+        else remains to be computed.
+    v = sFMU.getValues(t>0...)
+        
+    ______________________________
+    """
+    
+    def __init__(self, name, num_rtol, num_atol, state_transition_function, initial_state, input_vars, output_vars):
+        """
+        The state transition functions hold the encoding of the statechart.
+        They are called with the current state and the elapsed time on that state.
+        """
+        
+        self._state_transition_function = state_transition_function
+        
+        self._num_rtol = num_rtol
+        self._num_atol = num_atol
+        
+        self.__current_state = "state"
+        
+        self.__initial_state = initial_state
+        
+        self.__last_transition_time = 0.0
+        
+        state_vars = [self.__current_state] + output_vars
+        
+        AbstractSimulationUnit.__init__(self, name, {}, state_vars, input_vars)
+    
+    def _isClose(self, a, b):
+        return numpy.isclose(a,b, self._num_rtol, self._num_atol)
+    
+    def _biggerThan(self, a, b):
+        return not numpy.isclose(a,b, self._num_rtol, self._num_atol) and a > b
+    
+    def enterInitMode(self):
+        l.debug(">%s.StatechartSimulationUnit_CTInOut.enterInitMode()", self._name)
+        
+        self.setValues(0, 0, {self.__current_state: self.__initial_state})
+        
+        AbstractSimulationUnit.enterInitMode(self)
+        
+        l.debug("<%s.StatechartSimulationUnit_CTInOut.enterInitMode()", self._name)
+    
+    def setValues(self, step, iteration, values):
+        l.debug(">%s.StatechartSimulationUnit_CTInOut.setValues(%d, %d, %s)", self._name, step, iteration, values)
+        
+        AbstractSimulationUnit.setValues(self, step, iteration, values)
+        
+        if self._mode == INIT_MODE:
+            assert step == 0
+            state_snapshot = self.getValues(step, iteration, [self.__current_state])
+            input_snapshot = self.getValues(step, iteration, self._getInputVars())
+            
+            (next_state, output_assignments) = self._doStepFunction(0.0, state_snapshot, input_snapshot)
+            
+            # Commit the new state and outputs.
+            AbstractSimulationUnit.setValues(self, step, iteration, {self.__current_state : next_state})
+            AbstractSimulationUnit.setValues(self, step, iteration, output_assignments)
+                
+        l.debug("<%s.StatechartSimulationUnit_CTInOut.setValues()", self._name)
+    
+    
+    def _doStepFunction(self, time, state, inputs):
+        """
+        Runs all transitions that are enabled, or become enabled at time time with the inputs 
+            valued *at that time*.
+        """
+        l.debug(">%s._doStepFunction(%f, %s, %s)", self._name, time, state, inputs)
+        
+        l.debug(">%s._runAllEnabledTransitions(%f, %s, %s)", self._name, time, state, inputs)
+        
+        transition_taken = True
+        statechart_state = state[self.__current_state]
+        output_assignments = {}
+        while transition_taken:
+            elapsed = time - self.__last_transition_time
+            """
+            The state transition function is responsible for prioritising any simultaneously enabled transitions.
+            The out_values is a map of assignments to the output variables.
+            It will be merged with output_assignments
+            """
+            (out_values, new_state, transition_taken, trigger) = self._state_transition_function(statechart_state, inputs, elapsed)
+            if transition_taken:
+                l.debug("Transition taken from %s to %s because of %s. Produced assignments: %s.", 
+                                statechart_state, new_state, trigger, out_values)
+                
+                output_assignments.update(out_values)
+                l.debug("Merged assignments: %s", output_assignments)
+                statechart_state = new_state
+                self.__last_transition_time = time
+        l.debug("Finished all enabled transitions.")
+        
+        l.debug("%s.state=%s", self._name, statechart_state)
+        l.debug("%s.Merged assignments: %s", self._name, output_assignments)
+        
+        l.debug("<%s._doStepFunction()", self._name)
+        return (statechart_state, output_assignments)
+    
+    
+    def _doInternalSteps(self, time, step, iteration, cosim_step_size):
+        l.debug(">%s._doInternalSteps(%f, %d, %d, %f)", 
+                self._name, time, step, iteration, cosim_step_size)
+        
+        assert self._biggerThan(cosim_step_size, 0), "cosim_step_size too small: {0}".format(cosim_step_size)
+        assert iteration == 0, "Fixed point iterations involving this component are not supported."
+        
+        state_snapshot = self.getValues(step-1, iteration, [self.__current_state])
+        input_snapshot = self.getValues(step, iteration, self._getInputVars())
+        
+        (next_state, output_assignments) = self._doStepFunction(time+cosim_step_size, state_snapshot, input_snapshot)
+        
+        # Commit the new state and outputs.
+        self.setValues(step, iteration, {self.__current_state : next_state})
+        self.setValues(step, iteration, output_assignments)
+        # TODO Zero order hold the remaining outputs.
+        self._ZOHOldValues(step, iteration)
+        
+        l.debug("<%s._doInternalSteps() = (%s, %d)", self._name, STEP_ACCEPT, cosim_step_size)
+        return (STEP_ACCEPT, cosim_step_size)
+
+          

+ 6 - 6
SemanticAdaptationForFMI/FMIAbstraction/src/abstract_units/StatechartSimulationUnit_Event.py

@@ -72,7 +72,7 @@ class StatechartSimulationUnit_Event(AbstractSimulationUnit):
         
         self.in_event = "__in_event"
         self.out_event = "__out_event"
-        self.current_state = "state"
+        self.__current_state = "state"
         
         self.__last_transition_time = 0.0
         
@@ -80,7 +80,7 @@ class StatechartSimulationUnit_Event(AbstractSimulationUnit):
         
         input_vars = [self.in_event] if not autonomous else []
         
-        AbstractSimulationUnit.__init__(self, name, {}, [self.current_state, self.out_event], input_vars)
+        AbstractSimulationUnit.__init__(self, name, {}, [self.__current_state, self.out_event], input_vars)
     
     def _isClose(self, a, b):
         return numpy.isclose(a,b, self._num_rtol, self._num_atol)
@@ -94,13 +94,13 @@ class StatechartSimulationUnit_Event(AbstractSimulationUnit):
     """
     def _doStepFunction(self, time, state, inputs):
         """
-        state is {self.current_state : current_state}
+        state is {self.__current_state : __current_state}
         input is {self.input : input}
         """
         l.debug(">%s._doStepFunction(%f, %s, %s)", self._name, time, state, inputs)
         
         transition_taken = True
-        old_state = state[self.current_state]
+        old_state = state[self.__current_state]
         inputToConsume = inputs[self.in_event] if not self.__autonomous else ""
         output_event = ""
         while transition_taken:
@@ -132,13 +132,13 @@ class StatechartSimulationUnit_Event(AbstractSimulationUnit):
         assert self._biggerThan(cosim_step_size, 0), "cosim_step_size too small: {0}".format(cosim_step_size)
         assert iteration == 0, "Fixed point iterations involving this component are not supported."
         
-        state_snapshot = self.getValues(step-1, iteration, [self.current_state])
+        state_snapshot = self.getValues(step-1, iteration, [self.__current_state])
         input_snapshot = self.getValues(step, iteration, self._getInputVars())
         
         (next_state, output_event) = self._doStepFunction(time+cosim_step_size, state_snapshot, input_snapshot)
         
         # Commit the new state
-        self.setValues(step, iteration, {self.current_state : next_state, self.out_event : output_event})
+        self.setValues(step, iteration, {self.__current_state : next_state, self.out_event : output_event})
         
         l.debug("<%s._doInternalSteps() = (%s, %d)", self._name, STEP_ACCEPT, cosim_step_size)
         return (STEP_ACCEPT, cosim_step_size)

+ 4 - 4
SemanticAdaptationForFMI/FMIAbstraction/src/case_study/scenarios/ControlledScenario_EventController.py

@@ -13,8 +13,8 @@ from case_study.units.adaptations.PowerInputAdaptation_Event import PowerInputAd
 from case_study.units.ct_based.ObstacleFMU import ObstacleFMU
 from case_study.units.ct_based.PowerFMU import PowerFMU
 from case_study.units.ct_based.WindowFMU import WindowFMU
-from case_study.units.de_based.DriverControllerStatechartFMU import DriverControllerStatechartFMU_Event
-from case_study.units.de_based.EnvironmentStatechartFMU import EnvironmentStatechartFMU_Event
+from case_study.units.de_based.DriverControllerStatechartFMU_Event import DriverControllerStatechartFMU_Event
+from case_study.units.de_based.EnvironmentStatechartFMU_Event import EnvironmentStatechartFMU_Event
 
 
 NUM_RTOL = 1e-08
@@ -94,7 +94,7 @@ adapt_armature.setValues(0, 0, {adapt_armature.armature_current: pOut[power.i],
 
 adaptArmOut = adapt_armature.getValues(0, 0, [adapt_armature.out_event])
 
-environment.setValues(0, 0, {environment.current_state : "Neutral",
+environment.setValues(0, 0, {environment.__current_state : "Neutral",
                              environment.out_event : ""})
 envOut = environment.getValues(0, 0, [environment.out_event])
 
@@ -103,7 +103,7 @@ controller_in = adaptArmOut[adapt_armature.out_event] + envOut[environment.out_e
 if adaptArmOut[adapt_armature.out_event] != "" and envOut[environment.out_event] != "":
     controller_in = adaptArmOut[adapt_armature.out_event]
 controller.setValues(0, 0, {controller.in_event : controller_in,
-                            controller.current_state: "Neutral",
+                            controller.__current_state: "Neutral",
                             controller.out_event: ""})
 
 cOut = controller.getValues(0, 0, [controller.out_event])

+ 55 - 0
SemanticAdaptationForFMI/FMIAbstraction/src/case_study/units/de_based/EnvironmentStatechartFMU_InOut.py

@@ -0,0 +1,55 @@
+import logging
+
+from abstract_units.StatechartSimulationUnit_CTInOut import StatechartSimulationUnit_CTInOut
+
+l = logging.getLogger()
+
+class EnvironmentStatechartFMU_CTInOut(StatechartSimulationUnit_CTInOut):
+    """
+    This is a simple environment for the power window case study.
+    It has the states
+        Neutral    (initial)
+        Up
+        Down
+    And the outputs are: up, down, valued at either 0 or 1.
+    """
+    
+    def __init__(self, name, num_rtol, num_atol):
+        
+        input_vars = []
+        self.out_up = "out_up"
+        self.out_down = "out_down"
+        
+        output_vars = [self.out_up , self.out_down]
+        
+        initial_state = "Initial"
+        
+        def state_transition(current_state, input_event, elapsed):
+            l.debug(">%s.state_transition(%s, %s, %f)", self._name, current_state, input_event, elapsed)
+            
+            output_assignment = {}
+            target_state = ""
+            transition_taken = False
+            trigger = StatechartSimulationUnit_CTInOut.TRIGGER_DEFAULT
+            
+            if current_state == "Initial":
+                target_state = "Neutral"
+                transition_taken = True
+                trigger = StatechartSimulationUnit_CTInOut.TRIGGER_DEFAULT
+                output_assignment[self.out_up] = 0.0
+                output_assignment[self.out_down] = 0.0
+            elif current_state == "Neutral":
+                if self._biggerThan(elapsed, 0.5):
+                    target_state = "Up"
+                    transition_taken = True
+                    trigger = StatechartSimulationUnit_CTInOut.TRIGGER_AFTER
+                    output_assignment[self.out_up] = 1.0
+                
+            return (output_assignment, target_state, transition_taken, trigger)
+            l.debug("<%s.state_transition(%s, %s, %s, %s)", self._name, output_assignment, target_state, transition_taken, trigger)
+        
+        StatechartSimulationUnit_CTInOut.__init__(self, name, 
+                                                  num_rtol, num_atol, 
+                                                  state_transition, initial_state, 
+                                                  input_vars, output_vars)
+