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
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