Example #1
0
    def __connect_input__(self, input_signal=None, base_system=None, block_diagram=None):
        """
        Connects an input signal to a SystemBase object in a new simupy.BlockDiagram or in an existing simupy.BlockDiagram.
        """
        if base_system is None:
            base_system = self
        elif not isinstance(base_system, SystemBase):
            error_text = '[SystemBase.__connect_input__] The system should be an SystemBase instance.'
            raise TypeError(error_text)

        if input_signal is None:
            if block_diagram is None:
                BD = BlockDiagram(base_system.system)
            elif not base_system.system in set(block_diagram.systems):
                    BD = block_diagram
                    BD.add_system(base_system.system)
        else:
            if block_diagram is None:
                BD = BlockDiagram(input_signal.system, base_system.system)
            else:
                BD = block_diagram
                BD.add_system(input_signal.system)
                if not base_system.system in set(block_diagram.systems):
                    BD.add_system(base_system.system)
            
            BD.connect(input_signal.system, base_system.system)
        return BD
Example #2
0
    def create_block_diagram(self, forward_systems:list=None, backward_systems:list=None):
        """
        Create a closed loop block diagram with negative feedback. The loop contains a list of SystemBase objects in the forward path and ControllerBase objects in the backward path.

        Parameters
        -----------
        forward_systems : list, optional (at least one system should be present in the loop)
            A list of SystemBase objects. All input and output dimensions should match.
        backward_systems: list, optional (at least one system should be present in the loop)
            A list of ControllerBase objects. All input and output dimensions should match.

        Returns
        --------
        BD : a simupy's BlockDiagram object 
            contains the configuration of the closed-loop.
        indices : dict
            information on the ranges of the states and outputs in the output vectors of a simulation dataset.
        """
        if (forward_systems is None):
            if (self.system is None):
                error_text = "[ClosedLoop.create_block_diagram] Both the forward_systems argument and the ClosedLoop.system variable are empty. Please provide a forward_system."
                assert AssertionError(error_text)
            else:
                forward_systems = [self.system]
        if (backward_systems is None):
            if (self.system is None):
                error_text = "[ClosedLoop.create_block_diagram] Both the backward_systems argument and the ClosedLoop.controller variable are empty. Please provide a backward_system."
                assert AssertionError(error_text)
            else:
                backward_systems = [self.controller]

        BD = BlockDiagram()
        # Order of adding systems is important. The negative feedback_block needs to be added before the backward systems. This can be seen from simupy.block_diagram.BlockDiagram.output_equation_function(). Possibly only for stateless systems important. #TODO: check whether there is a problem with list of backward systems.
        output_startidx_process = 0
        output_endidx_process = -1
        state_startidx_process = 0
        state_endidx_process = -1

        if (len(forward_systems) is not 0):
            for forward_system in forward_systems:
                forward_sys = forward_system.system
                BD.add_system(forward_sys)
                output_endidx_process += forward_sys.dim_output
                state_endidx_process += forward_sys.dim_state
        output_endidx_process += 1
        state_endidx_process += 1

        output_startidx_controller = output_endidx_process
        output_endidx_controller = output_startidx_controller
        state_startidx_controller = state_endidx_process
        state_endidx_controller = state_startidx_controller

        if (len(backward_systems) is not 0):
            negative_feedback = gain_block(-1, backward_systems[-1].system.dim_output)
            BD.add_system(negative_feedback)
            output_startidx_controller += negative_feedback.dim_output
            output_endidx_controller = output_startidx_controller
            for backward_system in backward_systems:
                backward_sys = backward_system.system
                BD.add_system(backward_sys)
                output_endidx_controller += backward_sys.dim_output
                state_endidx_controller += backward_sys.dim_state
        else:
            negative_feedback = gain_block(-1, forward_systems[-1].system.dim_output)
            BD.add_system(negative_feedback)

        for i in range(len(forward_systems)):
            if (i == len(forward_systems) - 1):
                BD.connect(forward_systems[i].system, backward_systems[0].system)
            else:
                BD.connect(forward_systems[i].system, forward_systems[i + 1].system)
        if (len(backward_systems) == 0):
            BD.add_system(negative_feedback)
            BD.connect(forward_systems[-1].system, negative_feedback)
            BD.connect(negative_feedback, forward_systems[0].system)
        else:
            for j in range(len(backward_systems)):
                if (j == len(backward_systems) - 1):
                    BD.connect(backward_systems[j].system, negative_feedback)
                    BD.connect(negative_feedback, forward_systems[0].system)
                else:
                    BD.connect(backward_systems[j].system, backward_systems[j + 1].system)
        
        indices = {
            'process': {
                'output': [output_endidx_process] if output_startidx_process == output_endidx_process\
                    else [output_startidx_process, output_endidx_process],
                'state': None if state_endidx_process is 0\
                    else[state_endidx_process] if state_startidx_process == state_endidx_process\
                    else [state_startidx_process, state_endidx_process]
            },
            'controller': {
                'output': [output_endidx_controller] if output_startidx_controller == output_endidx_controller\
                    else [output_startidx_controller, output_endidx_controller],
                'state': None if state_endidx_controller == state_endidx_process\
                    else[state_endidx_controller] if state_startidx_controller == state_endidx_controller\
                    else [state_startidx_controller, state_endidx_controller]
            }
        }
        return BD, indices