Closed Loop

Basis

class nlcontrol.closedloop.feedback.ClosedLoop(system=None, controller=None)[source]

Bases: object

The object contains a closed loop configuration using BlockDiagram objects of the simupy module. The closed loop systems is given by the following block scheme:

../_images/aafig-7cb4f916cab1da65e8177f820a8059e6f764922e.svg
Parameters
systemSystembase or list of Systembase

A state-full or state-less system. The number of inputs should be equal to the number of controller outputs.

controllerControllerBase or list of ControllerBase

A state-full or state-less controller. The number of inputs should be equal to the number of system outputs.

Examples

  • Create a closed-loop object of SystemBase object ‘sys’, which uses the Euler-Lagrange formulation, and ControllerBase object ‘contr’ containing a PID and a DynamicController object in parallel.
    >>> from nlcontrol import PID, DynamicController, EulerLagrange
    >>> $
    >>> # Define the system:
    >>> states = 'x1, x2'
    >>> inputs = 'u1, u2'
    >>> sys = EulerLagrange(states, inputs)
    >>> x1, x2, dx1, dx2, u1, u2, du1, du2 = sys.create_variables(input_diffs=True)
    >>> M = [[1, x1*x2],
        [x1*x2, 1]]
    >>> C = [[2*dx1, 1 + x1],
        [x2 - 2, 3*dx2]]
    >>> K = [x1, 2*x2]
    >>> F = [u1, 0]
    >>> sys.define_system(M, C, K, F)
    >>> $
    >>> # Define the DynamicController controller:
    >>> st = 'z1, z2'
    >>> dyn_contr = DynamicController(states=st, inputs=sys.minimal_states)
    >>> z1, z2, z1dot, z2dot, w, wdot = contr.create_variables()
    >>> a0, a1, k1 = 12.87, 6.63, 0.45
    >>> b0 = (48.65 - a1) * k1
    >>> b1 = (11.79 - 1) * k1
    >>> A = [[0, 1], [-a0, -a1]]
    >>> B = [[0], [1]]
    >>> C = [[b0], [b1]]
    >>> f = lambda x: x**2
    >>> eta = [[w + wdot], [(w + wdot)**2]]
    >>> phi = [[z1], [z2dot]]
    >>> contr.define_controller(A, B, C, f, eta, phi)
    >>> $
    >>> # Define the PID:
    >>> kp = 1
    >>> kd = 1
    >>> ksi0 = [kp * x1, kp * x2]
    >>> psi0 = [kd * dx1, kd * dx2]
    >>> pid = PID(ksi0, None, psi0, inputs=sys.minimal_states)
    >>> $
    >>> # Create the controller:
    >>> contr = dyn_contr.parallel(pid)
    >>> $
    >>> # Create a closed-loop object:
    >>> CL = ClosedLoop(sys, contr)
    
Attributes
backward_system

ControllerBase

forward_system

Systembase

Methods

create_block_diagram([forward_systems, …])

Create a closed loop block diagram with negative feedback.

create_closed_loop_system()

Create a SystemBase object of the closed-loop system.

linearize(working_point_states)

In many cases a nonlinear closed-loop system is observed around a certain working point.

simulation(tspan, initial_conditions[, …])

Simulates the closed-loop in various conditions.

property backward_system

ControllerBase

The controller in the backward path of the closed loop.

create_block_diagram(forward_systems: list = None, backward_systems: list = None)[source]

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_systemslist, 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
BDa simupy’s BlockDiagram object

contains the configuration of the closed-loop.

indicesdict

information on the ranges of the states and outputs in the output vectors of a simulation dataset.

create_closed_loop_system()[source]

Create a SystemBase object of the closed-loop system.

Returns
systemSystemBase

A Systembase object of the closed-loop system.

property forward_system

Systembase

The system in the forward path of the closed loop.

linearize(working_point_states)[source]

In many cases a nonlinear closed-loop system is observed around a certain working point. In the state space close to this working point it is save to say that a linearized version of the nonlinear system is a sufficient approximation. The linearized model allows the user to use linear control techniques to examine the nonlinear system close to this working point. A first order Taylor expansion is used to obtain the linearized system. A working point for the states needs to be provided.

Parameters
working_point_stateslist or int

the state equations are linearized around the working point of the states.

Returns
sys_lin: SystemBase object

with the same states and inputs as the original system. The state and output equation is linearized.

sys_control: control.StateSpace object

Examples

  • Print the state equation of the linearized closed-loop object of `CL’ around the state’s working point x[1] = 1 and x[2] = 5:
    >>> CL_lin, CL_control = CL.linearize([1, 5])
    >>> print('Linearized state equation: ', CL_lin.state_equation)
    
simulation(tspan, initial_conditions, plot=False, custom_integrator_options=None)[source]

Simulates the closed-loop in various conditions. It is possible to impose initial conditions on the states of the system. The results of the simulation are numerically available. Also, a plot of the states and outputs is available. To simulate the system scipy’s ode is used. # TODO: output_signal -> a disturbance on the output signal.

Parameters
tspanfloat or list-like

the parameter defines the time vector for the simulation in seconds. An integer indicates the end time. A list-like object with two elements indicates the start and end time respectively. And more than two elements indicates at which time instances the system needs to be simulated.

initial_conditionsint, float, list-like object

the initial conditions of the states of a statefull system. If none is given, all are zero, default: None

plotboolean, optional

the plot boolean decides whether to show a plot of the inputs, states, and outputs, default: False

custom_integrator_optionsdict, optional (default: None)

Specify specific integrator options to pass to integrator_class.set_integrator (scipy ode). The options are ‘name’, ‘rtol’, ‘atol’, ‘nsteps’, and ‘max_step’, which specify the integrator name, relative tolerance, absolute tolerance, number of steps, and maximal step size respectively. If no custom integrator options are specified the DEFAULT_INTEGRATOR_OPTIONS are used:

{
    "name": "dopri5",
    "rtol": 1e-6,
    "atol": 1e-12,
    "nsteps": 500,
    "max_step": 0.0
}
Returns
tarray

time vector

datatuple

four data vectors, the states and the outputs of the systems in the forward path and the states and outputs of the systems in the backward path.

Examples

  • A simulation of 5 seconds of the statefull SystemBase object ‘sys’ in the forward path and the statefull ControllerBase object `contr’ in the backward path for a set of initial conditions [x0_0, x1_0] and plot the results:
    >>> CL = ClosedLoop(sys, contr)
    >>> t, data = CL.simulation(5, [x0_0, x1_0], custom_integrator_options={'nsteps': 1000}, plot=True)
    >>> (x_p, y_p, x_c, y_c) = data
    

Building blocks

nlcontrol.closedloop.blocks.gain_block(value, dim)[source]

Multiply the output of system with dimension ‘dim’ with a contant value ‘K’.

../_images/aafig-6128b4ef2f5bd83f312f820d52a9eb1d844b34ce.svg
Parameters
valueint or float

Multiply the input signal with a value.

dimint
Returns
simupy's MemorylessSystem

Examples

A negative gain block with dimension 3:
>>> negative_feedback = gain_block(-1, 3)