Systems¶
Base System¶
-
class
nlcontrol.systems.system.
SystemBase
(states, inputs, sys=None)[source]¶ Bases:
object
Returns a base structure for a system with outputs, optional inputs, and optional states. The system is defines 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)\]A SystemBase object contains several basic functions to manipulate and simulate the system.
- 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 system with one state, one input, and one output:
>>> from simupy.systems.symbolic import MemorylessSystem, DynamicalSystem >>> from sympy.tensor.array import Array >>> states = 'x' >>> inputs = 'u' >>> sys = SystemBase(states, inputs) >>> x, xdot, u = sys.create_variables() >>> sys.system = DynamicalSystem(state_equation=Array([-x + u1]), state=x, output_equation=x, input_=u1)
- Statefull system with two states, one input, and two outputs:
>>> states = 'x1, x2' >>> inputs = 'u' >>> sys = SystemBase(states, inputs) >>> x1, x2, x1dot, x2dot, u = sys.create_variables() >>> sys.system = DynamicalSystem(state_equation=Array([-x1 + x2**2 + u, -x2 + 0.5 * x1]), state=Array([x1, x2]), output_equation=Array([x1 * x2, x2]), input_=u)
- Stateless system with one input:
>>> states = None >>> inputs = 'w' >>> sys = SystemBase(states, inputs) >>> w = sys.create_variables() >>> sys.system = MemorylessSystem(input_=Array([w]), output_equation= Array([5 * w]))
- Create a copy a SystemBase object `sys’ and linearize around the working point of state [0, 0] and working point of input 0 and simulate:
>>> new_sys = SystemBase(sys.states, sys.inputs, sys.system) >>> new_sys_lin = new_sys.linearize([0, 0], 0) >>> new_sys_lin.simulation(10)
- Attributes
block_configuration
Returns info on the systems: the dimension of the inputs, the states, and the output.
output_equation
expression
containingdynamicsymbols
state_equation
expression
containingdynamicsymbols
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
(sys_append)A system is generated which is the result of a parallel connection of two systems.
series
(sys_append)A system is generated which is the result of a serial connection of two systems.
simulation
(tspan[, number_of_samples, …])Simulates the system in various conditions.
-
property
block_configuration
¶ the dimension of the inputs, the states, and the output. This property is mainly intended for debugging.
- Type
Returns info on the systems
-
create_variables
(input_diffs: bool = False, states=None) → tuple[source]¶ Returns a tuple with all variables. First the states are given, next the derivative of the states, and finally the inputs, optionally followed by the diffs of the inputs. All variables are sympy dynamic symbols.
- Parameters
- input_diffsboolean
also return the differentiated versions of the inputs, default: false.
- statesarray-like
An alternative list of states, used by more complex system models, optional. (see e.g. EulerLagrange.create_variables)
- Returns
- variablestuple
all variables of the system.
Examples
Return the variables of `sys’, which has two states and two inputs and add a system to the SytemBase object:
>>> from sympy.tensor.array import Array >>> from simupy.systems.symbolic import DynamicalSystem >>> x1, x2, x1dot, x2dot, u1, u2, u1dot, u2dot = sys.create_variables(input_diffs=True) >>> state_eq = Array([-5 * x1 + x2 + u1**2, x1/2 - x2**3 + u2]) >>> output_eq = Array([x1 + x2]) >>> sys.system = DynamicalSystem(input_=Array([u1, u2], state=Array([x1, x2], state_equation=state_eq, output_equation=output_eq)
-
linearize
(working_point_states, working_point_inputs=None)[source]¶ In many cases a nonlinear 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 is necessary, but the working point for the input is optional.
- Parameters
- working_point_stateslist or int
the state equations are linearized around the working point of the states.
- working_point_inputslist or int
the state equations are linearized around the working point of the states and inputs.
- 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 system of `sys’ around the state’s working point x[1] = 1 and x[2] = 5 and the input’s working point u = 2:
>>> sys_lin, sys_control = sys.linearize([1, 5], 2) >>> print('Linearized state equation: ', sys_lin.state_equation)
-
property
output_equation
¶ expression
containingdynamicsymbols
The output equation contains sympy’s dynamicsymbols.
-
parallel
(sys_append)[source]¶ A system is generated which is the result of a parallel connection of two systems. 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
- sys_appendSystemBase object
the system that is added in parallel.
- Returns
- A SystemBase object with the parallel system’s equations.
Examples
- Place ‘sys2’ in parallel with ‘sys1’ and show the inputs, states, state equations and output equations:
>>> parallel_sys = sys1.parallel(sys2) >>> 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
(sys_append)[source]¶ A system is generated which is the result of a serial connection of two systems. The outputs of this object are connected to the inputs of the appended system and a new system 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
- sys_appendSystemBase object
the system that is placed in a serial configuration. ‘sys_append’ follows the current system.
- Returns
- A SystemBase object with the serial system’s equations.
Examples
- Place ‘sys1’ behind ‘sys2’ in a serial configuration and show the inputs, states, state equations and output equations:
>>> series_sys = sys1.series(sys2) >>> 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)
-
simulation
(tspan, number_of_samples=100, initial_conditions=None, input_signals=None, plot=False, custom_integrator_options=None)[source]¶ Simulates the system in various conditions. It is possible to impose initial conditions on the states of the system. A specific input signal can be applied to the system to check its behavior. The results of the simulation are numerically available. Also, a plot of the states, inputs, and outputs is available. To simulate the system scipy’s ode is used if the system has states. Both the option of variable time-step and fixed time step are available. If there are no states, a time signal is applied to the system. # 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.
- number_of_samplesint, optional
number of samples in the case that the system is stateless and tspan only indicates the end and/or start time (span is length two or smaller), default: 100
- initial_conditionsint, float, list-like object, optional
the initial conditions of the states of a statefull system. If none is given, all are zero, default: None
- input_signalsSystemBase object
the input signal that is directly connected to the system’s inputs. Preferably, the signals in nlcontrol.signals are used. If no input signal is specified and the system has inputs, all inputs are defaulted to 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 top 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
- A tuple:
- -> statefull system :
- tndarray
time vector.
- xndarray
state vectors.
- yndarray
input and ouput vectors.
- resSimulationResult object
A class object which contains information on events, next to the above vectors.
- -> stateless system :
- tndarray
time vector.
- yndarray
output vectors.
- undarray
input vectors. Is an empty list if the system has no inputs.
Examples
- A simulation of 20 seconds of the statefull system ‘sys’ for a set of initial conditions [x0_0, x1_0, x2_0] and plot the results:
>>> init_cond = [0.3, 5.7, 2] >>> t, x, y, u, res = sys.simulation(20, initial_conditions=init_cond)
- A simulation from second 2 to 18 of the statefull system ‘sys’ for an input signal, which is a step from 0.4 to 1.3 at second 5 for input 1 and from 0.9 to 1.1 at second 7. Use 1000 nsteps for the integrator. No plot is required:
>>> from nlcontrol.signals import step >>> step_signal = step(step_times=[5, 7], begin_values=[0.4, 0.9], end_values=[1.3, 11]) >>> integrator_options = {'nsteps': 1000} >>> t, x, y, u, res = sys.simulation([2, 18], input_signals=step_signal, custom_integrator_options=integrator_options)
- Plot the stateless signal step from previous example for a custom time axis (a time axis going from 3 seconds to 20 seconds with 1000 equidistant samples in between):
>>> import numpy as np >>> time_axis = np.linspace(3, 20, 1000) >>> t, y, _ = step_signal.simulation(time_axis, plot=True) Or >>> t, y, _ = step_signal.simulation([3, 20], number_of_samples=1000, plot=True)
- Simulate the stateless system ‘sys_stateless’ with input signal step_signal from the previous examples for 40 seconds with 1500 samples in between and plot:
>>> t, y, u = sys_stateless.simulation(40, number_of_samples=1500, input_signals=step_signal, plot=True)
-
property
state_equation
¶ expression
containingdynamicsymbols
The state equation contains sympy’s dynamicsymbols.
-
property
system
¶ simupy's DynamicalSystem
The system attribute of the SystemBase class. The system is defined using simupy’s DynamicalSystem.
Specific Systems¶
-
class
nlcontrol.systems.eula.
EulerLagrange
(states, inputs, sys=None)[source]¶ Bases:
nlcontrol.systems.system.SystemBase
A class that defines SystemBase object using an Euler-Lagrange formulation:
\[M(x).x'' + C(x, x').x' + K(x)= F(u)\]Here, x represents a minimal state:
\[[x_1, x_2, ...]\]the apostrophe represents a time derivative, and u is the input vector:
\[[u_1, u_2, ...]\]A SystemBase object uses a state equation function of the form:
\[x' = f(x, u)\]However, as system contains second time derivatives of the state, an extended state x* is necessary containing the minimized states and its first time derivatives:
\[x^{*} = [x_1, x_1', x_2, x_2', ...]\]which makes it possible to adhere to the SystemBase formulation:
\[x^{*'} = f(x^{*}, u)\]- 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.
- syssimupy’s DynamicalSystem object (simupy.systems.symbolic), optional
the object containing output and state equations, default: None.
Examples
- Create a EulerLagrange object with two states and two inputs:
>>> 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)
- Get the Euler-Lagrange matrices and the state equations:
>>> M = sys.inertia_matrix >>> C = sys.damping_matrix >>> K = sys.stiffness_matrix >>> F = sys.force_vector >>> xdot = sys.state_equation
- Linearize an Euler-Lagrange system around the state’s working point [0, 0, 0, 0] and the input’s working point = [0, 0] and simulate for a step input and initial conditions
>>> sys_lin, _ = sys.linearize([0, 0, 0, 0], [0, 0]) >>> from nlcontrol.signals import step >>> step_sgnl = step(2) >>> init_cond = [1, 2, 0.5, 4] >>> sys_lin.simulation(5, initial_conditions=init_cond, input_signals=step_sgnl, plot=True)
- Attributes
block_configuration
Returns info on the systems: the dimension of the inputs, the states, and the output.
damping_matrix
sympy Matrix
force_vector
sympy Matrix
inertia_matrix
sympy Matrix
output_equation
expression
containingdynamicsymbols
state_equation
expression
containingdynamicsymbols
stiffness_matrix
sympy Matrix
system
simupy's DynamicalSystem
Methods
check_symmetry
(matrix)Check if matrix is symmetric.
As the system contains a second derivative of the states, an extended state should be used, which contains the first derivative of the states as well.
create_variables
([input_diffs])Returns a tuple with all variables.
define_system
(M, C, K, F)Define the Euler-Lagrange system using the differential equation representation:
linearize
(working_point_states[, …])In many cases a nonlinear system is observed around a certain working point.
parallel
(sys_append)A system is generated which is the result of a parallel connection of two systems.
series
(sys_append)A system is generated which is the result of a serial connection of two systems.
simulation
(tspan[, number_of_samples, …])Simulates the system in various conditions.
-
check_symmetry
(matrix) → bool[source]¶ Check if matrix is symmetric. Returns a bool.
- Returns
- valuebool
the matrix being symmetric or not.
-
create_state_equations
()[source]¶ As the system contains a second derivative of the states, an extended state should be used, which contains the first derivative of the states as well. Therefore, the state equation has to be adapted to this new state vector.
- Returns
- resultsympy array object
the state equation for each element in self.states
-
create_variables
(input_diffs: bool = False)[source]¶ Returns a tuple with all variables. First the states are given, next the derivative of the states, and finally the inputs, optionally followed by the diffs of the inputs. All variables are sympy dynamic symbols.
- Parameters
- input_diffsboolean
also return the differentiated versions of the inputs, default: false.
- Returns
- variablestuple
all variables of the system.
Examples
- Return the variables of ‘sys’, which has two states and two inputs and add a system to the EulerLagrange object:
>>> x1, x2, x1dot, x2dot, u1, u2, u1dot, u2dot = sys.create_variables(input_diffs=True) >>> M = [[1, x1*x2], [x1*x2, 1]] >>> C = [[2*x1dot, 1 + x1], [x2 - 2, 3*x2dot]] >>> K = [x1, 2*x2] >>> F = [u1, 0] >>> sys.define_system(M, C, K, F)
-
property
damping_matrix
¶ sympy Matrix
The matrix represents the damping and coriolis forces. More on sympy’s Matrix.
-
define_system
(M, C, K, F)[source]¶ Define the Euler-Lagrange system using the differential equation representation:
\[M(x).x'' + C(x, x').x' + K(x)= F(u)\]Here, x is the minimal state vector created in the constructor. The state-space model is generated in the form \(x^{*'} = f(x^*, u)\), with \(x^* = [x_1, dx_1, x_2, dx_2, ...]\), the extended state vector. The output is the minimal state vector.
Note
Use create_variables() for an easy notation of state[i] and dstate[i].
-
property
force_vector
¶ sympy Matrix
The matrix represents the external force or torque vector. This is a non-square matrix. More on sympy’s Matrix.
-
property
inertia_matrix
¶ sympy Matrix
The matrix represents the inertia forces and it is checked that it is positive definite and symmetric. More on sympy’s Matrix.
-
property
stiffness_matrix
¶ sympy Matrix
The matrix represents the elastic and centrifugal forces. More on sympy’s Matrix.
Utilities¶
-
nlcontrol.systems.utils.
read_simulation_result_from_csv
(file_name, plot=False)[source]¶ Read a csv file created with write_simulation_result_to_csv() containing simulation results. Based on the header it is determined if the results contains input or event vector. There is a possibility to create plot of the data.
- Parameters
- file_namestring
The filename of the csv file, containing the extension.
- plotboolean, optional
Create a plot, default: False
- Returns
- tuple :
- tnumpy array
The time vector.
- xnumpy array
The state vectors.
- ynumpy array
The output vectors. Contains the inputs, when the data contains the event vector.
- u or enumpy array
The input vectors or event vectors. See boolean ‘contains_u’ to know which one.
- contains_uboolean
Indicates whether the output contains the input or event vector.
Examples
- Read and plot a csv file ‘results.csv’ with an input vector:
>>> t, x, y, u, contains_u = read_simulation_result_from_csv('results.csv', plot=True) >>> print(contains_u) True
- Read and plot a csv file ‘results.csv’ with an event vector:
>>> t, x, y, e, contains_u = read_simulation_result_from_csv('results.csv', plot=True) >>> print(contains_u) False
-
nlcontrol.systems.utils.
write_simulation_result_to_csv
(simulation_result, file_name=None)[source]¶ Write the results of a SimulationResult object (see simupy.BlockDiagram.simulate) to a csv file. This object type is also returned by a SystemBase’s simulation function.
- Parameters
- simulation_resultSimulationResult object or list
Results of a simulation packaged as Simupy’s SimulationResult object or a list which includes the time, input, state, and output vector in this order.
- file_namestring
The filename of the newly created csv file. Defaults to a timestamp.
Examples
- Simulate a SystemBase object called ‘sys’ and store the results:
>>> t, x, y, u, res = sys.simulation(1) >>> write_simulation_result_to_csv(res, file_name='use_simulation_result_object') >>> write_simulation_result_to_csv([t, u, x, y], file_name='use_separate_vectors')