Nonlinear models

pynamics.models.state_space_models.NonlinearModel(initial_state, initial_control, state_update_fcn, state_output_fcn, input_dim, output_dim, input_labels=None, output_labels=None)

Bases: BaseModel

Generic nonlinear state-space model.

This class implements a generic continuous nonlinear state-space model. Since both the state equations and the output equations are user-defined, time-varying systems are supported. In order to implement such a system, the state and/or the output equations should explicitly dependent on time.

Parameters:

Name Type Description Default
initial_state ndarray

The system's state vector. Should be an array shaped (n, 1), where n is the number of state variables.

required
initial_control ndarray

Input vector. Should be an array shaped (u, 1), where u is the number of input variables.

required
state_update_fcn callable

State update function. This function should implement the system's state equations, i.e. it should compute its state derivatives given the inputs and the current state vector.

required
state_output_fcn callable

Output function. This function should implement the system's output equations, i.e. it should compute its output vector given the inputs and the current state vector.

required
input_dim int

Number of system inputs.

required
output_dim int

Number of system outputs.

required
input_labels list[str]

List of input labels.

None
output_labels list[str]

List of output labels.

None

Attributes:

Name Type Description
x ndarray

The system's state. Should be an array of shape (n, 1), where n is the number of variables.

state_equations callable

The state equations. These describe the evolution of the system's state depending on its current state and its inputs.

output_equations callable

The output equations. These relate the system's state to its output.

u ndarray

The current control action, or set of control actions, defined as an (n, 1)-shaped array, where n is the number of controlled inputs.

Methods:

Name Description
get_state

Get the current state vector.

get_output

Compute the system's output from the current state.

get_input

Get the current inputs.

set_input

Pass new inputs to the system.

update_state

Assign new values to the system's state vector.

eval

Compute the system's state derivative.

See also

LinearModel: Implements a linear time-invariant state-space model.

Notes

A generic, nonlinear state-space model describes the relations between inputs and ouputs using nonlinear differential equations of the form:

\[ \dot{x}(t) = f(x(t), u(t), t) \]
\[ y(t) = g(x(t), u(t), t) \]

where \(x(t)\) is the system's state vector, \(u(t)\) is its input vector, \(y(t)\) is the output vector, and t is the time variable. f(.) represents the state equations, while g(.) stands for the output equations.

Source code in pynamics/models/state_space_models.py
def __init__(self, 
             initial_state: np.ndarray, 
             initial_control: np.ndarray, 
             state_update_fcn: callable, 
             state_output_fcn: callable, 
             input_dim: int, 
             output_dim: int,
             input_labels: list[str] | None=None, 
             output_labels: list[str] | None=None) -> None:

    """
    Class constructor.
    """

    super().__init__(initial_state, input_dim, output_dim, input_labels, output_labels);
    self.state_equations = state_update_fcn;
    self.output_equations = state_output_fcn;
    self.u = self._control_type_checks(initial_control);

    return;

eval(t, x)

Compute the system's state derivative.

This method computes the system's state derivative via the state equation: \(\dot{x} = f(x(t), u(t), t)\), where \(x(t)\) is the state vector, \(u(t)\) is the input vector, \(t\) is the time instant, and \(f(.)\) are the state equations.

Parameters:

Name Type Description Default
t float

Time instant. Used for compatibility reasons. Unused by this method.

required
x ndarray

The current state vector.

required

Returns:

Type Description
ndarray

The system's state derivative.

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.ones((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>> 
>>> model.eval(t=0.0, x=model.get_state())
array([[2.08060461],
       [2.        ]])
Source code in pynamics/models/state_space_models.py
def eval(self, t: float, x: np.ndarray) -> np.ndarray:
    """
    Compute the system's state derivative.

    This method computes the system's state derivative via the state \
    equation: $\dot{x} = f(x(t), u(t), t)$, where $x(t)$ is the state vector, \
    $u(t)$ is the input vector, $t$ is the time instant, and $f(.)$ are the state equations.

    Parameters
    ----------
    t : float
        Time instant. Used for compatibility reasons. Unused by this method.

    x : np.ndarray
        The current state vector.

    Returns
    -------
    np.ndarray
        The system's state derivative.

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.ones((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>> 
    >>> model.eval(t=0.0, x=model.get_state())
    array([[2.08060461],
           [2.        ]])
    """

    return self.state_equations(x, self.u, t);

get_input()

Access the system's input.

This method can be use to access the current input vector.

Returns:

Type Description
ndarray

Current input vector.

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.ones((2, 1)), 2.5 * np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>>
>>> model.get_input()
array([[2.5]])
Source code in pynamics/models/state_space_models.py
def get_input(self) -> np.ndarray:
    """
    Access the system's input.

    This method can be use to access the current input vector.

    Returns
    -------
    np.ndarray
        Current input vector.

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.ones((2, 1)), 2.5 * np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>>
    >>> model.get_input()
    array([[2.5]])
    """

    return self.u;

get_output()

Compute the system's output from the current state vector.

This method can be used to compute the output of a nonlinear state-space model from its current state vector. This is done by computing \(y = g(x(t), u(t), t)\), where \(y(t)\) is the output vector, \(x(t)\) is the state vector, \(u(t)\) is the input vector, \(t\) is the time instant, and \(g(.)\) represents the output equations.

Returns:

Type Description
ndarray

Output vector.

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.ones((2, 1)), np.zeros((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>>
>>> model.get_output()
array([[1.]])
Source code in pynamics/models/state_space_models.py
def get_output(self) -> np.ndarray:
    """
    Compute the system's output from the current state vector.

    This method can be used to compute the output of a nonlinear state-space \
    model from its current state vector. This is done by computing \
    $y = g(x(t), u(t), t)$, where $y(t)$ is the output vector, $x(t)$ is the state vector, \
    $u(t)$ is the input vector, $t$ is the time instant, and $g(.)$ represents the output equations.

    Returns
    -------
    np.ndarray
        Output vector.

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.ones((2, 1)), np.zeros((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>>
    >>> model.get_output()
    array([[1.]])
    """

    return self.output_equations(self.x);

get_state()

Access the system's state.

This method allows one to access the current state vector.

Returns:

Type Description
ndarray

Current state vector.

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.zeros((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>>
>>> model.get_state()
array([[0.],
       [0.]])
Source code in pynamics/models/state_space_models.py
def get_state(self) -> np.ndarray:
    """
    Access the system's state.

    This method allows one to access the current state vector.

    Returns
    -------
    np.ndarray
        Current state vector.

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.zeros((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>>
    >>> model.get_state()
    array([[0.],
           [0.]])
    """

    return self.x;

set_input(u)

Pass a new set of inputs (references, control actions, etc.) to the system.

This method can be used to update the system's input vector directly.

Parameters:

Name Type Description Default
u ndarray | float

The new set of inputs (i.e. input vector).

required

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.ones((2, 1)), 2.5 * np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>>
>>> model.get_input()
array([[2.5]])
>>>
>>> model.set_input(np.array([[5.0]]));
>>> model.get_input();
array([[5.]])
Source code in pynamics/models/state_space_models.py
def set_input(self, u: np.ndarray | float) -> None:
    """
    Pass a new set of inputs (references, control actions, etc.) to the system.

    This method can be used to update the system's input vector directly.

    Parameters
    ----------
    u : np.ndarray | float
        The new set of inputs (i.e. input vector).

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.ones((2, 1)), 2.5 * np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>>
    >>> model.get_input()
    array([[2.5]])
    >>>
    >>> model.set_input(np.array([[5.0]]));
    >>> model.get_input();
    array([[5.]])
    """

    self.u = self._control_type_checks(u);

    return;

update_state(state)

Assign new values to the system's state vector.

This method can be used to update the system's state vector directly.

Parameters:

Name Type Description Default
state ndarray

New state vector.

required

Examples:

>>> import numpy as np
>>> from pynamics.models.state_space_models import NonlinearModel
>>>
>>> # Define the state function.
>>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
...
...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
...     state_derivative_2 = state[1] + control[0];
...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
...
...     return state_derivative;   
>>>
>>> # Define the output function.
>>> def output_function(state: np.ndarray):
...
...     output = np.array([state[0]**state[1]]);
...
...     return output;
>>>
>>> model = NonlinearModel(np.ones((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
>>> 
>>> model.get_state()
array([[1.],
       [1.]])
>>>
>>> model.update_state(np.zeros((2, 1)));
>>> model.get_state()
array([[0.],
       [0.]])
Source code in pynamics/models/state_space_models.py
def update_state(self, state: np.ndarray) -> None:
    """
    Assign new values to the system's state vector.

    This method can be used to update the system's state vector directly.

    Parameters
    ----------
    state : np.ndarray
        New state vector.

    Examples
    --------
    >>> import numpy as np
    >>> from pynamics.models.state_space_models import NonlinearModel
    >>>
    >>> # Define the state function.
    >>> def state_function(state: np.ndarray, control: np.ndarray, time: float):
    ...
    ...     state_derivative_1 = state[0] + 2 * np.cos(state[1]);
    ...     state_derivative_2 = state[1] + control[0];
    ...     state_derivative = np.array([state_derivative_1, state_derivative_2]);
    ...
    ...     return state_derivative;   
    >>>
    >>> # Define the output function.
    >>> def output_function(state: np.ndarray):
    ...
    ...     output = np.array([state[0]**state[1]]);
    ...
    ...     return output;
    >>>
    >>> model = NonlinearModel(np.ones((2, 1)), np.ones((1, 1)), state_function, output_function, input_dim=2, output_dim=1);
    >>> 
    >>> model.get_state()
    array([[1.],
           [1.]])
    >>>
    >>> model.update_state(np.zeros((2, 1)));
    >>> model.get_state()
    array([[0.],
           [0.]])
    """

    self.x = state;

    return;