Controllers

Base Controller

class nlcontrol.systems.controllers.controller.ControllerBase(states, inputs, sys=None)[source]

Bases: nlcontrol.systems.system.SystemBase

Returns a base structure for a controller with outputs, optional inputs, and optional states. The controller is an instance of a SystemBase, which is defined by it state equations (optional):

\[\frac{dx(t)}{dt} = h(x(t), u(t), t)\]

with x(t) the state vector, u(t) the input vector and t the time in seconds. Next, the output is given by the output equation:

\[y(t) = g(x(t), u(t), t)\]
Parameters
statesstring or array-like

if states is a string, it is a comma-separated listing of the state names. If states is array-like it contains the states as sympy’s dynamic symbols.

inputsstring or array-like

if inputs is a string, it is a comma-separated listing of the input names. If inputs is array-like it contains the inputs as sympy’s dynamic symbols.

systemsimupy’s DynamicalSystem object (simupy.systems.symbolic), optional

the object containing output and state equations, default: None.

Examples

  • Statefull controller with one state, one input, and one output:
    >>> from simupy.systems.symbolic import MemorylessSystem, DynamicalSystem
    >>> from sympy.tensor.array import Array
    >>> st = 'z'
    >>> inp = 'w'
    >>> contr = ControllerBase(states=st, inputs=inp)
    >>> z, zdot, w = contr.create_variables()
    >>> contr.system = DynamicalSystem(state_equation=Array([-z + w]), state=z, output_equation=z, input_=w)
    
  • Statefull controller with two states, one input, and two outputs:
    >>> st = 'z1, z2'
    >>> inp = 'w'
    >>> contr = ControllerBase(states=st, inputs=inp)
    >>> z1, z2, z1dot, z2dot, w = contr.create_variables()
    >>> contr.system = DynamicalSystem(state_equation=Array([-z1 + z2**2 + w, -z2 + 0.5 * z1]), state=Array([z1, z2]), output_equation=Array([z1 * z2, z2]), input_=w)
    
  • Stateless controller with one input:
    >>> st = None
    >>> inp = 'w'
    >>> contr = ControllerBase(states=st, inputs=inp)
    >>> w = contr.create_variables()
    >>> contr.system = MemorylessSystem(input_=Array([w]), output_equation= Array([5 * w]))
    
  • Create a copy a ControllerBase object ‘contr’ and linearize around the working point of state [0, 0] and working point of input 0 and simulate:
    >>> new_contr = ControllerBase(states=contr.states, inputs=contr.inputs, sys=contr.system)
    >>> new_contr_lin = new_contr.linearize([0, 0], 0)
    >>> new_contr_lin.simulation(10)
    
Attributes
block_configuration

Returns info on the systems: the dimension of the inputs, the states, and the output.

output_equation

expression containing dynamicsymbols

state_equation

expression containing dynamicsymbols

system

simupy's DynamicalSystem

Methods

create_variables([input_diffs, states])

Returns a tuple with all variables.

linearize(working_point_states[, …])

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

parallel(contr_append)

A controller is generated which is the result of a parallel connection of two controllers.

series(contr_append)

A controller is generated which is the result of a serial connection of two controllers.

simulation(tspan[, number_of_samples, …])

Simulates the system in various conditions.

parallel(contr_append)[source]

A controller is generated which is the result of a parallel connection of two controllers. The inputs of this object are connected to the system that is placed in parallel and a new system is achieved with the output the sum of the outputs of both systems in parallel. Notice that the dimensions of the inputs and the outputs of both systems should be equal.

Parameters
contr_appendControllerBase object

the controller that is added in parallel.

Returns
A ControllerBase object with the parallel system’s equations.

Examples

  • Place ‘contr2’ in parallel with ‘contr1’ and show the inputs, states, state equations and output equations:

>>> parallel_sys = contr1.parallel(contr2)
>>> print('inputs: ', parallel_sys.system.input_)
>>> print('States: ', parallel_sys.system.state)
>>> print('State eqs: ', parallel_sys.system.state_equation)
>>> print('Output eqs: ', parallel_sys.system.output_equation)
series(contr_append)[source]

A controller is generated which is the result of a serial connection of two controllers. The outputs of this object are connected to the inputs of the appended system and a new controller is achieved which has the inputs of the current system and the outputs of the appended system. Notice that the dimensions of the output of the current system should be equal to the dimension of the input of the appended system.

Parameters
contr_appendControllerBase object

the controller that is placed in a serial configuration. ‘contr_append’ follows the current system.

Returns
A ControllerBase object with the serial system’s equations.

Examples

  • Place ‘contr1’ behind ‘contr2’ in a serial configuration and show the inputs, states, state equations and output equations:
    >>> series_sys = contr1.series(contr2)
    >>> print('inputs: ', series_sys.system.input_)
    >>> print('States: ', series_sys.system.state)
    >>> print('State eqs: ', series_sys.system.state_equation)
    >>> print('Output eqs: ', series_sys.system.output_equation)
    

Typical Controllers

class nlcontrol.systems.controllers.basic.PID(inputs=w) PID(ksi0, chi0, psi0, inputs=inputs)[source]

Bases: nlcontrol.systems.controllers.controller.ControllerBase

A nonlinear PID controller can be created using the PID class. This class is based on the ControllerBase object. The nonlinear PID is is based on the input vector w(t), containing sympy’s dynamicsymbols. The formulation is the following:

\[u(t) = \xi_0(w(t)) + \chi_0\left(\int(w(t),t)\right) + \psi_0(w'(t))\]

with \(.'(t)\) indicating the time derivative of the signal. The class object allows the construction of P, PI, PD and PID controllers, by setting chi0 or psi0 to None. The system is based on a MemorylessSystem object from simupy.

Parameters
argsoptional
ksi0array-like

A list of P-action expressions, containing the input signal.

chi0array-like

A list of I-action expressions, containing the integral of the input signal.

psi0array-like

A list of D-action expressions, containing the derivative of the input signal.

kwargs :
inputsarray-like or string

if inputs is a string, it is a comma-separated listing of the input names. If inputs is array-like it contains the inputs as sympy’s dynamic symbols.

Examples

  • Create a classic PD controller with two inputs:
    >>> C = PID(inputs='w1, w2')
    >>> w1, w2, w1dot, w2dot = C.create_variables()
    >>> kp = 1, kd = 5
    >>> ksi0 = [kp * w1, kp * w2]
    >>> psi0 = [kd * w1dot, kd * w2dot]
    >>> C.define_PID(ksi0, None, psi0)
    
  • Same as exercise as above, but with a different constructor:
    >>> from sympy.physics.mechanics import dynamicsymbols
    >>> from sympy import Symbol, diff
    >>> w = dynamicsymbols('w1, w2')
    >>> w1, w2 = tuple(inputs)
    >>> kp = 1, kd = 5
    >>> ksi0 = [kp * w1, kp * w2]
    >>> psi0 = [kd * diff(w1, Symbol('t')), kd * diff(w2, Symbol('t'))]
    >>> C = PID(ksi0, None, psi0, inputs=w)
    
  • Formulate a standard I-action chi0:
    >>> from sympy.physics.mechanics import dynamicsymbols
    >>> from sympy import Symbol, integrate
    >>> w = dynamicsymbols('w1, w2')
    >>> w1, w2 = tuple(inputs)
    >>> ki = 0.5
    >>> chi0 = [ki * integrate(w1, Symbol('t')), ki * integrate(w2, Symbol('t'))]
    
Attributes
D_action
I_action
P_action
block_configuration

Returns info on the systems: the dimension of the inputs, the states, and the output.

output_equation

expression containing dynamicsymbols

state_equation

expression containing dynamicsymbols

system

simupy's DynamicalSystem

Methods

create_variables([input_diffs, states])

Returns a tuple with all variables.

define_PID(P, I, D)

Set all three PID actions with one function, instead of using the setter functions for each individual action.

linearize(working_point_states[, …])

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

parallel(contr_append)

A controller is generated which is the result of a parallel connection of two controllers.

series(contr_append)

A controller is generated which is the result of a serial connection of two controllers.

simulation(tspan[, number_of_samples, …])

Simulates the system in various conditions.

property D_action

!! processed by numpydoc !!

property I_action

!! processed by numpydoc !!

property P_action

!! processed by numpydoc !!

define_PID(P, I, D)[source]

Set all three PID actions with one function, instead of using the setter functions for each individual action. Automatic checking of the dimensions is done as well. The PID’s system arguments is set to a simupy’s MemorylessSystem object, containing the proper PID expressions. Both P, PI, PD and PID can be formed by setting the appropriate actions to None.

Parameters
Plist or expression

A list of expressions or an expression defining ksi0.

Ilist or expression or None

A list of expressions or an expression defining chi0. If I is None, the controller does not contain an I-action.

Dlist or expression or None

A list of expressions or an expression defining psi0. If D is None, the controller does not contain a D-action.

Statefull Controllers

class nlcontrol.systems.controllers.eulaC.DynamicController(states=None, inputs=None, sys=None)[source]

Bases: nlcontrol.systems.controllers.controller.ControllerBase

The DynamicController object is based on the ControllerBase class. A dynamic controller is defined by the following differential equations:

\[\frac{dz(t)}{dt} = A.z(t) - B.f(\sigma(t)) + \eta\left(w(t), \frac{dw(t)}{dt}\right)\]
\[\sigma(t) = C'.z\]
\[u_0 = \phi\left(z(t), \frac{dz(t)}{dt}\right)\]

with z(t) the state vector, w(t) the input vector and t the time in seconds. the symbol ‘ refers to the transpose.

Conditions:

  • A is Hurwitz,

  • (A, B) should be controllable,

  • (A, C) is observable,

  • rank(B) = rang (C) = s <= n, with s the dimension of sigma, and n the number of states.

More info on the controller can be found in [1, 2].

Parameters
statesstring or array-like

if states is a string, it is a comma-separated listing of the state names. If states is array-like it contains the states as sympy’s dynamic symbols.

inputsstring or array-like

if inputs is a string, it is a comma-separated listing of the input names. If inputs is array-like it contains the inputs as sympy’s dynamic symbols. Do not provide the derivatives as these will be added automatically.

systemsimupy’s DynamicalSystem object (simupy.systems.symbolic), optional

the object containing output and state equations, default: None.

References

[1] L. Luyckx, The nonlinear control of underactuated mechanical systems. PhD thesis, UGent, Ghent, Belgium, 5 2006.

[2] M. Loccufier, “Stabilization and set-point regulation of underactuated mechanical systems”, Journal of Physics: Conference Series, 2016, vol. 744, no. 1, p.012065.

Examples

  • Statefull controller with two states, one input, and two outputs:
    >>> inp = 'w'
    >>> st = 'z1, z2'
    >>> contr = DynamicController(states=st, inputs=inp)
    >>> 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)
    >>> print(contr)
    
Attributes
block_configuration

Returns info on the systems: the dimension of the inputs, the states, and the output.

output_equation

expression containing dynamicsymbols

state_equation

expression containing dynamicsymbols

system

simupy's DynamicalSystem

Methods

controllability_linear(A, B)

Controllability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

create_variables([input_diffs, states])

Returns a tuple with all variables.

define_controller(A, B, C, f, eta, phi)

Define the Dynamic controller given by the differential equations:

hurwitz(matrix)

Check whether a time-invariant matrix is Hurwitz.

linearize(working_point_states[, …])

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

observability_linear(A, C)

Observability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

parallel(contr_append)

A controller is generated which is the result of a parallel connection of two controllers.

series(contr_append)

A controller is generated which is the result of a serial connection of two controllers.

simulation(tspan[, number_of_samples, …])

Simulates the system in various conditions.

controllability_linear(A, B)[source]

Controllability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

Reference:

[1]. R.E. Kalman, “On the general theory of control systems”, IFAC Proc., vol. 1(1), pp. 491-502, 1960. doi.10.1016/S1474-6670(17)70094-8.

Parameters
Aarray-like

Size: n x n

Barray-like

Size: s x n

define_controller(A, B, C, f, eta, phi)[source]

Define the Dynamic controller given by the differential equations:

\[\frac{dz(t)}{dt} = A.z(t) - B.f(\sigma(t)) + \eta\left(w(t), \frac{dw(t)}{dt}\right)\]
\[\sigma(t) = C'.z\]
\[u_0 = \phi\left(z(t), \frac{dz(t)}{dt}\right)\]

with z(t) the state vector, w(t) the input vector and t the time in seconds. the symbol ‘ refers to the transpose. Conditions:

  • A is Hurwitz,

  • (A, B) should be controllable,

  • (A, C) is observable,

  • rank(B) = rang (C) = s <= n, with s the dimension of sigma, and n the number of states.

HINT: use create_variables() for an easy notation of the equations.

Parameters
Aarray-like

Hurwitz matrix. Size: n x n

Barray-like

In combination with matrix A, the controllability is checked. The linear definition can be used. Size: s x n

Carray-like

In combination with matrix A, the observability is checked. The linear definition can be used. Size: n x 1

fcallable (lambda-function)

A (non)linear lambda function with argument sigma, which equals C’.z.

etaarray-like

The (non)linear relation between the inputs plus its derivatives to the change in state. Size: n x 1

phiarray-like

The (non)linear output equation. The equations should only contain states and its derivatives. Size: n x 1

hurwitz(matrix)[source]

Check whether a time-invariant matrix is Hurwitz. The real part of the eigenvalues should be smaller than zero.

Parameters
matrix: array-like

A square matrix.

observability_linear(A, C)[source]

Observability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

Reference:

[1] R.E. Kalman, “On the general theory of control systems”, IFAC Proc., vol. 1(1), pp. 491-502, 1960. doi.10.1016/S1474-6670(17)70094-8.

Parameters
Aarray-like

Size: n x n

Carray-like

Size: n x 1

class nlcontrol.systems.controllers.eulaC.EulerLagrangeController(D0, C0, K0, C1, f, NA, NB, inputs, nonlinearity_type='stiffness')[source]

Bases: nlcontrol.systems.controllers.eulaC.DynamicController

The EulerLagrangeController object is based on the DynamicController class. The control equation is:

\[D0.p'' + C0.p' + K0.p + C1.f(C1^T.p) + N0.w' = 0\]

The apostrophe represents a time derivative, \(.^T\) is the transpose of the matrix.

The output equation is:

\[{NA}^T.D0^{-1}.K0^{-1}.D0.K0.p - {NB}^T.D0^{-1}.K0^{-1}.D0.K0.p'\]

More info on the controller can be found in [1, 2]. Here, the parameters are chosen to be

  • \(\bar{\gamma} = 0\)

  • \(\bar{\alpha} = I\)

with I the identity matrix.

Parameters
D0matrix-like

inertia matrix with numerical values. The matrix should be positive definite and symmetric.

C0matrix-like

linear damping matrix with numerical values. The matrix should be positive definite and symmetric.

K0matrix-like

linear stiffness matrix with numerical values. The matrix should be positive definite and symmetric.

C1matrix-like

nonlinear function’s constant matrix with numerical values.

fmatrix-like

nonlinear functions containing lambda functions.

NAmatrix-like

the numerical multipliers of the position feedback variables.

NBmatrix-like

the numerical multipliers of the velocity feedback variables.

nonlinearity_typestring

the nonlinear part acts on the state or the derivative of the state of the dynamic controller. The only options are `stiffness’ and `damping’.

References

[1] L. Luyckx, The nonlinear control of underactuated mechanical systems. PhD thesis, UGent, Ghent, Belgium, 5 2006.

[2] M. Loccufier, “Stabilization and set-point regulation of underactuated mechanical systems”, Journal of Physics: Conference Series, 2016, vol. 744, no. 1, p.012065.

Examples

  • An Euler-Lagrange controller with two states, the input is the minimal state of a BasicSystem `sys’ and the nonlinearity is acting on the position variable of the Euler-Lagrange controller’s state:
    >>> from sympy import atan
    >>> D0 = [[1, 0], [0, 1.5]]
    >>> C0 = [[25, 0], [0, 35]]
    >>> K0 = [[1, 0], [0, 1]]
    >>> C1 = [[0.5, 0], [0, 0.5]]
    >>> s_star = 0.01
    >>> f0 = 10
    >>> f1 = 1
    >>> f2 = (f0 - f1)*s_star
    >>> func = lambda x: f1 * x + f2 * atan((f0 - f1)/f2 * x)
    >>> f = [[func], [func]]
    >>> NA = [[0, 0], [0, 0]]
    >>> NB = [[3, 0], [2.5, 0]]
    >>> contr = EulerLagrangeController(D0, C0, K0, C1, f, NA, NB, sys.minimal_states, nonlinearity_type='stiffness')
    
Attributes
D0inertia_matrix

Inertia forces.

C0damping_matrix

Damping and Coriolis forces.

K0stiffness_matrix

Elastic en centrifugal forces.

C1nonlinear_coefficient_matrix

Coëfficient of the nonlinear functions.

typenl_stiffness

A boolean indicating whether a nonlinear stiffness (True) or damping (False) is present.

nlnonlinear_fcts

Nonlinear functions of the controller.

nl_callnonlinear_fcts_callable

Callable lambda functions of the nonlinear functions.

NAgain_inputs

Coëfficients of the position inputs.

NBgain_dinputs

Coëfficients of the velocity inputs.

inputssympy array of dynamicsymbols

input variables.

dinputssympy array of dynamicsymbols

derivative of the input array

statessympy array of dynamicsymbols

state variables.

Methods

check_symmetry(matrix)

Check if matrix is symmetric.

controllability_linear(A, B)

Controllability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

convert_to_dynamic_controller()

The Euler-Lagrange formalism is transformed to the state and output equation notation of the DynamicController class.

create_variables([input_diffs, states])

Returns a tuple with all variables.

define_controller(A, B, C, f, eta, phi)

Define the Dynamic controller given by the differential equations:

hurwitz(matrix)

Check whether a time-invariant matrix is Hurwitz.

linearize(working_point_states[, …])

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

observability_linear(A, C)

Observability check of two matrices using the Kalman rank condition for time-invariant linear systems [1].

parallel(contr_append)

A controller is generated which is the result of a parallel connection of two controllers.

series(contr_append)

A controller is generated which is the result of a serial connection of two controllers.

simulation(tspan[, number_of_samples, …])

Simulates the system in various conditions.

check_positive_definite

create_states

check_positive_definite(matrix: sympy.matrices.dense.MutableDenseMatrix)[source]
check_symmetry(matrix) → bool[source]

Check if matrix is symmetric. Returns a bool.

convert_to_dynamic_controller()[source]

The Euler-Lagrange formalism is transformed to the state and output equation notation of the DynamicController class.

create_states(size: int, level: int = 0)[source]
property damping_matrix

!! processed by numpydoc !!

property gain_dinputs

!! processed by numpydoc !!

property gain_inputs

!! processed by numpydoc !!

property inertia_matrix

!! processed by numpydoc !!

property nonlinear_coefficient_matrix

!! processed by numpydoc !!

property nonlinear_fcts

!! processed by numpydoc !!

property nonlinear_fcts_callable

!! processed by numpydoc !!

property stiffness_matrix

!! processed by numpydoc !!