diff --git a/control/__init__.py b/control/__init__.py index 57f2d2690..386fa91c1 100644 --- a/control/__init__.py +++ b/control/__init__.py @@ -61,6 +61,7 @@ from .rlocus import * from .statefbk import * from .statesp import * +from .stochsys import * from .timeresp import * from .xferfcn import * from .ctrlutil import * diff --git a/control/iosys.py b/control/iosys.py index ccfdba2ca..161f06510 100644 --- a/control/iosys.py +++ b/control/iosys.py @@ -1585,11 +1585,17 @@ def input_output_response( T : array-like Time steps at which the input is defined; values must be evenly spaced. - U : array-like or number, optional - Input array giving input at each time `T` (default = 0). - - X0 : array-like or number, optional - Initial condition (default = 0). + U : array-like, list, or number, optional + Input array giving input at each time `T` (default = 0). If a list + is specified, each element in the list will be treated as a portion + of the input and broadcast (if necessary) to match the time vector. + + X0 : array-like, list, or number, optional + Initial condition (default = 0). If a list is given, each element + in the list will be flattened and stacked into the initial + condition. If a smaller number of elements are given that the + number of states in the system, the initial condition will be padded + with zeros. return_x : bool, optional If True, return the state vector when assigning to a tuple (default = @@ -1641,6 +1647,16 @@ def input_output_response( ValueError If time step does not match sampling time (for discrete time systems). + Notes + ----- + 1. If a smaller number of initial conditions are given than the number of + states in the system, the initial conditions will be padded with + zeros. This is often useful for interconnected control systems where + the process dynamics are the first system and all other components + start with zero initial condition since this can be specified as + [xsys_0, 0]. A warning is issued if the initial conditions are padded + and and the final listed initial state is not zero. + """ # # Process keyword arguments @@ -1656,14 +1672,14 @@ def input_output_response( raise ValueError("ivp_method specified more than once") solve_ivp_kwargs['method'] = kwargs.pop('solve_ivp_method') - # Make sure there were no extraneous keywords - if kwargs: - raise TypeError("unrecognized keywords: ", str(kwargs)) - # Set the default method to 'RK45' if solve_ivp_kwargs.get('method', None) is None: solve_ivp_kwargs['method'] = 'RK45' + # Make sure there were no extraneous keywords + if kwargs: + raise TypeError("unrecognized keyword(s): ", str(kwargs)) + # Sanity checking on the input if not isinstance(sys, InputOutputSystem): raise TypeError("System of type ", type(sys), " not valid") @@ -1683,19 +1699,75 @@ def input_output_response( # Use the input time points as the output time points t_eval = T - # Check and convert the input, if needed - # TODO: improve MIMO ninputs check (choose from U) + # If we were passed a list of input, concatenate them (w/ broadcast) + if isinstance(U, (tuple, list)) and len(U) != ntimepts: + U_elements = [] + for i, u in enumerate(U): + u = np.array(u) # convert everyting to an array + # Process this input + if u.ndim == 0 or (u.ndim == 1 and u.shape[0] != T.shape[0]): + # Broadcast array to the length of the time input + u = np.outer(u, np.ones_like(T)) + + elif (u.ndim == 1 and u.shape[0] == T.shape[0]) or \ + (u.ndim == 2 and u.shape[1] == T.shape[0]): + # No processing necessary; just stack + pass + + else: + raise ValueError(f"Input element {i} has inconsistent shape") + + # Append this input to our list + U_elements.append(u) + + # Save the newly created input vector + U = np.vstack(U_elements) + + # Make sure the input has the right shape if sys.ninputs is None or sys.ninputs == 1: legal_shapes = [(ntimepts,), (1, ntimepts)] else: legal_shapes = [(sys.ninputs, ntimepts)] + U = _check_convert_array(U, legal_shapes, 'Parameter ``U``: ', squeeze=False) + + # Always store the input as a 2D array U = U.reshape(-1, ntimepts) ninputs = U.shape[0] - # create X0 if not given, test if X0 has correct shape + # If we were passed a list of initial states, concatenate them + if isinstance(X0, (tuple, list)): + X0_list = [] + for i, x0 in enumerate(X0): + x0 = np.array(x0).reshape(-1) # convert everyting to 1D array + X0_list += x0.tolist() # add elements to initial state + + # Save the newly created input vector + X0 = np.array(X0_list) + + # If the initial state is too short, make it longer (NB: sys.nstates + # could be None if nstates comes from size of initial condition) + if sys.nstates and isinstance(X0, np.ndarray) and X0.size < sys.nstates: + if X0[-1] != 0: + warn("initial state too short; padding with zeros") + X0 = np.hstack([X0, np.zeros(sys.nstates - X0.size)]) + + # Check to make sure this is not a static function nstates = _find_size(sys.nstates, X0) + if nstates == 0: + # No states => map input to output + u = U[0] if len(U.shape) == 1 else U[:, 0] + y = np.zeros((np.shape(sys._out(T[0], X0, u))[0], len(T))) + for i in range(len(T)): + u = U[i] if len(U.shape) == 1 else U[:, i] + y[:, i] = sys._out(T[i], [], u) + return TimeResponseData( + T, y, None, U, issiso=sys.issiso(), + output_labels=sys.output_index, input_labels=sys.input_index, + transpose=transpose, return_x=return_x, squeeze=squeeze) + + # create X0 if not given, test if X0 has correct shape X0 = _check_convert_array(X0, [(nstates,), (nstates, 1)], 'Parameter ``X0``: ', squeeze=True) diff --git a/control/optimal.py b/control/optimal.py index aea9b02b8..da1bdcb8e 100644 --- a/control/optimal.py +++ b/control/optimal.py @@ -776,7 +776,7 @@ def create_mpc_iosystem(self): """Create an I/O system implementing an MPC controller""" # Check to make sure we are in discrete time if self.system.dt == 0: - raise ControlNotImplemented( + raise ct.ControlNotImplemented( "MPC for continuous time systems not implemented") def _update(t, x, u, params={}): diff --git a/control/sisotool.py b/control/sisotool.py index b47eb7e40..41f21ecbe 100644 --- a/control/sisotool.py +++ b/control/sisotool.py @@ -215,14 +215,14 @@ def rootlocus_pid_designer(plant, gain='P', sign=+1, input_signal='r', derivative terms are given instead by Kp, Ki*dt/2*(z+1)/(z-1), and Kd/dt*(z-1)/z, respectively. - ------> C_ff ------ d - | | | - r | e V V u y - ------->O---> C_f --->O--->O---> plant ---> - ^- ^- | - | | | - | ----- C_b <-------| - --------------------------------- + ------> C_ff ------ d + | | | + r | e V V u y + ------->O---> C_f --->O--->O---> plant ---> + ^- ^- | + | | | + | ----- C_b <-------| + --------------------------------- It is also possible to move the derivative term into the feedback path `C_b` using `derivative_in_feedback_path=True`. This may be desired to @@ -234,8 +234,8 @@ def rootlocus_pid_designer(plant, gain='P', sign=+1, input_signal='r', Remark: It may be helpful to zoom in using the magnifying glass on the plot. Just ake sure to deactivate magnification mode when you are done by - clicking the magnifying glass. Otherwise you will not be able to be able to choose - a gain on the root locus plot. + clicking the magnifying glass. Otherwise you will not be able to be able + to choose a gain on the root locus plot. Parameters ---------- @@ -269,6 +269,7 @@ def rootlocus_pid_designer(plant, gain='P', sign=+1, input_signal='r', ---------- closedloop : class:`StateSpace` system The closed-loop system using initial gains. + """ plant = _convert_to_statespace(plant) diff --git a/control/statefbk.py b/control/statefbk.py index 099baa225..0aaf49f61 100644 --- a/control/statefbk.py +++ b/control/statefbk.py @@ -70,8 +70,8 @@ def sb03md(n, C, A, U, dico, job='X',fact='N',trana='N',ldwork=None): sb03od = None -__all__ = ['ctrb', 'obsv', 'gram', 'place', 'place_varga', 'lqr', 'lqe', - 'dlqr', 'dlqe', 'acker', 'create_statefbk_iosystem'] +__all__ = ['ctrb', 'obsv', 'gram', 'place', 'place_varga', 'lqr', + 'dlqr', 'acker', 'create_statefbk_iosystem'] # Pole placement @@ -260,270 +260,6 @@ def place_varga(A, B, p, dtime=False, alpha=None): return _ssmatrix(-F) -# contributed by Sawyer B. Fuller -def lqe(*args, method=None): - """lqe(A, G, C, QN, RN, [, NN]) - - Linear quadratic estimator design (Kalman filter) for continuous-time - systems. Given the system - - .. math:: - - x &= Ax + Bu + Gw \\\\ - y &= Cx + Du + v - - with unbiased process noise w and measurement noise v with covariances - - .. math:: E{ww'} = QN, E{vv'} = RN, E{wv'} = NN - - The lqe() function computes the observer gain matrix L such that the - stationary (non-time-varying) Kalman filter - - .. math:: x_e = A x_e + B u + L(y - C x_e - D u) - - produces a state estimate x_e that minimizes the expected squared error - using the sensor measurements y. The noise cross-correlation `NN` is - set to zero when omitted. - - The function can be called with either 3, 4, 5, or 6 arguments: - - * ``L, P, E = lqe(sys, QN, RN)`` - * ``L, P, E = lqe(sys, QN, RN, NN)`` - * ``L, P, E = lqe(A, G, C, QN, RN)`` - * ``L, P, E = lqe(A, G, C, QN, RN, NN)`` - - where `sys` is an `LTI` object, and `A`, `G`, `C`, `QN`, `RN`, and `NN` - are 2D arrays or matrices of appropriate dimension. - - Parameters - ---------- - A, G, C : 2D array_like - Dynamics, process noise (disturbance), and output matrices - sys : LTI (StateSpace or TransferFunction) - Linear I/O system, with the process noise input taken as the system - input. - QN, RN : 2D array_like - Process and sensor noise covariance matrices - NN : 2D array, optional - Cross covariance matrix. Not currently implemented. - method : str, optional - Set the method used for computing the result. Current methods are - 'slycot' and 'scipy'. If set to None (default), try 'slycot' first - and then 'scipy'. - - Returns - ------- - L : 2D array (or matrix) - Kalman estimator gain - P : 2D array (or matrix) - Solution to Riccati equation - - .. math:: - - A P + P A^T - (P C^T + G N) R^{-1} (C P + N^T G^T) + G Q G^T = 0 - - E : 1D array - Eigenvalues of estimator poles eig(A - L C) - - Notes - ----- - 1. If the first argument is an LTI object, then this object will be used - to define the dynamics, noise and output matrices. Furthermore, if - the LTI object corresponds to a discrete time system, the ``dlqe()`` - function will be called. - - 2. The return type for 2D arrays depends on the default class set for - state space operations. See :func:`~control.use_numpy_matrix`. - - Examples - -------- - >>> L, P, E = lqe(A, G, C, QN, RN) - >>> L, P, E = lqe(A, G, C, Q, RN, NN) - - See Also - -------- - lqr, dlqe, dlqr - - """ - - # TODO: incorporate cross-covariance NN, something like this, - # which doesn't work for some reason - # if NN is None: - # NN = np.zeros(QN.size(0),RN.size(1)) - # NG = G @ NN - - # - # Process the arguments and figure out what inputs we received - # - - # If we were passed a discrete time system as the first arg, use dlqe() - if isinstance(args[0], LTI) and isdtime(args[0], strict=True): - # Call dlqe - return dlqe(*args, method=method) - - # Get the system description - if (len(args) < 3): - raise ControlArgument("not enough input arguments") - - # If we were passed a state space system, use that to get system matrices - if isinstance(args[0], StateSpace): - A = np.array(args[0].A, ndmin=2, dtype=float) - G = np.array(args[0].B, ndmin=2, dtype=float) - C = np.array(args[0].C, ndmin=2, dtype=float) - index = 1 - - elif isinstance(args[0], LTI): - # Don't allow other types of LTI systems - raise ControlArgument("LTI system must be in state space form") - - else: - # Arguments should be A and B matrices - A = np.array(args[0], ndmin=2, dtype=float) - G = np.array(args[1], ndmin=2, dtype=float) - C = np.array(args[2], ndmin=2, dtype=float) - index = 3 - - # Get the weighting matrices (converting to matrices, if needed) - QN = np.array(args[index], ndmin=2, dtype=float) - RN = np.array(args[index+1], ndmin=2, dtype=float) - - # Get the cross-covariance matrix, if given - if (len(args) > index + 2): - NN = np.array(args[index+2], ndmin=2, dtype=float) - raise ControlNotImplemented("cross-covariance not implemented") - - else: - # For future use (not currently used below) - NN = np.zeros((QN.shape[0], RN.shape[1])) - - # Check dimensions of G (needed before calling care()) - _check_shape("QN", QN, G.shape[1], G.shape[1]) - - # Compute the result (dimension and symmetry checking done in care()) - P, E, LT = care(A.T, C.T, G @ QN @ G.T, RN, method=method, - B_s="C", Q_s="QN", R_s="RN", S_s="NN") - return _ssmatrix(LT.T), _ssmatrix(P), E - - -# contributed by Sawyer B. Fuller -def dlqe(*args, method=None): - """dlqe(A, G, C, QN, RN, [, N]) - - Linear quadratic estimator design (Kalman filter) for discrete-time - systems. Given the system - - .. math:: - - x[n+1] &= Ax[n] + Bu[n] + Gw[n] \\\\ - y[n] &= Cx[n] + Du[n] + v[n] - - with unbiased process noise w and measurement noise v with covariances - - .. math:: E{ww'} = QN, E{vv'} = RN, E{wv'} = NN - - The dlqe() function computes the observer gain matrix L such that the - stationary (non-time-varying) Kalman filter - - .. math:: x_e[n+1] = A x_e[n] + B u[n] + L(y[n] - C x_e[n] - D u[n]) - - produces a state estimate x_e[n] that minimizes the expected squared error - using the sensor measurements y. The noise cross-correlation `NN` is - set to zero when omitted. - - Parameters - ---------- - A, G : 2D array_like - Dynamics and noise input matrices - QN, RN : 2D array_like - Process and sensor noise covariance matrices - NN : 2D array, optional - Cross covariance matrix (not yet supported) - method : str, optional - Set the method used for computing the result. Current methods are - 'slycot' and 'scipy'. If set to None (default), try 'slycot' first - and then 'scipy'. - - Returns - ------- - L : 2D array (or matrix) - Kalman estimator gain - P : 2D array (or matrix) - Solution to Riccati equation - - .. math:: - - A P + P A^T - (P C^T + G N) R^{-1} (C P + N^T G^T) + G Q G^T = 0 - - E : 1D array - Eigenvalues of estimator poles eig(A - L C) - - Notes - ----- - The return type for 2D arrays depends on the default class set for - state space operations. See :func:`~control.use_numpy_matrix`. - - Examples - -------- - >>> L, P, E = dlqe(A, G, C, QN, RN) - >>> L, P, E = dlqe(A, G, C, QN, RN, NN) - - See Also - -------- - dlqr, lqe, lqr - - """ - - # - # Process the arguments and figure out what inputs we received - # - - # Get the system description - if (len(args) < 3): - raise ControlArgument("not enough input arguments") - - # If we were passed a continus time system as the first arg, raise error - if isinstance(args[0], LTI) and isctime(args[0], strict=True): - raise ControlArgument("dlqr() called with a continuous time system") - - # If we were passed a state space system, use that to get system matrices - if isinstance(args[0], StateSpace): - A = np.array(args[0].A, ndmin=2, dtype=float) - G = np.array(args[0].B, ndmin=2, dtype=float) - C = np.array(args[0].C, ndmin=2, dtype=float) - index = 1 - - elif isinstance(args[0], LTI): - # Don't allow other types of LTI systems - raise ControlArgument("LTI system must be in state space form") - - else: - # Arguments should be A and B matrices - A = np.array(args[0], ndmin=2, dtype=float) - G = np.array(args[1], ndmin=2, dtype=float) - C = np.array(args[2], ndmin=2, dtype=float) - index = 3 - - # Get the weighting matrices (converting to matrices, if needed) - QN = np.array(args[index], ndmin=2, dtype=float) - RN = np.array(args[index+1], ndmin=2, dtype=float) - - # TODO: incorporate cross-covariance NN, something like this, - # which doesn't work for some reason - # if NN is None: - # NN = np.zeros(QN.size(0),RN.size(1)) - # NG = G @ NN - if len(args) > index + 2: - NN = np.array(args[index+2], ndmin=2, dtype=float) - raise ControlNotImplemented("cross-covariance not yet implememented") - - # Check dimensions of G (needed before calling care()) - _check_shape("QN", QN, G.shape[1], G.shape[1]) - - # Compute the result (dimension and symmetry checking done in dare()) - P, E, LT = dare(A.T, C.T, G @ QN @ G.T, RN, method=method, - B_s="C", Q_s="QN", R_s="RN", S_s="NN") - return _ssmatrix(LT.T), _ssmatrix(P), E - # Contributed by Roberto Bucher def acker(A, B, poles): """Pole placement using Ackermann method diff --git a/control/stochsys.py b/control/stochsys.py new file mode 100644 index 000000000..fd276b92c --- /dev/null +++ b/control/stochsys.py @@ -0,0 +1,584 @@ +# stochsys.py - stochastic systems module +# RMM, 16 Mar 2022 +# +# This module contains functions that are intended to be used for analysis +# and design of stochastic control systems, mainly involving Kalman +# filtering and its variants. +# + +"""The :mod:`~control.stochsys` module contains functions for analyzing and +designing stochastic (control) systems, including white noise processes and +Kalman filtering. + +""" + +__license__ = "BSD" +__maintainer__ = "Richard Murray" +__email__ = "murray@cds.caltech.edu" + +import numpy as np +import scipy as sp +from math import sqrt + +from .iosys import InputOutputSystem, NonlinearIOSystem +from .lti import LTI, isctime, isdtime +from .mateqn import care, dare, _check_shape +from .statesp import StateSpace, _ssmatrix +from .exception import ControlArgument, ControlNotImplemented + +__all__ = ['lqe', 'dlqe', 'create_estimator_iosystem', 'white_noise', + 'correlation'] + + +# contributed by Sawyer B. Fuller +def lqe(*args, **kwargs): + """lqe(A, G, C, QN, RN, [, NN]) + + Linear quadratic estimator design (Kalman filter) for continuous-time + systems. Given the system + + .. math:: + + x &= Ax + Bu + Gw \\\\ + y &= Cx + Du + v + + with unbiased process noise w and measurement noise v with covariances + + .. math:: E{ww'} = QN, E{vv'} = RN, E{wv'} = NN + + The lqe() function computes the observer gain matrix L such that the + stationary (non-time-varying) Kalman filter + + .. math:: x_e = A x_e + B u + L(y - C x_e - D u) + + produces a state estimate x_e that minimizes the expected squared error + using the sensor measurements y. The noise cross-correlation `NN` is + set to zero when omitted. + + The function can be called with either 3, 4, 5, or 6 arguments: + + * ``L, P, E = lqe(sys, QN, RN)`` + * ``L, P, E = lqe(sys, QN, RN, NN)`` + * ``L, P, E = lqe(A, G, C, QN, RN)`` + * ``L, P, E = lqe(A, G, C, QN, RN, NN)`` + + where `sys` is an `LTI` object, and `A`, `G`, `C`, `QN`, `RN`, and `NN` + are 2D arrays or matrices of appropriate dimension. + + Parameters + ---------- + A, G, C : 2D array_like + Dynamics, process noise (disturbance), and output matrices + sys : LTI (StateSpace or TransferFunction) + Linear I/O system, with the process noise input taken as the system + input. + QN, RN : 2D array_like + Process and sensor noise covariance matrices + NN : 2D array, optional + Cross covariance matrix. Not currently implemented. + method : str, optional + Set the method used for computing the result. Current methods are + 'slycot' and 'scipy'. If set to None (default), try 'slycot' first + and then 'scipy'. + + Returns + ------- + L : 2D array (or matrix) + Kalman estimator gain + P : 2D array (or matrix) + Solution to Riccati equation + + .. math:: + + A P + P A^T - (P C^T + G N) R^{-1} (C P + N^T G^T) + G Q G^T = 0 + + E : 1D array + Eigenvalues of estimator poles eig(A - L C) + + Notes + ----- + 1. If the first argument is an LTI object, then this object will be used + to define the dynamics, noise and output matrices. Furthermore, if + the LTI object corresponds to a discrete time system, the ``dlqe()`` + function will be called. + + 2. The return type for 2D arrays depends on the default class set for + state space operations. See :func:`~control.use_numpy_matrix`. + + Examples + -------- + >>> L, P, E = lqe(A, G, C, QN, RN) + >>> L, P, E = lqe(A, G, C, Q, RN, NN) + + See Also + -------- + lqr, dlqe, dlqr + + """ + + # TODO: incorporate cross-covariance NN, something like this, + # which doesn't work for some reason + # if NN is None: + # NN = np.zeros(QN.size(0),RN.size(1)) + # NG = G @ NN + + # + # Process the arguments and figure out what inputs we received + # + + # If we were passed a discrete time system as the first arg, use dlqe() + if isinstance(args[0], LTI) and isdtime(args[0], strict=True): + # Call dlqe + return dlqe(*args, **kwargs) + + # Get the method to use (if specified as a keyword) + method = kwargs.pop('method', None) + if kwargs: + raise TypeError("unrecognized keyword(s): ", str(kwargs)) + + # Get the system description + if (len(args) < 3): + raise ControlArgument("not enough input arguments") + + # If we were passed a state space system, use that to get system matrices + if isinstance(args[0], StateSpace): + A = np.array(args[0].A, ndmin=2, dtype=float) + G = np.array(args[0].B, ndmin=2, dtype=float) + C = np.array(args[0].C, ndmin=2, dtype=float) + index = 1 + + elif isinstance(args[0], LTI): + # Don't allow other types of LTI systems + raise ControlArgument("LTI system must be in state space form") + + else: + # Arguments should be A and B matrices + A = np.array(args[0], ndmin=2, dtype=float) + G = np.array(args[1], ndmin=2, dtype=float) + C = np.array(args[2], ndmin=2, dtype=float) + index = 3 + + # Get the weighting matrices (converting to matrices, if needed) + QN = np.array(args[index], ndmin=2, dtype=float) + RN = np.array(args[index+1], ndmin=2, dtype=float) + + # Get the cross-covariance matrix, if given + if (len(args) > index + 2): + NN = np.array(args[index+2], ndmin=2, dtype=float) + raise ControlNotImplemented("cross-covariance not implemented") + + else: + # For future use (not currently used below) + NN = np.zeros((QN.shape[0], RN.shape[1])) + + # Check dimensions of G (needed before calling care()) + _check_shape("QN", QN, G.shape[1], G.shape[1]) + + # Compute the result (dimension and symmetry checking done in care()) + P, E, LT = care(A.T, C.T, G @ QN @ G.T, RN, method=method, + B_s="C", Q_s="QN", R_s="RN", S_s="NN") + return _ssmatrix(LT.T), _ssmatrix(P), E + + +# contributed by Sawyer B. Fuller +def dlqe(*args, **kwargs): + """dlqe(A, G, C, QN, RN, [, N]) + + Linear quadratic estimator design (Kalman filter) for discrete-time + systems. Given the system + + .. math:: + + x[n+1] &= Ax[n] + Bu[n] + Gw[n] \\\\ + y[n] &= Cx[n] + Du[n] + v[n] + + with unbiased process noise w and measurement noise v with covariances + + .. math:: E{ww'} = QN, E{vv'} = RN, E{wv'} = NN + + The dlqe() function computes the observer gain matrix L such that the + stationary (non-time-varying) Kalman filter + + .. math:: x_e[n+1] = A x_e[n] + B u[n] + L(y[n] - C x_e[n] - D u[n]) + + produces a state estimate x_e[n] that minimizes the expected squared error + using the sensor measurements y. The noise cross-correlation `NN` is + set to zero when omitted. + + Parameters + ---------- + A, G : 2D array_like + Dynamics and noise input matrices + QN, RN : 2D array_like + Process and sensor noise covariance matrices + NN : 2D array, optional + Cross covariance matrix (not yet supported) + method : str, optional + Set the method used for computing the result. Current methods are + 'slycot' and 'scipy'. If set to None (default), try 'slycot' first + and then 'scipy'. + + Returns + ------- + L : 2D array (or matrix) + Kalman estimator gain + P : 2D array (or matrix) + Solution to Riccati equation + + .. math:: + + A P + P A^T - (P C^T + G N) R^{-1} (C P + N^T G^T) + G Q G^T = 0 + + E : 1D array + Eigenvalues of estimator poles eig(A - L C) + + Notes + ----- + The return type for 2D arrays depends on the default class set for + state space operations. See :func:`~control.use_numpy_matrix`. + + Examples + -------- + >>> L, P, E = dlqe(A, G, C, QN, RN) + >>> L, P, E = dlqe(A, G, C, QN, RN, NN) + + See Also + -------- + dlqr, lqe, lqr + + """ + + # + # Process the arguments and figure out what inputs we received + # + + # Get the method to use (if specified as a keyword) + method = kwargs.pop('method', None) + if kwargs: + raise TypeError("unrecognized keyword(s): ", str(kwargs)) + + # Get the system description + if (len(args) < 3): + raise ControlArgument("not enough input arguments") + + # If we were passed a continus time system as the first arg, raise error + if isinstance(args[0], LTI) and isctime(args[0], strict=True): + raise ControlArgument("dlqr() called with a continuous time system") + + # If we were passed a state space system, use that to get system matrices + if isinstance(args[0], StateSpace): + A = np.array(args[0].A, ndmin=2, dtype=float) + G = np.array(args[0].B, ndmin=2, dtype=float) + C = np.array(args[0].C, ndmin=2, dtype=float) + index = 1 + + elif isinstance(args[0], LTI): + # Don't allow other types of LTI systems + raise ControlArgument("LTI system must be in state space form") + + else: + # Arguments should be A and B matrices + A = np.array(args[0], ndmin=2, dtype=float) + G = np.array(args[1], ndmin=2, dtype=float) + C = np.array(args[2], ndmin=2, dtype=float) + index = 3 + + # Get the weighting matrices (converting to matrices, if needed) + QN = np.array(args[index], ndmin=2, dtype=float) + RN = np.array(args[index+1], ndmin=2, dtype=float) + + # TODO: incorporate cross-covariance NN, something like this, + # which doesn't work for some reason + # if NN is None: + # NN = np.zeros(QN.size(0),RN.size(1)) + # NG = G @ NN + if len(args) > index + 2: + NN = np.array(args[index+2], ndmin=2, dtype=float) + raise ControlNotImplemented("cross-covariance not yet implememented") + + # Check dimensions of G (needed before calling care()) + _check_shape("QN", QN, G.shape[1], G.shape[1]) + + # Compute the result (dimension and symmetry checking done in dare()) + P, E, LT = dare(A.T, C.T, G @ QN @ G.T, RN, method=method, + B_s="C", Q_s="QN", R_s="RN", S_s="NN") + return _ssmatrix(LT.T), _ssmatrix(P), E + + +# Function to create an estimator +def create_estimator_iosystem( + sys, QN, RN, P0=None, G=None, C=None, + state_labels='xhat[{i}]', output_labels='xhat[{i}]', + covariance_labels='P[{i},{j}]', sensor_labels=None): + """Create an I/O system implementing a linqear quadratic estimator + + This function creates an input/output system that implements a + state estimator of the form + + xhat[k + 1] = A x[k] + B u[k] - L (C xhat[k] - y[k]) + P[k + 1] = A P A^T + F QN F^T - A P C^T Reps^{-1} C P A + L = A P C^T Reps^{-1} + + where Reps = RN + C P C^T. It can be called in the form + + estim = ct.create_estimator_iosystem(sys, QN, RN) + + where ``sys`` is the process dynamics and QN and RN are the covariance + of the disturbance noise and sensor noise. The function returns the + estimator ``estim`` as I/O system with a parameter ``correct`` that can + be used to turn off the correction term in the estimation (for forward + predictions). + + Parameters + ---------- + sys : InputOutputSystem + The I/O system that represents the process dynamics. If no estimator + is given, the output of this system should represent the full state. + QN, RN : ndarray + Process and sensor noise covariance matrices. + P0 : ndarray, optional + Initial covariance matrix. If not specified, defaults to the steady + state covariance. + G : ndarray, optional + Disturbance matrix describing how the disturbances enters the + dynamics. Defaults to sys.B. + C : ndarray, optional + If the system has all full states output, define the measured values + to be used by the estimator. Otherwise, use the system output as the + measured values. + {state, covariance, sensor, output}_labels : str or list of str, optional + Set the name of the signals to use for the internal state, covariance, + sensors, and outputs (state estimate). If a single string is + specified, it should be a format string using the variable ``i`` as an + index (or ``i`` and ``j`` for covariance). Otherwise, a list of + strings matching the size of the respective signal should be used. + Default is ``'xhat[{i}]'`` for state and output labels, ``'y[{i}]'`` + for output labels and ``'P[{i},{j}]'`` for covariance labels. + + Returns + ------- + estim : InputOutputSystem + Input/output system representing the estimator. This system takes the + system input and output and generates the estimated state. + + Notes + ----- + This function can be used with the ``create_statefbk_iosystem()`` function + to create a closed loop, output-feedback, state space controller: + + K, _, _ = ct.lqr(sys, Q, R) + est = ct.create_estimator_iosystem(sys, QN, RN, P0) + ctrl, clsys = ct.create_statefbk_iosystem(sys, K, estimator=est) + + The estimator can also be run on its own to process a noisy signal: + + resp = ct.input_output_response(est, T, [Y, U], [X0, P0]) + + If desired, the ``correct`` parameter can be set to ``False`` to allow + prediction with no additional sensor information: + + resp = ct.input_output_response( + est, T, 0, [X0, P0], param={'correct': False) + + """ + + # Make sure that we were passed an I/O system as an input + if not isinstance(sys, InputOutputSystem): + raise ControlArgument("Input system must be I/O system") + + # Extract the matrices that we need for easy reference + A, B = sys.A, sys.B + + # Set the disturbance and output matrices + G = sys.B if G is None else G + if C is not None: + # Make sure that we have the full system output + if not np.array_equal(sys.C, np.eye(sys.nstates)): + raise ValueError("System output must be full state") + + # Make sure that the output matches the size of RN + if C.shape[0] != RN.shape[0]: + raise ValueError("System output is the wrong size for C") + else: + # Use the system outputs as the sensor outputs + C = sys.C + if sensor_labels is None: + sensor_labels = sys.output_labels + + # Initialize the covariance matrix + if P0 is None: + # Initalize P0 to the steady state value + _, P0, _ = lqe(A, G, C, QN, RN) + + # Figure out the labels to use + if isinstance(state_labels, str): + # Generate the list of labels using the argument as a format string + state_labels = [state_labels.format(i=i) for i in range(sys.nstates)] + + if isinstance(covariance_labels, str): + # Generate the list of labels using the argument as a format string + covariance_labels = [ + covariance_labels.format(i=i, j=j) \ + for i in range(sys.nstates) for j in range(sys.nstates)] + + if isinstance(output_labels, str): + # Generate the list of labels using the argument as a format string + output_labels = [output_labels.format(i=i) for i in range(sys.nstates)] + + sensor_labels = 'y[{i}]' if sensor_labels is None else sensor_labels + if isinstance(sensor_labels, str): + # Generate the list of labels using the argument as a format string + sensor_labels = [sensor_labels.format(i=i) for i in range(C.shape[0])] + + if isctime(sys): + raise NotImplementedError("continuous time not yet implemented") + + else: + # Create an I/O system for the state feedback gains + # Note: reshape vectors into column vectors for legacy np.matrix + def _estim_update(t, x, u, params): + # See if we are estimating or predicting + correct = params.get('correct', True) + + # Get the state of the estimator + xhat = x[0:sys.nstates].reshape(-1, 1) + P = x[sys.nstates:].reshape(sys.nstates, sys.nstates) + + # Extract the inputs to the estimator + y = u[0:C.shape[0]].reshape(-1, 1) + u = u[C.shape[0]:].reshape(-1, 1) + + # Compute the optimal again + Reps_inv = np.linalg.inv(RN + C @ P @ C.T) + L = A @ P @ C.T @ Reps_inv + + # Update the state estimate + dxhat = A @ xhat + B @ u # prediction + if correct: + dxhat -= L @ (C @ xhat - y) # correction + + # Update the covariance + dP = A @ P @ A.T + G @ QN @ G.T + if correct: + dP -= A @ P @ C.T @ Reps_inv @ C @ P @ A.T + + # Return the update + return np.hstack([dxhat.reshape(-1), dP.reshape(-1)]) + + def _estim_output(t, x, u, params): + return x[0:sys.nstates] + + # Define the estimator system + return NonlinearIOSystem( + _estim_update, _estim_output, states=state_labels + covariance_labels, + inputs=sensor_labels + sys.input_labels, outputs=output_labels, + dt=sys.dt) + + +def white_noise(T, Q, dt=0): + """Generate a white noise signal with specified intensity. + + This function generates a (multi-variable) white noise signal of + specified intensity as either a sampled continous time signal or a + discrete time signal. A white noise signal along a 1D array + of linearly spaced set of times T can be computing using + + V = ct.white_noise(T, Q, dt) + + where Q is a positive definite matrix providing the noise intensity. + + In continuous time, the white noise signal is scaled such that the + integral of the covariance over a sample period is Q, thus approximating + a white noise signal. In discrete time, the white noise signal has + covariance Q at each point in time (without any scaling based on the + sample time). + + """ + # Convert input arguments to arrays + T = np.atleast_1d(T) + Q = np.atleast_2d(Q) + + # Check the shape of the input arguments + if len(T.shape) != 1: + raise ValueError("Time vector T must be 1D") + if len(Q.shape) != 2 or Q.shape[0] != Q.shape[1]: + raise ValueError("Covariance matrix Q must be square") + + # Figure out the time increment + if dt != 0: + # Discrete time system => white noise is not scaled + dt = 1 + else: + dt = T[1] - T[0] + + # Make sure data points are equally spaced + if not np.allclose(np.diff(T), T[1] - T[0]): + raise ValueError("Time values must be equally spaced.") + + # Generate independent white noise sources for each input + W = np.array([ + np.random.normal(0, 1/sqrt(dt), T.size) for i in range(Q.shape[0])]) + + # Return a linear combination of the noise sources + return sp.linalg.sqrtm(Q) @ W + +def correlation(T, X, Y=None, squeeze=True): + """Compute the correlation of time signals. + + For a time series X(t) (and optionally Y(t)), the correlation() function + computes the correlation matrix E(X'(t+tau) X(t)) or the cross-correlation + matrix E(X'(t+tau) Y(t)]: + + tau, Rtau = correlation(T, X[, Y]) + + The signal X (and Y, if present) represent a continuous time signal + sampled at times T. The return value provides the correlation Rtau + between X(t+tau) and X(t) at a set of time offets tau. + + Parameters + ---------- + T : 1D array_like + Sample times for the signal(s). + X : 1D or 2D array_like + Values of the signal at each time in T. The signal can either be + scalar or vector values. + Y : 1D or 2D array_like, optional + If present, the signal with which to compute the correlation. + Defaults to X. + squeeze : bool, optional + If True, squeeze Rtau to remove extra dimensions (useful if the + signals are scalars). + + Returns + ------- + + """ + T = np.atleast_1d(T) + X = np.atleast_2d(X) + Y = np.atleast_2d(Y) if Y is not None else X + + # Check the shape of the input arguments + if len(T.shape) != 1: + raise ValueError("Time vector T must be 1D") + if len(X.shape) != 2 or len(Y.shape) != 2: + raise ValueError("Signals X and Y must be 2D arrays") + if T.shape[0] != X.shape[1] or T.shape[0] != Y.shape[1]: + raise ValueError("Signals X and Y must have same length as T") + + # Figure out the time increment + dt = T[1] - T[0] + + # Make sure data points are equally spaced + if not np.allclose(np.diff(T), T[1] - T[0]): + raise ValueError("Time values must be equally spaced.") + + # Compute the correlation matrix + R = np.array( + [[sp.signal.correlate(X[i], Y[j]) + for i in range(X.shape[0])] for j in range(Y.shape[0])] + ) * dt / (T[-1] - T[0]) + # From scipy.signal.correlation_lags (for use with older versions) + # tau = sp.signal.correlation_lags(len(X[0]), len(Y[0])) * dt + tau = np.arange(-len(Y[0]) + 1, len(X[0])) * dt + + return tau, R.squeeze() if squeeze else R diff --git a/control/tests/iosys_test.py b/control/tests/iosys_test.py index 93ce5df65..4e0adfa03 100644 --- a/control/tests/iosys_test.py +++ b/control/tests/iosys_test.py @@ -1711,6 +1711,47 @@ def test_interconnect_unused_output(): outputs=['y'], ignore_outputs=['v']) +def test_input_output_broadcasting(): + # Create a system, time vector, and noisy input + sys = ct.rss(6, 2, 3) + T = np.linspace(0, 10, 10) + U = np.zeros((sys.ninputs, T.size)) + U[0, :] = np.sin(T) + U[1, :] = np.zeros_like(U[1, :]) + U[2, :] = np.ones_like(U[2, :]) + X0 = np.array([1, 2]) + P0 = np.array([[3.11, 3.12], [3.21, 3.3]]) + + # Simulate the system with nominal input to establish baseline + resp_base = ct.input_output_response( + sys, T, U, np.hstack([X0, P0.reshape(-1)])) + + # Split up the inputs into two pieces + resp_inp1 = ct.input_output_response(sys, T, [U[:1], U[1:]], [X0, P0]) + np.testing.assert_equal(resp_base.states, resp_inp1.states) + + # Specify two of the inputs as constants + resp_inp2 = ct.input_output_response(sys, T, [U[0], 0, 1], [X0, P0]) + np.testing.assert_equal(resp_base.states, resp_inp2.states) + + # Specify two of the inputs as constant vector + resp_inp3 = ct.input_output_response(sys, T, [U[0], [0, 1]], [X0, P0]) + np.testing.assert_equal(resp_base.states, resp_inp3.states) + + # Specify only some of the initial conditions + resp_init = ct.input_output_response(sys, T, [U[0], [0, 1]], [X0, 0]) + resp_cov0 = ct.input_output_response(sys, T, U, [X0, P0 * 0]) + np.testing.assert_equal(resp_cov0.states, resp_init.states) + + # Specify only some of the initial conditions + with pytest.warns(UserWarning, match="initial state too short; padding"): + resp_short = ct.input_output_response(sys, T, [U[0], [0, 1]], [X0, 1]) + + # Make sure that inconsistent settings don't work + with pytest.raises(ValueError, match="inconsistent"): + resp_bad = ct.input_output_response( + sys, T, (U[0, :], U[:2, :-1]), [X0, P0]) + def test_nonuniform_timepts(): """Test non-uniform time points for simulations""" sys = ct.LinearIOSystem(ct.rss(2, 1, 1)) diff --git a/control/tests/kwargs_test.py b/control/tests/kwargs_test.py index 0502114dc..818a906a5 100644 --- a/control/tests/kwargs_test.py +++ b/control/tests/kwargs_test.py @@ -81,9 +81,11 @@ def test_unrecognized_kwargs(): sys = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None) table = [ + [control.dlqe, (sys, [[1]], [[1]]), {}], [control.dlqr, (sys, [[1, 0], [0, 1]], [[1]]), {}], [control.drss, (2, 1, 1), {}], [control.input_output_response, (sys, [0, 1, 2], [1, 1, 1]), {}], + [control.lqe, (sys, [[1]], [[1]]), {}], [control.lqr, (sys, [[1, 0], [0, 1]], [[1]]), {}], [control.linearize, (sys, 0, 0), {}], [control.pzmap, (sys,), {}], @@ -154,6 +156,7 @@ def test_matplotlib_kwargs(): 'bode': test_matplotlib_kwargs, 'bode_plot': test_matplotlib_kwargs, 'describing_function_plot': test_matplotlib_kwargs, + 'dlqe': test_unrecognized_kwargs, 'dlqr': statefbk_test.TestStatefbk.test_lqr_errors, 'drss': test_unrecognized_kwargs, 'gangof4': test_matplotlib_kwargs, @@ -161,6 +164,7 @@ def test_matplotlib_kwargs(): 'input_output_response': test_unrecognized_kwargs, 'interconnect': interconnect_test.test_interconnect_exceptions, 'linearize': test_unrecognized_kwargs, + 'lqe': test_unrecognized_kwargs, 'lqr': statefbk_test.TestStatefbk.test_lqr_errors, 'nyquist': test_matplotlib_kwargs, 'nyquist_plot': test_matplotlib_kwargs, diff --git a/control/tests/statefbk_test.py b/control/tests/statefbk_test.py index 10ae85a78..9f04b3723 100644 --- a/control/tests/statefbk_test.py +++ b/control/tests/statefbk_test.py @@ -7,12 +7,12 @@ import pytest import control as ct -from control import lqe, pole, rss, ss, tf +from control import lqe, dlqe, pole, rss, ss, tf from control.exception import ControlDimension, ControlSlycot, \ ControlArgument, slycot_check from control.mateqn import care, dare from control.statefbk import (ctrb, obsv, place, place_varga, lqr, dlqr, - lqe, dlqe, gram, acker) + gram, acker) from control.tests.conftest import (slycotonly, check_deprecated_matrix, ismatarrayout, asmatarrayout) @@ -440,82 +440,6 @@ def testDLQR_warning(self): with pytest.warns(UserWarning): (K, S, E) = dlqr(A, B, Q, R, N) - def check_LQE(self, L, P, poles, G, QN, RN): - P_expected = asmatarrayout(np.sqrt(G @ QN @ G @ RN)) - L_expected = asmatarrayout(P_expected / RN) - poles_expected = -np.squeeze(np.asarray(L_expected)) - np.testing.assert_array_almost_equal(P, P_expected) - np.testing.assert_array_almost_equal(L, L_expected) - np.testing.assert_array_almost_equal(poles, poles_expected) - - @pytest.mark.parametrize("method", [None, 'slycot', 'scipy']) - def test_LQE(self, matarrayin, method): - if method == 'slycot' and not slycot_check(): - return - - A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.]) - L, P, poles = lqe(A, G, C, QN, RN, method=method) - self.check_LQE(L, P, poles, G, QN, RN) - - @pytest.mark.parametrize("cdlqe", [lqe, dlqe]) - def test_lqe_call_format(self, cdlqe): - # Create a random state space system for testing - sys = rss(4, 3, 2) - sys.dt = None # treat as either continuous or discrete time - - # Covariance matrices - Q = np.eye(sys.ninputs) - R = np.eye(sys.noutputs) - N = np.zeros((sys.ninputs, sys.noutputs)) - - # Standard calling format - Lref, Pref, Eref = cdlqe(sys.A, sys.B, sys.C, Q, R) - - # Call with system instead of matricees - L, P, E = cdlqe(sys, Q, R) - np.testing.assert_array_almost_equal(Lref, L) - np.testing.assert_array_almost_equal(Pref, P) - np.testing.assert_array_almost_equal(Eref, E) - - # Make sure we get an error if we specify N - with pytest.raises(ct.ControlNotImplemented): - L, P, E = cdlqe(sys, Q, R, N) - - # Inconsistent system dimensions - with pytest.raises(ct.ControlDimension, match="Incompatible"): - L, P, E = cdlqe(sys.A, sys.C, sys.B, Q, R) - - # Incorrect covariance matrix dimensions - with pytest.raises(ct.ControlDimension, match="Incompatible"): - L, P, E = cdlqe(sys.A, sys.B, sys.C, R, Q) - - # Too few input arguments - with pytest.raises(ct.ControlArgument, match="not enough input"): - L, P, E = cdlqe(sys.A, sys.C) - - # First argument is the wrong type (use SISO for non-slycot tests) - sys_tf = tf(rss(3, 1, 1)) - sys_tf.dt = None # treat as either continuous or discrete time - with pytest.raises(ct.ControlArgument, match="LTI system must be"): - L, P, E = cdlqe(sys_tf, Q, R) - - def check_DLQE(self, L, P, poles, G, QN, RN): - P_expected = asmatarrayout(G.dot(QN).dot(G)) - L_expected = asmatarrayout(0) - poles_expected = -np.squeeze(np.asarray(L_expected)) - np.testing.assert_array_almost_equal(P, P_expected) - np.testing.assert_array_almost_equal(L, L_expected) - np.testing.assert_array_almost_equal(poles, poles_expected) - - @pytest.mark.parametrize("method", [None, 'slycot', 'scipy']) - def test_DLQE(self, matarrayin, method): - if method == 'slycot' and not slycot_check(): - return - - A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.]) - L, P, poles = dlqe(A, G, C, QN, RN, method=method) - self.check_DLQE(L, P, poles, G, QN, RN) - def test_care(self, matarrayin): """Test stabilizing and anti-stabilizing feedback, continuous""" A = matarrayin(np.diag([1, -1])) @@ -584,39 +508,6 @@ def test_lqr_discrete(self): with pytest.raises(ControlArgument, match="dsys must be discrete"): K, S, E = ct.dlqr(csys, Q, R) - def test_lqe_discrete(self): - """Test overloading of lqe operator for discrete time systems""" - csys = ct.rss(2, 1, 1) - dsys = ct.drss(2, 1, 1) - Q = np.eye(1) - R = np.eye(1) - - # Calling with a system versus explicit A, B should be the sam - K_csys, S_csys, E_csys = ct.lqe(csys, Q, R) - K_expl, S_expl, E_expl = ct.lqe(csys.A, csys.B, csys.C, Q, R) - np.testing.assert_almost_equal(K_csys, K_expl) - np.testing.assert_almost_equal(S_csys, S_expl) - np.testing.assert_almost_equal(E_csys, E_expl) - - # Calling lqe() with a discrete time system should call dlqe() - K_lqe, S_lqe, E_lqe = ct.lqe(dsys, Q, R) - K_dlqe, S_dlqe, E_dlqe = ct.dlqe(dsys, Q, R) - np.testing.assert_almost_equal(K_lqe, K_dlqe) - np.testing.assert_almost_equal(S_lqe, S_dlqe) - np.testing.assert_almost_equal(E_lqe, E_dlqe) - - # Calling lqe() with no timebase should call lqe() - asys = ct.ss(csys.A, csys.B, csys.C, csys.D, dt=None) - K_asys, S_asys, E_asys = ct.lqe(asys, Q, R) - K_expl, S_expl, E_expl = ct.lqe(csys.A, csys.B, csys.C, Q, R) - np.testing.assert_almost_equal(K_asys, K_expl) - np.testing.assert_almost_equal(S_asys, S_expl) - np.testing.assert_almost_equal(E_asys, E_expl) - - # Calling dlqe() with a continuous time system should raise an error - with pytest.raises(ControlArgument, match="called with a continuous"): - K, S, E = ct.dlqe(csys, Q, R) - @pytest.mark.parametrize( 'nstates, noutputs, ninputs, nintegrators, type', [(2, 0, 1, 0, None), @@ -630,7 +521,8 @@ def test_lqe_discrete(self): (4, 0, 2, 2, 'nonlinear'), (4, 3, 2, 2, 'nonlinear'), ]) - def test_lqr_iosys(self, nstates, ninputs, noutputs, nintegrators, type): + def test_statefbk_iosys( + self, nstates, ninputs, noutputs, nintegrators, type): # Create the system to be controlled (and estimator) # TODO: make sure it is controllable? if noutputs == 0: diff --git a/control/tests/stochsys_test.py b/control/tests/stochsys_test.py new file mode 100644 index 000000000..11084d9db --- /dev/null +++ b/control/tests/stochsys_test.py @@ -0,0 +1,262 @@ +# stochsys_test.py - test stochastic system operations +# RMM, 16 Mar 2022 + +import numpy as np +import pytest +from control.tests.conftest import asmatarrayout + +import control as ct +from control import lqe, dlqe, rss, drss, tf, ss, ControlArgument, slycot_check + +# Utility function to check LQE answer +def check_LQE(L, P, poles, G, QN, RN): + P_expected = asmatarrayout(np.sqrt(G @ QN @ G @ RN)) + L_expected = asmatarrayout(P_expected / RN) + poles_expected = -np.squeeze(np.asarray(L_expected)) + np.testing.assert_almost_equal(P, P_expected) + np.testing.assert_almost_equal(L, L_expected) + np.testing.assert_almost_equal(poles, poles_expected) + +# Utility function to check discrete LQE solutions +def check_DLQE(L, P, poles, G, QN, RN): + P_expected = asmatarrayout(G.dot(QN).dot(G)) + L_expected = asmatarrayout(0) + poles_expected = -np.squeeze(np.asarray(L_expected)) + np.testing.assert_almost_equal(P, P_expected) + np.testing.assert_almost_equal(L, L_expected) + np.testing.assert_almost_equal(poles, poles_expected) + +@pytest.mark.parametrize("method", [None, 'slycot', 'scipy']) +def test_LQE(matarrayin, method): + if method == 'slycot' and not slycot_check(): + return + + A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.]) + L, P, poles = lqe(A, G, C, QN, RN, method=method) + check_LQE(L, P, poles, G, QN, RN) + +@pytest.mark.parametrize("cdlqe", [lqe, dlqe]) +def test_lqe_call_format(cdlqe): + # Create a random state space system for testing + sys = rss(4, 3, 2) + sys.dt = None # treat as either continuous or discrete time + + # Covariance matrices + Q = np.eye(sys.ninputs) + R = np.eye(sys.noutputs) + N = np.zeros((sys.ninputs, sys.noutputs)) + + # Standard calling format + Lref, Pref, Eref = cdlqe(sys.A, sys.B, sys.C, Q, R) + + # Call with system instead of matricees + L, P, E = cdlqe(sys, Q, R) + np.testing.assert_almost_equal(Lref, L) + np.testing.assert_almost_equal(Pref, P) + np.testing.assert_almost_equal(Eref, E) + + # Make sure we get an error if we specify N + with pytest.raises(ct.ControlNotImplemented): + L, P, E = cdlqe(sys, Q, R, N) + + # Inconsistent system dimensions + with pytest.raises(ct.ControlDimension, match="Incompatible"): + L, P, E = cdlqe(sys.A, sys.C, sys.B, Q, R) + + # Incorrect covariance matrix dimensions + with pytest.raises(ct.ControlDimension, match="Incompatible"): + L, P, E = cdlqe(sys.A, sys.B, sys.C, R, Q) + + # Too few input arguments + with pytest.raises(ct.ControlArgument, match="not enough input"): + L, P, E = cdlqe(sys.A, sys.C) + + # First argument is the wrong type (use SISO for non-slycot tests) + sys_tf = tf(rss(3, 1, 1)) + sys_tf.dt = None # treat as either continuous or discrete time + with pytest.raises(ct.ControlArgument, match="LTI system must be"): + L, P, E = cdlqe(sys_tf, Q, R) + +@pytest.mark.parametrize("method", [None, 'slycot', 'scipy']) +def test_DLQE(matarrayin, method): + if method == 'slycot' and not slycot_check(): + return + + A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.]) + L, P, poles = dlqe(A, G, C, QN, RN, method=method) + check_DLQE(L, P, poles, G, QN, RN) + +def test_lqe_discrete(): + """Test overloading of lqe operator for discrete time systems""" + csys = ct.rss(2, 1, 1) + dsys = ct.drss(2, 1, 1) + Q = np.eye(1) + R = np.eye(1) + + # Calling with a system versus explicit A, B should be the sam + K_csys, S_csys, E_csys = ct.lqe(csys, Q, R) + K_expl, S_expl, E_expl = ct.lqe(csys.A, csys.B, csys.C, Q, R) + np.testing.assert_almost_equal(K_csys, K_expl) + np.testing.assert_almost_equal(S_csys, S_expl) + np.testing.assert_almost_equal(E_csys, E_expl) + + # Calling lqe() with a discrete time system should call dlqe() + K_lqe, S_lqe, E_lqe = ct.lqe(dsys, Q, R) + K_dlqe, S_dlqe, E_dlqe = ct.dlqe(dsys, Q, R) + np.testing.assert_almost_equal(K_lqe, K_dlqe) + np.testing.assert_almost_equal(S_lqe, S_dlqe) + np.testing.assert_almost_equal(E_lqe, E_dlqe) + + # Calling lqe() with no timebase should call lqe() + asys = ct.ss(csys.A, csys.B, csys.C, csys.D, dt=None) + K_asys, S_asys, E_asys = ct.lqe(asys, Q, R) + K_expl, S_expl, E_expl = ct.lqe(csys.A, csys.B, csys.C, Q, R) + np.testing.assert_almost_equal(K_asys, K_expl) + np.testing.assert_almost_equal(S_asys, S_expl) + np.testing.assert_almost_equal(E_asys, E_expl) + + # Calling dlqe() with a continuous time system should raise an error + with pytest.raises(ControlArgument, match="called with a continuous"): + K, S, E = ct.dlqe(csys, Q, R) + +def test_estimator_iosys(): + sys = ct.drss(4, 2, 2, strictly_proper=True) + + Q, R = np.eye(sys.nstates), np.eye(sys.ninputs) + K, _, _ = ct.dlqr(sys, Q, R) + + P0 = np.eye(sys.nstates) + QN = np.eye(sys.ninputs) + RN = np.eye(sys.noutputs) + estim = ct.create_estimator_iosystem(sys, QN, RN, P0) + + ctrl, clsys = ct.create_statefbk_iosystem(sys, K, estimator=estim) + + # Extract the elements of the estimator + est = estim.linearize(0, 0) + Be1 = est.B[:sys.nstates, :sys.noutputs] + Be2 = est.B[:sys.nstates, sys.noutputs:] + A_clchk = np.block([ + [sys.A, -sys.B @ K], + [Be1 @ sys.C, est.A[:sys.nstates, :sys.nstates] - Be2 @ K] + ]) + B_clchk = np.block([ + [sys.B @ K, sys.B], + [Be2 @ K, Be2] + ]) + C_clchk = np.block([ + [sys.C, np.zeros((sys.noutputs, sys.nstates))], + [np.zeros_like(K), -K] + ]) + D_clchk = np.block([ + [np.zeros((sys.noutputs, sys.nstates + sys.ninputs))], + [K, np.eye(sys.ninputs)] + ]) + + # Check to make sure everything matches + cls = clsys.linearize(0, 0) + nstates = sys.nstates + np.testing.assert_almost_equal(cls.A[:2*nstates, :2*nstates], A_clchk) + np.testing.assert_almost_equal(cls.B[:2*nstates, :], B_clchk) + np.testing.assert_almost_equal(cls.C[:, :2*nstates], C_clchk) + np.testing.assert_almost_equal(cls.D, D_clchk) + + +def test_estimator_errors(): + sys = ct.drss(4, 2, 2, strictly_proper=True) + P0 = np.eye(sys.nstates) + QN = np.eye(sys.ninputs) + RN = np.eye(sys.noutputs) + + with pytest.raises(ct.ControlArgument, match="Input system must be I/O"): + sys_tf = ct.tf([1], [1, 1], dt=True) + estim = ct.create_estimator_iosystem(sys_tf, QN, RN) + + with pytest.raises(NotImplementedError, match="continuous time not"): + sys_ct = ct.rss(4, 2, 2, strictly_proper=True) + estim = ct.create_estimator_iosystem(sys_ct, QN, RN) + + with pytest.raises(ValueError, match="output must be full state"): + C = np.eye(2, 4) + estim = ct.create_estimator_iosystem(sys, QN, RN, C=C) + + with pytest.raises(ValueError, match="output is the wrong size"): + sys_fs = ct.drss(4, 4, 2, strictly_proper=True) + sys_fs.C = np.eye(4) + C = np.eye(1, 4) + estim = ct.create_estimator_iosystem(sys_fs, QN, RN, C=C) + + +def test_white_noise(): + # Scalar white noise signal + T = np.linspace(0, 1000, 1000) + R = 0.5 + V = ct.white_noise(T, R) + assert abs(np.mean(V)) < 0.1 # can occassionally fail + assert abs(np.cov(V) - 0.5) < 0.1 # can occassionally fail + + # Vector white noise signal + R = [[0.5, 0], [0, 0.1]] + V = ct.white_noise(T, R) + assert abs(np.mean(V)) < 0.1 # can occassionally fail + assert np.all(abs(np.cov(V) - R) < 0.1) # can occassionally fail + + # Make sure time scaling works properly + T = T / 10 + V = ct.white_noise(T, R) + assert abs(np.mean(V)) < np.sqrt(10) # can occassionally fail + assert np.all(abs(np.cov(V) - R) < 10) # can occassionally fail + + # Make sure discrete time works properly + V = ct.white_noise(T, R, dt=T[1] - T[0]) + assert abs(np.mean(V)) < 0.1 # can occassionally fail + assert np.all(abs(np.cov(V) - R) < 0.1) # can occassionally fail + + # Test error conditions + with pytest.raises(ValueError, match="T must be 1D"): + V = ct.white_noise(R, R) + + with pytest.raises(ValueError, match="Q must be square"): + R = np.outer(np.eye(2, 3), np.ones_like(T)) + V = ct.white_noise(T, R) + + with pytest.raises(ValueError, match="Time values must be equally"): + T = np.logspace(0, 2, 100) + R = [[0.5, 0], [0, 0.1]] + V = ct.white_noise(T, R) + + +def test_correlation(): + # Create an uncorrelated random sigmal + T = np.linspace(0, 1000, 1000) + R = 0.5 + V = ct.white_noise(T, R) + + # Compute the correlation + tau, Rtau = ct.correlation(T, V) + + # Make sure the correlation makes sense + zero_index = np.where(tau == 0) + np.testing.assert_almost_equal(Rtau[zero_index], np.cov(V), decimal=2) + for i, t in enumerate(tau): + if i == zero_index: + continue + assert abs(Rtau[i]) < 0.01 + + # Try passing a second argument + tau, Rneg = ct.correlation(T, V, -V) + np.testing.assert_equal(Rtau, -Rneg) + + # Test error conditions + with pytest.raises(ValueError, match="Time vector T must be 1D"): + tau, Rtau = ct.correlation(V, V) + + with pytest.raises(ValueError, match="X and Y must be 2D"): + tau, Rtau = ct.correlation(T, np.zeros((3, T.size, 2))) + + with pytest.raises(ValueError, match="X and Y must have same length as T"): + tau, Rtau = ct.correlation(T, V[:, 0:-1]) + + with pytest.raises(ValueError, match="Time values must be equally"): + T = np.logspace(0, 2, T.size) + tau, Rtau = ct.correlation(T, V) diff --git a/doc/control.rst b/doc/control.rst index 8bd6f7a32..20f363a1e 100644 --- a/doc/control.rst +++ b/doc/control.rst @@ -108,10 +108,11 @@ Control system synthesis :toctree: generated/ acker + create_statefbk_iosystem + dlqr h2syn hinfsyn lqr - lqe mixsyn place rootlocus_pid_designer @@ -143,6 +144,17 @@ Nonlinear system support tf2io flatsys.point_to_point +Stochastic system support +========================= +.. autosummary:: + :toctree: generated/ + + correlation + create_estimator_iosystem + dlqe + lqe + white_noise + .. _utility-and-conversions: Utility functions and conversions diff --git a/doc/examples.rst b/doc/examples.rst index 89a2b16a1..0f23576bd 100644 --- a/doc/examples.rst +++ b/doc/examples.rst @@ -44,6 +44,9 @@ using running examples in FBS2e. cruise describing_functions + kincar-fusion mpc_aircraft steering pvtol-lqr-nested + pvtol-outputfbk + stochresp diff --git a/doc/kincar-fusion.ipynb b/doc/kincar-fusion.ipynb new file mode 120000 index 000000000..def600898 --- /dev/null +++ b/doc/kincar-fusion.ipynb @@ -0,0 +1 @@ +../examples/kincar-fusion.ipynb \ No newline at end of file diff --git a/doc/pvtol-outputfbk.ipynb b/doc/pvtol-outputfbk.ipynb new file mode 120000 index 000000000..ffcfd5401 --- /dev/null +++ b/doc/pvtol-outputfbk.ipynb @@ -0,0 +1 @@ +../examples/pvtol-outputfbk.ipynb \ No newline at end of file diff --git a/doc/stochresp.ipynb b/doc/stochresp.ipynb new file mode 120000 index 000000000..36190a54c --- /dev/null +++ b/doc/stochresp.ipynb @@ -0,0 +1 @@ +../examples/stochresp.ipynb \ No newline at end of file diff --git a/examples/kincar-fusion.ipynb b/examples/kincar-fusion.ipynb new file mode 100644 index 000000000..d8e680b81 --- /dev/null +++ b/examples/kincar-fusion.ipynb @@ -0,0 +1,581 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "eec23018", + "metadata": {}, + "source": [ + "# Discrete Time Sensor Fusion\n", + "RMM, 24 Feb 2022\n", + "\n", + "In this example we work through estimation of the state of a car changing lanes with two different sensors available: one with good longitudinal accuracy and the other with good lateral accuracy.\n", + "\n", + "All calculations are done in discrete time, using both a Kalman filter formulation and predictor-corrector form." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "107a6613", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import matplotlib.pyplot as plt\n", + "import control as ct\n", + "import control.optimal as opt\n", + "import control.flatsys as fs\n", + "from IPython.display import Image\n", + "\n", + "# Define line styles\n", + "ebarstyle = {'elinewidth': 0.5, 'capsize': 2}\n", + "xdstyle = {'color': 'k', 'linestyle': '--', 'linewidth': 0.5, \n", + " 'marker': '+', 'markersize': 4}" + ] + }, + { + "cell_type": "markdown", + "id": "ea8807a4", + "metadata": {}, + "source": [ + "## System definition\n", + "\n", + "We consider a bicycle model for an automobile:\n", + "\n", + "\n", + "\n", + "### Continuous time model\n", + "The dynamics are given by\n", + "\n", + "$$\n", + " \\begin{aligned}\n", + " \\dot x &= \\cos\\theta \\, v, \\qquad\n", + " \\dot y &= \\sin\\theta \\, v, \\qquad\n", + " \\dot \\theta &= \\frac{v}{l} \\tan\\phi,\n", + " \\end{aligned}\n", + "$$\n", + "\n", + "where $(x, y, \\theta)$ are the position and orientation of the vehicle, $v$ is the forward velocity, $\\phi$ is the steering wheel angle, and $l$ is the wheelbase.\n", + "\n", + "These dynamics are included in the file `vehicle.py`:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "a04106f8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: vehicle\n", + "Inputs (2): v, delta, \n", + "Outputs (3): x, y, theta, \n", + "States (3): x, y, theta, \n" + ] + } + ], + "source": [ + "# Vehicle steering dynamics\n", + "#\n", + "# System state: x, y, theta\n", + "# System input: v, phi\n", + "# System output: x, y\n", + "# System parameters: wheelbase, maxsteer\n", + "#\n", + "from vehicle import vehicle, plot_lanechange\n", + "print(vehicle)" + ] + }, + { + "cell_type": "markdown", + "id": "e8ae0344", + "metadata": {}, + "source": [ + "This system is differentially flat and so we can define a trajectory for the system using the `flatsys` module. We generate a motion that corresponds to changing lanes on a road:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "69c048ed", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Generate a trajectory for the vehicle\n", + "# Define the endpoints of the trajectory\n", + "x0 = [0., -2., 0.]; u0 = [10., 0.]\n", + "xf = [40., 2., 0.]; uf = [10., 0.]\n", + "Tf = 4\n", + "\n", + "# Find a trajectory between the initial condition and the final condition\n", + "traj = fs.point_to_point(vehicle, Tf, x0, u0, xf, uf, basis=fs.PolyFamily(6))\n", + "\n", + "# Create the desired trajectory between the initial and final condition\n", + "Ts = 0.1\n", + "# Ts = 0.5\n", + "T = np.arange(0, Tf + Ts, Ts)\n", + "xd, ud = traj.eval(T)\n", + "\n", + "plot_lanechange(T, xd, ud)" + ] + }, + { + "cell_type": "markdown", + "id": "aeeaa39e", + "metadata": {}, + "source": [ + "### Discrete time system model\n", + "\n", + "For the model that we use for the Kalman filter, we take a simple discretization using the approximation that $\\dot x = (x[k+1] - x[k])/T_s$ where $T_s$ is the sampling time." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "2469c60e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: sys[6]\n", + "Inputs (2): u[0], u[1], \n", + "Outputs (3): y[0], y[1], y[2], \n", + "States (3): x[0], x[1], x[2], \n", + "\n", + "A = [[ 1.0000000e+00 0.0000000e+00 -5.0004445e-07]\n", + " [ 0.0000000e+00 1.0000000e+00 1.0000000e+00]\n", + " [ 0.0000000e+00 0.0000000e+00 1.0000000e+00]]\n", + "\n", + "B = [[0.1 0. ]\n", + " [0. 0. ]\n", + " [0. 0.33333333]]\n", + "\n", + "C = [[1. 0. 0.]\n", + " [0. 1. 0.]\n", + " [0. 0. 1.]]\n", + "\n", + "D = [[0. 0.]\n", + " [0. 0.]\n", + " [0. 0.]]\n", + "\n", + "dt = 0.1\n", + "\n" + ] + } + ], + "source": [ + "#\n", + "# Create a discrete time, linear model\n", + "#\n", + "\n", + "# Linearize about the starting point\n", + "linsys = ct.linearize(vehicle, x0, u0)\n", + "\n", + "# Create a discrete time model by hand\n", + "Ad = np.eye(linsys.nstates) + linsys.A * Ts\n", + "Bd = linsys.B * Ts\n", + "discsys = ct.LinearIOSystem(ct.ss(Ad, Bd, np.eye(linsys.nstates), 0, dt=Ts))\n", + "print(discsys)" + ] + }, + { + "cell_type": "markdown", + "id": "084c5ae8", + "metadata": {}, + "source": [ + "### Sensor model\n", + "\n", + "We assume that we have two sensors: one with good longitudinal accuracy and the other with good lateral accuracy. For each sensor we define the map from the state space to the sensor outputs, the covariance matrix for the measurements, and a white noise signal (now in discrete time)." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "0a19d109", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Sensor #1: longitudinal\n", + "C_lon = np.eye(2, discsys.nstates)\n", + "Rw_lon = np.diag([0.1 ** 2, 1 ** 2])\n", + "W_lon = ct.white_noise(T, Rw_lon, dt=Ts)\n", + "\n", + "# Sensor #2: lateral\n", + "C_lat = np.eye(2, discsys.nstates)\n", + "Rw_lat = np.diag([1 ** 2, 0.1 ** 2])\n", + "W_lat = ct.white_noise(T, Rw_lat, dt=Ts)\n", + "\n", + "# Plot the noisy signals\n", + "plt.subplot(2, 1, 1)\n", + "Y = xd[0:2] + W_lon\n", + "plt.plot(Y[0], Y[1])\n", + "plt.plot(xd[0], xd[1], **xdstyle)\n", + "plt.xlabel(\"$x$ position [m]\")\n", + "plt.ylabel(\"$y$ position [m]\")\n", + "plt.title(\"Sensor #1\")\n", + " \n", + "plt.subplot(2, 1, 2)\n", + "Y = xd[0:2] + W_lat\n", + "plt.plot(Y[0], Y[1])\n", + "plt.plot(xd[0], xd[1], **xdstyle)\n", + "plt.xlabel(\"$x$ position [m]\")\n", + "plt.ylabel(\"$y$ position [m]\")\n", + "plt.title(\"Sensor #2\")\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "id": "c3fa1a3d", + "metadata": {}, + "source": [ + "## Linear Quadratic Estimator\n", + "\n", + "To estimate the position of the vehicle, we construct an optimal estimator (Kalman filter)." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "993601a2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: sys[7]\n", + "Inputs (6): y[0], y[1], y[2], y[3], u[0], u[1], \n", + "Outputs (3): xhat[0], xhat[1], xhat[2], \n", + "States (12): xhat[0], xhat[1], xhat[2], P[0,0], P[0,1], P[0,2], P[1,0], P[1,1], P[1,2], P[2,0], P[2,1], P[2,2], \n" + ] + } + ], + "source": [ + "#\n", + "# Create an estimator for the system\n", + "#\n", + "\n", + "# Disturbance and initial condition model\n", + "Rv = np.diag([0.1, 0.01]) * Ts\n", + "# Rv = np.diag([10, 0.1]) * Ts # No input data\n", + "P0 = np.diag([1, 1, 0.1])\n", + "\n", + "# Combine the sensors\n", + "C = np.vstack([C_lon, C_lat])\n", + "Rw = sp.linalg.block_diag(Rw_lon, Rw_lat)\n", + "\n", + "estim = ct.create_estimator_iosystem(discsys, Rv, Rw, C=C, P0=P0)\n", + "print(estim)" + ] + }, + { + "cell_type": "markdown", + "id": "d9e2e618", + "metadata": {}, + "source": [ + "Finally, we estimate the position of the vehicle based on sensor measurements. We assume that the input to the vehicle (velocity and steering angle) is available, though we can also explore what happens if that information is not available (see commented out code).\n", + "\n", + "We also carry out a prediction of the position of the vehicle by turning off the correction term in the Kalman filter." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "3d02ec33", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEKCAYAAAAFJbKyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAA0jklEQVR4nO3deXxU9bn48c9DEiAssggCsisKoghCZBHc96UuP22rvfVeba9oXarVXmu1Knax2uu1Fqm2qKCtiCiCouwqO7IkbAn7vi9hDyEkJHl+f3zPOJMQIEPm5Mwkz/v1Oq/MWeacJ5Dkme8uqooxxhhTXjWCDsAYY0xiscRhjDEmKpY4jDHGRMUShzHGmKhY4jDGGBMVSxzGGGOikhx0AJWhSZMm2q5du6DDMMaYhJGRkbFbVZuWda5aJI527dqRnp4edBjGGJMwRGTj8c5ZVZUxxpioVIsShzHGVBsFBTBrFowdCzt2wIcfxvwRljiMMSbRbd8O48e7ZDF5MuTkhM8NGwaXXw5Tp8bscZY4jDEm0RQVQXq6SxRjx8KCBSXPn38+zJkD9er58vi4TRwi0hEYEXHoLOAFoCHwAJDtHX9WVcdVbnTGGFPJ9u2DSZNcohg/HnbvLnm+Rw+YPx9EfA8lbhOHqq4EugGISBKwFRgN3A/8VVVfCy46Y4zxmSpkZsK4cS5ZzJxZ8vx558GMGXD66ZUeWtwmjlKuBtaq6kaphGxqjDGByM2Fb75xyeL99yE/P3yuTRv4+GPo2ROSkgILERIncdwNDI/Yf1RE/hNIB55S1X3BhGWMMRW0dq0rUYwb5xqw8/Nd28RNN8HNN8ONN8KZZwYdZQkS7ws5iUhNYBtwvqruFJFmwG5AgT8ALVT1Z2W8rz/QH6BNmzY9Nm487lgWY4ypPAUFroop1LC9apU7npoKeXnh62LcEypaIpKhqmllnUuEEseNwAJV3QkQ+gogIu8AX5X1JlUdDAwGSEtLi+/saIyp2rZtcyWKceNcd9lDh1wjduQH9549A00U0UiExHEPEdVUItJCVbd7u3cAWYFEZYwxx1NUBHPnhhu2Fy1yx2vVCrdbqAZeqjhVcZ04RKQOcC3wYMThv4hIN1xV1YZS54wxJhh798KECS5ZTJgAe/Yce02vXjBtWuXHFmNxnThU9TBweqlj9wYUjjHGhKnCkiXhhu3vvoPi4pLXXHKJm/6jionrxGGMMXHl0CHXXTaULLZuLXn+oovcILyAu8v6LeaJQ0Qal+OyYlXdH+tnG2NMzK1eHW6r+Prrkg3aHTvClCnQokVw8QXAjxLHNm870Ui9JKCND882xpiKyc937RChXlCrV5c8f+GFbp6olJRg4osDfiSO5ap60YkuEJGFPjzXGGNOzZYt4VLFV1+VbKvo0MHNEdW+fXDxxRk/EkefGF1jjDH+KCx03WVDg/CWLHHH27SBBx90I7avvBLq1Ak2zjgV88ShqkcARCQNeA5o6z1H3Gm9MHSNMcZUmt27YeJElygmTHCzzSYllZx6fNMmWLYM3noruDgTgJ+9qoYB/wNkAsUnudYYY2JL1Q28C/WAmjvXVUGlpMDRo+6aoiLo1i0hB+EFyc/Eka2qY3y8vzHGlJST46b0CDVsb99+7DV9+lSJQXhB8jNxvCgi7wLfAN/PDayqo3x8pjGmOlF1kwSG2ipmzAiXJkL69IHZs4OJr4ryM3HcD3QCUghXVSlgicMYc+qOHHElhlCyWLfu2GsuvRSmT6/82KoJPxNHV1Xt4uP9jTHVxaZNbrnUsWPdyO3Dh0ue79XLrbFtKoWfiWOOiHRW1WU+PsMYUxUVFrrqpVBbRWZmyfMXXADz5rk1LEyl8zNx9AP+S0TW49o4vu+O6+MzjTGJKjvblSrGjYPPPnPJI+Sss9zAvE6d3DoWJlB+Jo4bfLy3MSbRFRfDwoWu+um111yPqJDmzWHQILjmGmjQILgYTZl8Sxyqamu1GmNKOnjQdZcdO9aVLnbscCWInj3dGts33QTdu0ONGkFHak7Aj9lxF6hq94peY4ypAlRhxYrwPFAzZrgqqIYNw5MEqrrBebVrwwsvBBquKR8/ShzniciSE5wXwMqexlRVeXluJHZoxPb69e543brhdov9+xN22VTjT+LoVI5rinx4rjEmKBs3hhPFt9+65FGjRslZZtPSLFFUEX5McmhtG8ZUdUePuu6yoUF4y8rodd+3rw3Cq6LieulYEdkA5OBKKIWqmuatMDgCaAdsAH6kqvuCitGYamPnTjer7Nixbn2KAwdKnr/4YtdWYd1lq7y4ThyeK1V1d8T+M8A3qvqKiDzj7f8mmNCMqcKKiyEjI9ywPX/+sdf07QszZ1Z+bCZQiZA4SrsNuMJ7/QEwFUscxsTG/v0lu8vu2lXyfPfubtlUK1VUa74lDhGpBdyJq1L6/jmq+vsobqPAJBFR4J+qOhhopqrbvXttF5EzjvP8/kB/gDZtbHlzY8qk6tonQg3bpacb79TJdaFt0iSY+Exc8rPE8QVwAMggYlr1KPVV1W1ecpgsIivK+0YvyQwGSEtL01N8vjFVz+HDMGWKSxZDhkB+xK9n69YwfLibNDA5ESskTGXw8yejlapWaNoRVd3mfd0lIqOBnsBOEWnhlTZaALtOeBNjDGzYEO4BNWWKm5q8Th24/nq3vvZNN0GrVkFHaRKEn4ljtoh0UdXMk196LBGpC9RQ1Rzv9XXA74ExwH8Br3hfv4hVwMZUGQUFMGtWuApq+XJ3PDXVJQ1wJY8DB6B//+DiNAnJ79lx76vA7LjNgNHiGuGSgY9UdYKIzAc+EZGfA5uAH8Y+dGMS0I4d4WnIJ01ykwbWrOlGbIfk5dmIbVNhfiaOGyvyZlVdB3Qt4/ge4OqK3NuYKqG42HWRDZUqMjLc8Zo1XYkD3Nc+fSxRmJjydXZcEekKXOodmqGqi/16njHVwr59rjQxdqwbjJedfew1vXsf2zvKmBjyszvu48ADhNcY/1BEBqvqm34905gqRxWyssKD8GbPhqJSU71dcolrzzCmkvhZVfVzoJeq5gKIyKvAd4AlDmNOJDfXTRQYaq/YtKnk+W7d3CC8pKRAwjPGz8QhlJwFt8g7Zowpbe3acFvF1Kklx1aAq3767rtAQjOmND8Tx1Bgrjf+AuB24D0fn2dMwsjPh6w3p3D6d1/Sbuk4WLmy5AUXXgjz5kGtWsEEaMwJ+Nk4/rqITAP64koa96vqQr+eZ0y8y8o6yMCBa5g4Ucje1JGveY4WZAAFbKndgVaZ46FDh6DDNOakfJ1TQFUzcFOOGFPtFBbCl1/uYeDAtUyf3pTi4vZAd2AjTZrkkvfHf1F4RwtqnVEXG7NtEokfa47PVNV+IpKDm6Tw+1O4AYCnxfqZxsSL9evzGDhwFUuXtmXevIYcOHA6cBr16i2gZ89l3HdfM+6+uxspKclA06DDNeaU+LECYD/va/1Y39uYeFNUBGPGbOedd7Ywe3ZDDhw4B+hKjRr7vVVTi4Gd9OjRi2++CTZWY2LFz3Ecr6rqb052zJhEs3PnUT76aDcLFrRgwgRl9+4WwBmILAS+AhpTXNzdm9mjBlhFlKli/GzjuJZjF1i6sYxjxsQ1VZgyZQ9vvbWBqVPrsmfPOUALkpOVwkIBMoFULrsszWb2MNWCH20cvwAeBs4WkSWEx27UB2x4q0kIBw4U8+23wvjxwogRBzl48HTgdGAJMA6oT58+lzJ9ehLQJdBYjalsfpQ4hgHjgZdx64ELrpE8R1X3+fA8YypMFebPP8igQev4+usUtm8/B6jpnS0AvqRLl3YsXtwFkfJO8GxM1eRH4hjn9aq6Fbgl4riIiPWqMnHj8GE3SHvEiIN88kkOR460BLoBK4BJnHvueWRlnU1KShPgB0GGakxc8bNXVb1Y39uYisrKyuPNN9cyYQJs396Jo0eTcbWoi4F0OnduxZIl3UhK6hRwpMbEL1tU2FRp+fkwYwb85S9ZzJ7dkNzcVsAFwCpgDl269GPePKF27UtPcidjTEgNv24sIj8Ukfre6+dFZJSIdPfrecaEbNhQwFNPraBLl9XUqQPXXguTJ59Lbu46GjQYxdChMzlypC2q/ViyBGrXDjpiYxKLnyWO51X1UxHph1sv/DXgbaCXj8801VBxMUyatJe33trI9OkNOHDgLKATsJn778/njjtq0bt3IU2bXhZ0qMZUCX4mjtCU6jcDb6vqFyIywMfnmWpkz54i/vGPdSxZ0popU2qTnd0YaIBIOrAIaAj0ZN26WvzgBwB1ggvWmCrGz8SxVUT+CVwDvCoitYiiakxEWgP/Aprj5m0YrKp/85LPA0BozcxnVXVcTCM3cUcVZs8+wN//vp5vv63Fzp0dgHOoUeOIN7XHIWADl17ak2nTbNkXY/zkZ+L4EXAD8Jqq7heRFsD/RPH+QuApVV3gtZVkiMhk79xfVfW1GMdr4kxOjvLll4eZNq0uY8cWsXVrA1x32UzcUKFUiot7cPnltZk6tR6u0dsY4zc/1+M4LCJrgetF5HpghqpOiuL924Ht3uscEVkOtPQnWhMPVGHRosMMGrSOiROT2Lr1LKAuSUlQVJQEfAM05LLLujFtmo3WNiYofvaqehw3ivwMb/tQRB47xXu1Ay4C5nqHHhWRJSIyREQaHec9/UUkXUTSs7Ozy7rExIEjR2DiRPjlL6FRo910716HIUMuYOtWgAnAZC65xCUV1atR7cG0abbWtjFBElU9+VWncmM3T1UfVc319usC36lqVPM1iEg9YBrwJ1UdJSLNgN24aUz+ALRQ1Z+d6B5paWmanp5+Kt+G8cH69QW8+eYaxowpYv36sykuDjVcbwTm06lTCxYvvpiaNWue6DbGGB+JSIaqppV1zs82DiHcswrvdVStliKSAnwGDFPVUQCqujPi/Du4eaxNHCsqcstnv/feDkaOPOx1l+0MbAK+oWPHnixc2IzU1LZA22CDNcaclJ+JYygwV0RG4xLGbcB75X2ziIh3/XJVfT3ieAuv/QPgDiArdiGbWNm7t4i3317DiBGHWbbsfIqKagLNgHnUr7+Il19uzH33XUy9ejYHlDGJxs/G8ddFZCrQzzt0v6oujOIWfYF7gUwRWeQdexa4R0S64aqqNgAPxiJeUzGqsGxZIX/+8xK+/roWO3eeC3QE9gBrOO+8zsyYAY0b98R9JjDGJCo/VwCsDVwBXIobh5EkIstV9Uh53q+qMym7asvGbMSJ/Hzl/ffXMX58DZYubc+aNclAd5KSlnL++RO4665UHn20B02adPbeYQnDmKrAz6qqfwE5wEBv/x7g38APfXym8dnq1bn87W+r+OorZdOmc1E9GzhCo0aKSwybKSrqRJMm5zNgQLCxGmP84Wfi6KiqXSP2p4jIYh+fZ3xQVAQjR25myZJWjB8vLFxYF9czegswG9ejuwsXXtjMWza1dXDBGmMqhZ+JY6GI9FbVOQAi0gtbOjYhbNuWz8CBqxg9uoA1a86iuLg1rkkJYAewiX79ujFjRqsAozTGBMXPxNEL+E8R2eTttwGWi0gmoNGO5zD+UYWsrGLGjq3Bxx/nsHhxHdw62ruADKCQiy9OY968Jripw5oHGa4xJmB+Jo4bfLy3qaBDhwp5552VfPTRAZYsaUNBQaj0UBc3Yvs0+vbtzsyZ1wQYpTEmHvnZHXejX/c2p2brVhg7Fv70p0Vs2nQOcD6Qh5uGfCu9e/fiu+9qADcFGaYxJs7Z0rFVWGGh8uGHqxg6NJvMzDbs29fGO9MKmEPr1jWZM6cLZ57ZJ8gwjTEJxhJHFXPgAAwatJL339/DmjUdcYPwzgaW0K5dC776KoXOnZsgcnXAkRpjEpWfAwDfAH6lfs2iaAAoLla++moDgwdvYfr0nuTk1MIli33UqpXF/fcX88QT59Gxoy33boyJDT9LHIeAMSJyt6rmish1wIuq2tfHZ1YL+/cXMHBgFp9+epgVK86isLA90J62bffx6KO1uOqqfPr2rUdq6qVBh2qMqYL8bBz/nYj8BJgqIvlALvCMX8+r6qZN28aECTVYuLA5U6emkJ/fHcghJSUTWAmcw8aNrZg9G15+uVbA0RpjqjI/q6quxq0Nngu0AH6uqiv9el5Vc+hQIf/853KGDz9IZmYrCgrcdOOpqZCfL7jlUztwySWXeCO2jTGmcvhZVfUc8LyqzhSRLsAIEXlSVb/18ZkJLTPzEDNm1GP8eBg37ijFxV2Aw8BiYDXQnp49z/YShS2daowJhp9VVVdFvM4UkRtxizJd4tczE01eXjFDh67hww/3snBhc44caRdxdjuwjd69u/Ddd9Zd1hgTPyqtO66qbhfrA8rmzTB+PAwZsp15805D9VzgCG4Q3kq6d+9DevppiJwFnBVorMYYU5ZKHcehqnmV+bx4UFCgjBixkaFDdzJvXhNyc8/2zpwOTAWS6dmzC3Pn9g4uSGOMiYINAPTBrl0walQ+r722lHXrOqDaDmiJK1XkkZZ2AfPm1cT1UDbGmMRiiSMGVOHrr7fx5pubyMxsx4YNzYFauGQxhxYtYNKk87jggosDjtQYYyouIROHiNwA/A1IAt5V1VcqO4aiIhgyZCnvvJNNenp7VNsCZwLLadu2OaNHw4UXNiUpyUoVxpiqJeESh4gkAX8HrsUtQzdfRMao6jK/n52Zmc2gQas5cKAPkycLe/eeDxTQuPFirrpqNY891o5LL+2EfL+0dg2/QzLGmEqXcIkD6AmsUdV1ACLyMXAbEPPEUVhYzL//vZz3388mPf0MDh/uDDQlOfkohYUpwH4giS5dLubTT2P9dGOMiU+JmDhaApsj9rfgVhuMqeeeg5dfLsCtWVGEyFJgCtCCwsKOXH45TJ3aMNaPNcaYuJeIiUPKOHbMDLwi0h/oD9CmTZtj3nAyf/oTFBUl8c03Mxk27DzOPddWujXGGEjMSvgtQOuI/VbAttIXqepgVU1T1bSmTZtG/ZABA+DVV1NIT+9Hx46nM2DAqYZrjDFViyTachkikgysAq4GtgLzgZ+o6tLjvSctLU3T09MrKUJjjEl8IpKhqmllnUu4qipVLRSRR4GJuO64Q06UNIwxxsRWwiUOAFUdB4wLOg5jjKmOEq6q6lSISDaw8RTf3gTYHcNwYsXiio7FFR2LKzpVMa62qlpmA3G1SBwVISLpx6vnC5LFFR2LKzoWV3SqW1yJ2KvKGGNMgCxxGGOMiYoljpMbHHQAx2FxRcfiio7FFZ1qFZe1cRhjjImKlTiMMcZExRKHMcaYqFjiOA4RuUFEVorIGhF5Juh4QkRkiIjsEpGsoGMJEZHWIjJFRJaLyFIReTzomABEpLaIzBORxV5cLwUdUyQRSRKRhSLyVdCxRBKRDSKSKSKLRCRu5uoRkYYiMlJEVng/a33iIKaO3r9TaDsoIk8EHReAiPzK+7nPEpHhIlI7Zve2No5jeYtFrSJisSjgnspYLOpkROQy4BDwL1W9IOh4AESkBdBCVReISH0gA7g96H8vERGgrqoeEpEUYCbwuKrOCTKuEBF5EkgDTlPVW4KOJ0RENgBpqhpXA9pE5ANghqq+KyI1gTqquj/gsL7n/d3YCvRS1VMdcByrWFrift47q2qeiHwCjFPV92NxfytxlO37xaJUtQAILRYVOFWdDuwNOo5IqrpdVRd4r3OA5bh1UwKlziFvN8Xb4uKTkoi0Am4G3g06lkQgIqcBlwHvAahqQTwlDc/VwNqgk0aEZCDVmxi2DmXMIn6qLHGUrazFogL/Q5gIRKQdcBEwN+BQgO+rgxYBu4DJqhoXcQFvAE8DxQHHURYFJolIhreuTTw4C8gGhnrVe++KSN2ggyrlbmB40EEAqOpW4DVgE7AdOKCqk2J1f0scZSvXYlGmJBGpB3wGPKGqB4OOB0BVi1S1G27dlp4iEnj1nojcAuxS1YygYzmOvqraHbgReMSrHg1aMtAdeFtVLwJygXhqe6wJ3ArExSLSItIIV0vSHjgTqCsiP43V/S1xlK1ci0WZMK8N4TNgmKqOCjqe0rxqjanADcFGAkBf4FavLeFj4CoR+TDYkMJUdZv3dRcwGld1G7QtwJaIEuNIXCKJFzcCC1R1Z9CBeK4B1qtqtqoeBUYBl8Tq5pY4yjYfOEdE2nufJO4GxgQcU9zyGqHfA5ar6utBxxMiIk1FpKH3OhX3y7Qi0KAAVf2tqrZS1Xa4n61vVTVmnwYrQkTqeh0c8KqCrgMC78GnqjuAzSLS0Tt0NRB4Z5UI9xAn1VSeTUBvEanj/X5ejWt7jImEXI/Db/G8WJSIDAeuAJqIyBbgRVV9L9io6AvcC2R67QkAz3rrpgSpBfCB19ulBvCJqsZV19c41AwY7f7WkAx8pKoTgg3pe48Bw7wPc+uA+wOOBwARqYPrgflg0LGEqOpcERkJLAAKgYXEcPoR645rjDEmKlZVZYwxJiqWOIwxxkTFEocxxpioxFXjuNc9MQcoAgpLL3no9Q74G3ATcBi4LzRi+USaNGmi7dq1i3m8xhhTVWVkZOw+3prjcZU4PFeeYI6cG4FzvK0X8Lb39YTatWtHenrczNVmjDFxT0SOO3VKolVV3Yab3E+9ieoaehPsGWOMqSTxljhONkdOueeQEpH+IpIuIunZ2dk+hGqMMdVTvCWOk82RU+45pFR1sKqmqWpa06ZlVtMZY4w5BXGVOMoxR47NIWWMMSczYACIhLcBA2J6+7hJHOWcI2cM8J/i9MZNFby9kkM1xpj4NmAAqMKLL7qvVTVx4ObImSkii4F5wFhVnSAiD4nIQ94143Bz1KwB3gEeDiZUY4yJIz6XMEqLm+64qroO6FrG8X9EvFbgkcqMyxhj4t6AASU3n8VTicMYY0x5VXIpI5IlDmOMSUQ+t2OciCUOY4xJBAGWMEqzxGGMMYkgwBJGaZY4jDEmHsVRCaM0SxzGGBOP4qiEUZolDmOMiQdxXMIozRKHMcbEgzguYZR20sQhIo3LsTWshFiNMabqSKASRmnlGTm+zdvKmpk2JAloE5OIjDGmOqjk0d6xVJ6qquWqepaqtj/eBuzxO1BjjEl4CVzKiFSexNEnRtcYY0z1lkDtGCdy0sShqkcARCRNREaLyAIRWSIimSKyJPIaY4wxEapICaO0aHpVDQOGAncCPwBu8b4aY4yBYxMFVIkSRmnRJI5sVR2jqutVdWNo8y0yY4xJNFWkKupkokkcL4rIuyJyj4j8v9DmW2TGGBPvqmhV1MlEkzjuB7oBN+CqqELVVcYYUz1Uk6qok4lmBcCuqtrFt0iMMSYeDRgAL70U3n/xxfDxaiqaEsccEensWyTGGBMPrFRxUtEkjn7AIhFZWbo7biyISGsRmSIiy0VkqYg8XsY1V4jIARFZ5G0vxOr5xhgDVJsG7oqIpqrqBt+icAqBp1R1gYjUBzJEZLKqLit13QxVtbYVY0xslFUVZcnihMpd4ojsgutHd1xV3a6qC7zXOcByoGWs7m+MMYBVRcVAeWbHXRCLa6IhIu2Ai4C5ZZzuIyKLRWS8iJwfy+caY6ogSxQxV54Sx3lem8bxtkygSawCEpF6wGfAE6p6sNTpBUBbVe0KvAl8foL79BeRdBFJz87OjlV4xph4VDo5WKLwVXkSRyfC4zbK2m4BLolFMCKSgksaw1R1VOnzqnpQVQ95r8cBKSJSZtJS1cGqmqaqaU2bNo1FeMaYeHGyUoQlCl+VZ5LDMts2Sm1bKhqIiAjwHm4a99ePc01z7zpEpKcXv03pbkxVUzoxXHGFlSLiSDwtHdsXuBe4KqK77U0i8pCIPORdcxeQJSKLgYHA3aqqQQVsjKmAaKqXpk61RBFHoumO6ytVncmJVxlEVQcBgyonImPKLz8/n927k1m5Mom1aw+ydu0+9u5V9u4V9u5NYe/emhQUNKZGjRp07HiAM85Yz4Vtt/DAQ1eQXD8VkpKC/hZir3Q318svh2nTwvuRSSCUCBJwNbzqKG4ShzHxqKCggPXr17NhwwZq1+7NF180ICNjJ6tWLSU//yBHjhzkyJGWqF4ANPPedZq3AeQCO4D1uKne6rJ0aQrQjVk8TPJvvZUJUlKgdm1ITS17O965yOPluSZyK0+yOtkf/0jlSQyhe1pySGjlThwiUgu3Fke7yPep6u9jH5Yxla+4uJgaNWqQlZXFgAEDWLZsGatW5VBUdCdwH9DAu7IucA6QCtQEDgDbadAglQMHTgO2ACv4yU+Ehx6qSVJSEklJyXTrlkytWrB9+0E+7XAPuw4LmVxAF7IoKKxBzZwcyMlxj0hJgaNHyw40KQmKimLzTZe+V716cOhQeP+88+CnP4Vly6BfP5dwrrwSZsyAW291++PHw09+4l6/8AIMGwaPPeb2N26E3Fz3fdWu7b4vk/CiKXF8gfsNyQDy/QnHmMpRXFxMZmYmU6ZMYfr06cybN4+XXvo9P/zhz8jKqs2UKZdx+PCfKSo6x3tHDtddl8fw4ak0blwPqBdxt9OA1hH7rbytbC1aNOeXuV+UOFYzmuBLlwL69YOZM8P7PXpARkZ4//zzYenS8P6117qk1KcP5OW5bc4c6NgxvL9yJTRt6l7PnAm7d8PatXDkCOR7v/7ffBO+5+jRJWMcMqTk/muvua9JSW57661wSejAAZg40b3evBkyM8OloiVLXAyha+fMgcGDw+dXrXJxhEpW2dmwYYPbz89336clq5iLJnG0UlW/px0xxjeFhYUkJyezZk0O3bv/nJycdkBXatb8A0lJZ/LQQw347/8G6IDIL2nZErZ831+wPn36QOPGQUUfoSJVPZFJZ+rUktVLixeX3N+8OTz9RuQzi4vh+efhySfdH/VXX4X+/cNJ55134K67wvsjR8JVV7mkk5cH334L3bqFzy9eDPXru9e5ubBiRfjaffvc+fyIz6oTJ5b8noYPL7n/1lvh16+84hJV7dqu2mzIkHDS2b3bfa+h/dWr3X94aH/uXPe+UNJavBg+/dS9XrcOZs0KX7tvH+zYEd6v4n12okkcs0Wki6pm+haNMTG2cuVK3ntvLCNH7kP1MmrWvJZVq+oDnwBQs2YhBQXH/hqowtlnu7+dVUq0SSfU8wlcwolMLC+/7BLL6adDl4gVF6ZMgdtvD+9v2gS//vXxYzhR43hov7jYJY8BA+CXvwwnnYED4d57w/v//jfcfLNLPJ9/Dpdd5o4fOQLTp8MFF4Svzclx1XTZ2W5/2zaXTEJJK/SeSJ9/Hn7973+XPDdwYPi1CPzf/4WTzuHDrlQWSixbtrjSVGqqqwbcvTt8btYseOON8HuXLoUvvwyf37bNvSe0HyoF1oyq3Foh0SSOfsB9IrIeV1UlgKrqhb5EZkwFDBr0L/7ylzVs3nwp8DiQBOSTmlryuj59kpk6tfLjSxgnSjSRpZfSSeWll2I7WWCNGuE/lC0jprBr2dIlh5BFi+BnP3Ovd+2C3/2uZLwnaqQvvf/ii/DMM+FE8sor4ZLVW2/BPfeEk9Dw4XD99eH9SZPg4ovD750/H9q3D58/fNiVcPLyXJwbN4aTFbhSWaSRI0vuv/NOyf1XX3XJKjkZBg0K/1sVFPjSESGaxHFjzJ9uTIzk5uby6aef07Dhj/j44xQ+++weCgtTSE3dT15eLq4dohZPP20demLmZKWX0qWVRJt1ViT8B7hRI1dPecEF7lzbtnDddeFrV6yAhx8O7xcWlj9JRb5Wdcnu178OJ5n/+z+XDEP7Q4bAHXeE9z//3CXtvDzX3nPRRSXbqnxQ7sShqhtFpCtwqXdohqou9iUqY8ppyZIl/OEPX/DFF404evSHQKgh1P1oX3xxw+P2HjU+K+uP5fGqvUKJpboTcY35jRq5DeCMMyAtLXzN7Nnw4x+H93fuhGefda+Tko79N/dBuUeOewsrDQPO8LYPReQxX6Iy5iRWrcrm7LNfp2vXo4wc+TxHjz4IJNG5s5KfD6qC6vGHHJgAhBZICm2h0eChEeEvveQ2kcQqmVRD0Uw58nOgl6q+oKovAL2BB/wJy5hj7d+/nw8+SOe//xsuvLAJ69Y9ScuWrXjllVx2705BtQlLl0plthGaWCmdVMAlEEskcSmaxCFA5KijIk4yRYgxsbB58xbuvPMfNGkyn/vuS2PoUCU/3/3obd3ajPHj63L66QEHaWLLEklciyZxDAXmisgAERkAzMHNZmuML9av38Q11/yTNm2yGTXqIYqKLga28dRTckyNh6niLJHElWiWjn0d+BmwF9gH3K+qb/gUl6mmVGH5cmXgQLjiiqZ8882D1Kp1JrAbaAicSZ06wcZo4oAlkkBFNcmhqmbgphwxJqYmTYK//z2HyZMLycvzepOQCuTQq1cza+Q2J1a6e2vk+JJE6wacAMqz5vhM72uOiByM2HJEpPTSrsZEZdUqaNQoj+uvhzFjDpOXN4lGjT5j9WqluBhU61vSMNGx0ojvyrMCYD/va31VPS1iq6+qp53s/caUZc8eN8apc+di9u8vICnpNzz88Cts23YZe/feSYcO8n2Xf2MqxBJJzEUzrfqrqvqbkx0z5kSysuDee4+yaFEyrlNeLuefP4CxY5+gbdu2QYdnqgNbD6TCoulVdW0Zx2waEnNCxcVuUtG//Q2uuqqYLl1g0aJCYLx3RX3uuuuvljRMcEIj2q0EUm7laeP4hYhkAp1EZImIZHrbBsBmyjVlWrEC7r4bmjRxM2g/8QRMmbIZeIZ69e5k1qyG39cc2O+pCZRVZUWtPCWOYcAPgM+BW7ztZuAiVf0P/0IziejAAXjqKejcGUaMcMsUwBSgNeeeex2jR/fm4MGxXHLJJQFHasxxWCI5qfIkjnGqugG4FcjClTKygE2x7lUlIjeIyEoRWSMiz5RxXkRkoHd+iYh0j+XzzakrLHQzPZ9zDvz1r3D33YeYNGkxqnDwYBr/+MfvyMrK4vbbb0es1dskktKJxBJHVL2q6vnZq0pEkoC/49pNOgP3iEjnUpfdiFvs+RygP/B2rJ5vTo0qjBkDDRq4pQqys4tQfYsRI5ry9NP3oarUr1+fBx98kBRbwtMkOmsPAaJrHPdbT2CNqq5T1QLgY+C2UtfcBvxLnTlAQxFpUdmBGmfhQjcz9m23QatWyi9+8TXNmrUCHuHHP76D0aNHW+nCVC1W+gCim1b9hyJS33v9vIiMinFVUUsgcqHOLd6xaK8JxdtfRNJFJD07OzuGYRpVVyXVvTvMmOGO1ajxKW+/fS1nndWe7777jo8++oh27doFGqcxvqumJZBoShzPq2qOiPQDrgM+ILZVRWV9NC294nt5rnEHVQerapqqpjVt2rTCwRnn4EG3hsyaNXD55TkMGzYRVcjKupMvv/ySWbNm0bt376DDNKZyVNOG9GgSR2hK9ZuBt1X1CyCWKx9sAVpH7LcCtp3CNcYnU6dCjx4wapTSu/doZsxozPPPP0xRURFJSUnccsstVjVlqrdqUpUVTeLYKiL/BH4EjBORWlG+/2TmA+eISHsRqQncDYwpdc0Y4D+93lW9gQOquj2GMZgyTJsGDRvClVfCmjUHKSq6nrlzf8TDDz/EnDlzSEpKCjpEY+JTFa3KiuYP/4+AicANqrofaAz8T6wCUdVC4FHvGcuBT1R1qYg8JCIPeZeNA9YBa4B3gIfLvJmJiQULXLK44gpITYVHHlkNNOO22+qwfHkWb775JlYNaMwJVNESSLnnqlLVwyKyFrheRK4HZqjqpFgGo6rjcMkh8tg/Il4r8Egsn2mOtX8/nH8+bNumQAHwHR06XMGgQefwwANz6Nq1a8ARGpOgypryPQFF06vqcdwo8jO87UMRecyvwEwwPvoIOnWCHTuUFi1GAc3o3PkRvv32KIAlDWMqooqUQKKpqvo50EtVX1DVF4DewAP+hGUqmyq0bg3/8R+wc+dKiovT2LPnUf7+95dZtGiRDd4zJtYSuP0jmsQhhHtW4b22LjRVwNGjcN99xWzZAnffvZ/TT7+MP//5h+zdu4aHH37YkoYxfkjg0kc0S8cOBeaKyGhcwrgNeM+XqEylWbRoFTfffIht27ozYAC88EJD8vM3Urt27aBDM6Z6SaAlb8td4lDV14H7gb3AHuB+VX3Dp7iMzxYvXsxVV73IRRcdYtu2blx//Wief74YESxpGBOEBCqBRNM4Xhu4ArgSuBy4wjtmEswrr3xBt27rmTLlJeBsIIeJE+/gqqviaeoyY6q5OG4DieYvxb+A84GBwCDgPODffgQVD0L/Z6Etjv7PolZUVMTIkSMZP34ajz8Ozz13K7Vq3cjzz+eRm9sA1QaoupHhxpg4EcclkGjaODqqamRfzCkisjjWAcWL0LLEibw88b59+xg6dCiDBg1i/fpGJCWNoagIQMjPr8X06fD73wcdpTEm0URT4ljoTfMBgIj0AmbFPiQTC3/4wx9o2bIlTz31NEVFz5CUNJ/mzc9k8uTwBxgrYRiTQOKo6iqaxNELmC0iG7z1xr8DLvfWH1/iS3Sm3Hbv3s3AgQM5ePAgqlBY2IUOHcbQpEkemzb15667arBkiXDNNUFHaow5JXFUdRVNVdUNvkVhTklubi5jx47l448/5quvvuLo0TosWnQZ8+d3IyvrdkTCMz2PGAE7dlgpw5gqI8DpS6KZq2qjn4GY8lFVRISdO3fSvn0H8vLq0KhRGp06TWPp0l4MHRouRPbpA7OsMtGYqqmsBthKKoVEU+IwAVBVVqxYwYQJExg1ajpHjtxG7dr3sXJlM44cOQgI+/bBvn3u+gcegMGDAw3ZGFPFWcf9OFNcXPz969/97nc0b96Kzp2f5cknz2bmzE9IT7+PmTMhOxtUhcaNS77/zDMrOWBjTPAqueG83CUOEfkaeEpVq2wX3GgUF8PGjdC+/anfIzc3l8zMpcyZs54FCzayYsUc1q6dy/bt69m7tyZz517H7t1P4pY+KQSS6dED0tNj9E0YY6qGSh43EE1V1dPAX0VkI/BsdV5571e/gjfeKLn/+uvHXpeTk8Pq1avZuXMnK1YcICOjkFWranDuubexZUtdMjOPsndvN6Bnifc1bqzk50Nh4WVcdx08/DDccksyttCeMaZcfJ73SjTU7aa8bxC5E3gBGAX8RVXzYhaNT9LS0jT9FD6m33ZbDrNnj6NLlwU0arQO1WI2buxLVtYvKShIBrKB0xAppHnzt0lNfYeDB/cybNgIevS4ijfemMYf/zgP1yGty/f3FSlENRk4COwAGgBNgCQaNnQLKYVcfrn1hDLGVD4RyVDVtDLPRZM4RERw0470A/4IHAF+q6pxPfXIqSSOvDzo3fswS5bUBmogsgfXsaw7sI/HHmvE/fcv5Be/+F/WrXuC7OyepKTkoppMYWGtiDsVUa9eDocOFQH1gZrxPOmlMcYAMUocIjITOAtYCswB5gIrgMeBWqraPzbhxt6pljgAnn4aunaFsWNh/nxo0wYmTaJEtdHll8P06eH9Bg3gwIHwviUKY0yiOVHiiKaN4yFgqR6baR4TkeWnHB0gIv8L/AC3wPVa3JTt+8u4bgOQg1tEqvB431Qs1anjVsVbvRqGD4c1ayA5uWQymDbN7yiMMSZ+RLMeR1YZSSPk5grGMRm4QFUvBFYBvz3BtVeqarfKSBqR4mi0vzHGBCom4zhUdV0F3z9JVQu93TlAq4pHZYwxxg/xOADwZ8D445xTYJKIZIhI3LapGGNMVVZpU454Awibl3HqOVX9wrvmOdxIt2HHuU1fVd0mImcAk0VkhapOL+tCL7H0B2jTpk2F4zfGGONUWuJQ1RNO6C0i/wXcAlx9vLYUVd3mfd0lIqNxI+fKTByqOhgYDK5XVQVCN8YYEyEuqqpE5AbgN8Ctqnr4ONfUFZH6odfAdUBW5UVpjDEG4iRx4NYwr4+rflokIv8AEJEzRWScd00zYKa3XO08YKyqTggmXGOMqb7iYlp1Ve1wnOPbgJu81+uArmVdZ4wxpvLES4kj7sTR8r7GGBNXop7kMBFVZMoRY4ypjk405YiVOIwxxkTFEocxxpioWOIwxhgTlWrRxiEi2cDGU3x7E2B3DMOJFYsrOhZXdCyu6FTFuNqqatOyTlSLxFERIpJe2TPxlofFFR2LKzoWV3SqW1xWVWWMMSYqljiMMcZExRLHyQ0OOoDjsLiiY3FFx+KKTrWKy9o4jDHGRMVKHMYYY6JiicMYY0xULHEch4jcICIrRWSNiDwTdDwhIjJERHaJSNysRSIirUVkiogsF5GlIvJ40DEBiEhtEZknIou9uF4KOqZIIpIkIgtF5KugY4kkIhtEJNNb4iBuJnkTkYYiMlJEVng/a33iIKaO3r9TaDsoIk8EHReAiPzK+7nPEpHhIlI7Zve2No5jiUgSsAq4FtgCzAfuUdVlgQYGiMhlwCHgX6p6QdDxAIhIC6CFqi7wFtvKAG4P+t9LRASoq6qHRCQFmAk8rqpzgowrRESeBNKA01T1lqDjCRGRDUCaqsbVgDYR+QCYoarvikhNoI6q7g84rO95fze2Ar1U9VQHHMcqlpa4n/fOqponIp8A41T1/Vjc30ocZesJrFHVdapaAHwM3BZwTAB4a6zvDTqOSKq6XVUXeK9zgOVAy2CjAnUOebsp3hYXn5REpBVwM/Bu0LEkAhE5DbgMeA9AVQviKWl4rgbWBp00IiQDqSKSDNQBtsXqxpY4ytYS2Byxv4U4+EOYCESkHXARMDfgUIDvq4MWAbuAyaoaF3EBbwBPA8UBx1EWBSaJSIaI9A86GM9ZQDYw1Kvee9dbQjqe3A0MDzoIAFXdCrwGbAK2AwdUdVKs7m+Jo2xSxrG4+KQaz0SkHvAZ8ISqHgw6HgBVLVLVbkAroKeIBF69JyK3ALtUNSPoWI6jr6p2B24EHvGqR4OWDHQH3lbVi4BcIJ7aHmsCtwKfBh0LgIg0wtWStAfOBOqKyE9jdX9LHGXbArSO2G9FDIt5VZHXhvAZMExVRwUdT2letcZU4IZgIwGgL3Cr15bwMXCViHwYbEhh3pLNqOouYDSu6jZoW4AtESXGkbhEEi9uBBao6s6gA/FcA6xX1WxVPQqMAi6J1c0tcZRtPnCOiLT3PkncDYwJOKa45TVCvwcsV9XXg44nRESaikhD73Uq7pdpRaBBAar6W1VtpartcD9b36pqzD4NVoSI1PU6OOBVBV0HBN6DT1V3AJtFpKN36Gog8M4qEe4hTqqpPJuA3iJSx/v9vBrX9hgTybG6UVWiqoUi8igwEUgChqjq0oDDAkBEhgNXAE1EZAvwoqq+F2xU9AXuBTK99gSAZ1V1XHAhAdAC+MDr7VID+ERV46rraxxqBox2f2tIBj5S1QnBhvS9x4Bh3oe5dcD9AccDgIjUwfXAfDDoWEJUda6IjAQWAIXAQmI4/Yh1xzXGGBMVq6oyxhgTFUscxhhjomKJwxhjTFQscRhjjImKJQ5jjDFRscRhjDEmKpY4jDkOETk9YrrsHSKyNWK/pojM9um5rUTkx2UcbycieRFjZcp6b6oXX4GINPEjPmNsAKAxx6Gqe4BuACIyADikqq9FXBKzKRxKuRroDIwo49xab+6tMqlqHtDNm87EGF9YicOYUyQih7xSwApvttYsERkmIteIyCwRWS0iPSOu/6m3sNQiEfmnN6K99D37Aa8Dd3nXtT/B8+uKyFhvoaqsskopxvjBEocxFdcB+BtwIdAJ+AnQD/g18CyAiJwH/Bg382w3oAj4j9I3UtWZuLnSblPVbqq6/gTPvQHYpqpdvUW94mVqEFPFWVWVMRW3XlUzAURkKfCNqqqIZALtvGuuBnoA8715oFJxa4SUpSOwshzPzQReE5FXga9UdcapfwvGlJ8lDmMqLj/idXHEfjHh3zEBPlDV357oRiJyOm7RnaMne6iqrhKRHsBNwJ9FZJKq/j7q6I2JklVVGVM5vsG1W5wBICKNRaRtGde1p5xrv4jImcBhVf0Qt9pbPK1PYaowK3EYUwlUdZmI/A63JGsN4CjwCFB6feoVuCnzs4D+qnqiLr9dgP8VkWLvfr/wIXRjjmHTqhuTILz13L/yGsJPdu0GIE1Vd/sdl6l+rKrKmMRRBDQozwBAIAXXxmJMzFmJwxhjTFSsxGGMMSYqljiMMcZExRKHMcaYqFjiMMYYExVLHMYYY6JiicMYY0xULHEYY4yJiiUOY4wxUfn/lND+tgaDBWwAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Compute the inputs to the estimator\n", + "Y = np.vstack([xd[0:2] + W_lon, xd[0:2] + W_lat])\n", + "U = np.vstack([Y, ud]) # add input to the Kalman filter\n", + "# U = np.vstack([Y, ud * 0]) # with no input information\n", + "X0 = np.hstack([xd[:, 0], P0.reshape(-1)])\n", + "\n", + "# Run the estimator on the trajectory\n", + "estim_resp = ct.input_output_response(estim, T, U, X0)\n", + "\n", + "# Run a prediction to see what happens next\n", + "T_predict = np.arange(T[-1], T[-1] + 4 + Ts, Ts)\n", + "U_predict = np.outer(U[:, -1], np.ones_like(T_predict))\n", + "predict_resp = ct.input_output_response(\n", + " estim, T_predict, U_predict, estim_resp.states[:, -1],\n", + " params={'correct': False})\n", + "\n", + "# Plot the estimated trajectory versus the actual trajectory\n", + "plt.subplot(2, 1, 1)\n", + "plt.errorbar(\n", + " estim_resp.time, estim_resp.outputs[0], \n", + " estim_resp.states[estim.find_state('P[0,0]')], fmt='b-', **ebarstyle)\n", + "plt.errorbar(\n", + " predict_resp.time, predict_resp.outputs[0], \n", + " predict_resp.states[estim.find_state('P[0,0]')], fmt='r-', **ebarstyle)\n", + "plt.plot(T, xd[0], 'k--')\n", + "plt.ylabel(\"$x$ position [m]\")\n", + "\n", + "plt.subplot(2, 1, 2)\n", + "plt.errorbar(\n", + " estim_resp.time, estim_resp.outputs[1], \n", + " estim_resp.states[estim.find_state('P[1,1]')], fmt='b-', **ebarstyle)\n", + "plt.errorbar(\n", + " predict_resp.time, predict_resp.outputs[1], \n", + " predict_resp.states[estim.find_state('P[1,1]')], fmt='r-', **ebarstyle)\n", + "# lims = plt.axis(); plt.axis([lims[0], lims[1], -5, 5])\n", + "plt.plot(T, xd[1], 'k--');\n", + "plt.ylabel(\"$y$ position [m]\")\n", + "plt.xlabel(\"Time $t$ [s]\");" + ] + }, + { + "cell_type": "markdown", + "id": "9f9e3d59", + "metadata": {}, + "source": [ + "More insight can be obtained by focusing on the errors in prediction:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "44f69f79", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the estimated errors\n", + "plt.subplot(2, 1, 1)\n", + "plt.errorbar(\n", + " estim_resp.time, estim_resp.outputs[0] - xd[0], \n", + " estim_resp.states[estim.find_state('P[0,0]')], fmt='b-', **ebarstyle)\n", + "plt.errorbar(\n", + " predict_resp.time, predict_resp.outputs[0] - (xd[0] + xd[0, -1]), \n", + " predict_resp.states[estim.find_state('P[0,0]')], fmt='r-', **ebarstyle)\n", + "lims = plt.axis(); plt.axis([lims[0], lims[1], -0.2, 0.2])\n", + "# lims = plt.axis(); plt.axis([lims[0], lims[1], -2, 0.2])\n", + "\n", + "plt.subplot(2, 1, 2)\n", + "plt.errorbar(\n", + " estim_resp.time, estim_resp.outputs[1] - xd[1], \n", + " estim_resp.states[estim.find_state('P[1,1]')], fmt='b-', **ebarstyle)\n", + "plt.errorbar(\n", + " predict_resp.time, predict_resp.outputs[1] - xd[1, -1], \n", + " predict_resp.states[estim.find_state('P[1,1]')], fmt='r-', **ebarstyle)\n", + "lims = plt.axis(); plt.axis([lims[0], lims[1], -0.2, 0.2]);" + ] + }, + { + "cell_type": "markdown", + "id": "6f6c1b6f", + "metadata": {}, + "source": [ + "### Things to try\n", + "\n", + "To gain a bit more insight into sensor fusion, you can try the following:\n", + "* Remove the input (and update P0)\n", + "* Change the sampling rate" + ] + }, + { + "cell_type": "markdown", + "id": "8f680b92", + "metadata": {}, + "source": [ + "### Predictor-corrector form\n", + "\n", + "Instead of using `create_estimator_iosystem`, we can also compute out the estimate in a more manual fashion, done here using the predictor-corrector form:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "fa488d51", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# System matrices\n", + "A, B, F = discsys.A, discsys.B, discsys.B\n", + "\n", + "# Create an array to store the results\n", + "xhat = np.zeros((discsys.nstates, T.size))\n", + "P = np.zeros((discsys.nstates, discsys.nstates, T.size))\n", + "\n", + "# Update the estimates at each time\n", + "for i, t in enumerate(T):\n", + " # Prediction step\n", + " if i == 0:\n", + " # Use the initial condition\n", + " xkkm1 = xd[:, 0]\n", + " Pkkm1 = P0\n", + " else:\n", + " xkkm1 = A @ xkk + B @ ud[:, i-1]\n", + " Pkkm1 = A @ Pkk @ A.T + F @ Rv @ F.T\n", + " \n", + " # Correction step\n", + " L = Pkkm1 @ C.T @ np.linalg.inv(Rw + C @ Pkkm1 @ C.T)\n", + " xkk = xkkm1 - L @ (C @ xkkm1 - Y[:, i])\n", + " Pkk = Pkkm1 - L @ C @ Pkkm1\n", + "\n", + " # Save the state estimate and covariance for later plotting\n", + " xhat[:, i], P[:, :, i] = xkk, Pkk\n", + " # xhat[:, i], P[:, :, i] = xkkm1, Pkkm1 # For comparison to Kalman form\n", + " \n", + "plt.subplot(2, 1, 1)\n", + "plt.errorbar(T, xhat[0], P[0, 0], fmt='b-', **ebarstyle)\n", + "plt.plot(T, xd[0], 'k--')\n", + "plt.ylabel(\"$x$ position [m]\")\n", + "\n", + "plt.subplot(2, 1, 2)\n", + "plt.errorbar(T, xhat[1], P[1, 1], fmt='b-', **ebarstyle)\n", + "plt.plot(T, xd[1], 'k--')\n", + "plt.ylabel(\"$x$ position [m]\");" + ] + }, + { + "cell_type": "markdown", + "id": "a9d5cb32", + "metadata": {}, + "source": [ + "We can compare the results of the predictor-corrector form to the Kalman filter form used at the top of the notebook:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "4eda4729", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the estimated errors (and compare to Kalman form)\n", + "plt.subplot(2, 1, 1)\n", + "plt.errorbar(T, xhat[0] - xd[0], P[0, 0], fmt='b-', **ebarstyle)\n", + "plt.plot(estim_resp.time, estim_resp.outputs[0] - xd[0], 'r--')\n", + "lims = plt.axis(); plt.axis([lims[0], lims[1], -0.2, 0.2])\n", + "\n", + "plt.subplot(2, 1, 2)\n", + "plt.errorbar(T, xhat[1] - xd[1], P[1, 1], fmt='b-', **ebarstyle)\n", + "plt.plot(estim_resp.time, estim_resp.outputs[1] - xd[1], 'r--')\n", + "lims = plt.axis(); plt.axis([lims[0], lims[1], -0.2, 0.2]);" + ] + }, + { + "cell_type": "markdown", + "id": "3f7e3e4d", + "metadata": {}, + "source": [ + "Note that the estimates are not the same! It turns out that to get the correspondence of the two formulations, we need to define $\\hat{x}_\\text{KF}(k) = \\hat{x}_\\text{PC}(k|k-1)$ (see commented out code above)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0796fc56", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/pvtol-lqr-nested.ipynb b/examples/pvtol-lqr-nested.ipynb index 59e97472a..63fde31f3 100644 --- a/examples/pvtol-lqr-nested.ipynb +++ b/examples/pvtol-lqr-nested.ipynb @@ -532,7 +532,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, diff --git a/examples/pvtol-outputfbk.ipynb b/examples/pvtol-outputfbk.ipynb new file mode 100644 index 000000000..8656ed241 --- /dev/null +++ b/examples/pvtol-outputfbk.ipynb @@ -0,0 +1,511 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c017196f", + "metadata": {}, + "source": [ + "# Output feedback control using LQR and extended Kalman filtering\n", + "RMM, 14 Feb 2022\n", + "\n", + "This notebook illustrates the implementation of an extended Kalman filter and the use of the estimated state for LQR feedback of a vectored thrust aircraft model." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "544525ab", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.patches as patches\n", + "import control as ct" + ] + }, + { + "cell_type": "markdown", + "id": "859834cf", + "metadata": {}, + "source": [ + "## System definition\n", + "We consider a (planar) vertical takeoff and landing aircraf model:\n", + "\n", + "![PVTOL diagram](https://murray.cds.caltech.edu/images/murray.cds/7/7d/Pvtol-diagram.png)\n", + "\n", + "The dynamics of the system with disturbances on the $x$ and $y$ variables are given by\n", + "\n", + "$$\n", + " \\begin{aligned}\n", + " m \\ddot x &= F_1 \\cos\\theta - F_2 \\sin\\theta - c \\dot x + d_x, \\\\\n", + " m \\ddot y &= F_1 \\sin\\theta + F_2 \\cos\\theta - c \\dot y - m g + d_y, \\\\\n", + " J \\ddot \\theta &= r F_1.\n", + " \\end{aligned}\n", + "$$\n", + "\n", + "The measured values of the system are the position and orientation,\n", + "with added noise $n_x$, $n_y$, and $n_\\theta$:\n", + "\n", + "$$\n", + " \\vec y = \\begin{bmatrix} x \\\\ y \\\\ \\theta \\end{bmatrix} + \n", + " \\begin{bmatrix} n_x \\\\ n_y \\\\ n_z \\end{bmatrix}.\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "198a068d", + "metadata": {}, + "source": [ + "The dynamics are defined in the `pvtol` module:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ffafed74", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: pvtol\n", + "Inputs (2): F1, F2, \n", + "Outputs (6): x0, x1, x2, x3, x4, x5, \n", + "States (6): x0, x1, x2, x3, x4, x5, \n", + "\n", + "Object: noisy_pvtol\n", + "Inputs (7): F1, F2, Dx, Dy, Nx, Ny, Nth, \n", + "Outputs (6): x0, x1, x2, x3, x4, x5, \n", + "States (6): x0, x1, x2, x3, x4, x5, \n" + ] + } + ], + "source": [ + "# pvtol = nominal system (no disturbances or noise)\n", + "# noisy_pvtol = pvtol w/ process disturbances and sensor noise\n", + "from pvtol import pvtol, noisy_pvtol, plot_results\n", + "\n", + "# Find the equiblirum point corresponding to the origin\n", + "xe, ue = ct.find_eqpt(\n", + " pvtol, np.zeros(pvtol.nstates),\n", + " np.zeros(pvtol.ninputs), [0, 0, 0, 0, 0, 0],\n", + " iu=range(2, pvtol.ninputs), iy=[0, 1])\n", + "\n", + "x0, u0 = ct.find_eqpt(\n", + " pvtol, np.zeros(pvtol.nstates),\n", + " np.zeros(pvtol.ninputs), np.array([2, 1, 0, 0, 0, 0]),\n", + " iu=range(2, pvtol.ninputs), iy=[0, 1])\n", + "\n", + "# Extract the linearization for use in LQR design\n", + "pvtol_lin = pvtol.linearize(xe, ue)\n", + "A, B = pvtol_lin.A, pvtol_lin.B\n", + "\n", + "print(pvtol, \"\\n\")\n", + "print(noisy_pvtol)" + ] + }, + { + "cell_type": "markdown", + "id": "be6ec05c", + "metadata": {}, + "source": [ + "We also define the properties of the disturbances, noise, and initial conditions:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1e1ee7c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Disturbance and noise intensities\n", + "Qv = np.diag([1e-2, 1e-2])\n", + "Qw = np.array([[2e-4, 0, 1e-5], [0, 2e-4, 1e-5], [1e-5, 1e-5, 1e-4]])\n", + "Qwinv = np.linalg.inv(Qw)\n", + "\n", + "# Initial state covariance\n", + "P0 = np.eye(pvtol.nstates)" + ] + }, + { + "cell_type": "markdown", + "id": "e4c52c73", + "metadata": {}, + "source": [ + "## Control system design\n", + "\n", + "We start be defining an extended Kalman filter to estimate the state of the system from the measured outputs." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "3647bf15", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: sys[3]\n", + "Inputs (5): x0, x1, x2, F1, F2, \n", + "Outputs (6): xh0, xh1, xh2, xh3, xh4, xh5, \n", + "States (42): x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26], x[27], x[28], x[29], x[30], x[31], x[32], x[33], x[34], x[35], x[36], x[37], x[38], x[39], x[40], x[41], \n" + ] + } + ], + "source": [ + "# Define the disturbance input and measured output matrices\n", + "F = np.array([[0, 0], [0, 0], [0, 0], [1, 0], [0, 1], [0, 0]])\n", + "C = np.eye(3, 6)\n", + "\n", + "# Estimator update law\n", + "def estimator_update(t, x, u, params):\n", + " # Extract the states of the estimator\n", + " xhat = x[0:pvtol.nstates]\n", + " P = x[pvtol.nstates:].reshape(pvtol.nstates, pvtol.nstates)\n", + "\n", + " # Extract the inputs to the estimator\n", + " y = u[0:3] # just grab the first three outputs\n", + " u = u[3:5] # get the inputs that were applied as well\n", + "\n", + " # Compute the linearization at the current state\n", + " A = pvtol.A(xhat, u) # A matrix depends on current state\n", + " # A = pvtol.A(xe, ue) # Fixed A matrix (for testing/comparison)\n", + " \n", + " # Compute the optimal again\n", + " L = P @ C.T @ Qwinv\n", + "\n", + " # Update the state estimate\n", + " xhatdot = pvtol.updfcn(t, xhat, u, params) - L @ (C @ xhat - y)\n", + "\n", + " # Update the covariance\n", + " Pdot = A @ P + P @ A.T - P @ C.T @ Qwinv @ C @ P + F @ Qv @ F.T\n", + "\n", + " # Return the derivative\n", + " return np.hstack([xhatdot, Pdot.reshape(-1)])\n", + "\n", + "estimator = ct.NonlinearIOSystem(\n", + " estimator_update, lambda t, x, u, params: x[0:pvtol.nstates],\n", + " states=pvtol.nstates + pvtol.nstates**2,\n", + " inputs= noisy_pvtol.state_labels[0:3] \\\n", + " + noisy_pvtol.input_labels[0:pvtol.ninputs],\n", + " outputs=[f'xh{i}' for i in range(pvtol.nstates)],\n", + ")\n", + "print(estimator)" + ] + }, + { + "cell_type": "markdown", + "id": "8c97626d", + "metadata": {}, + "source": [ + "We now define an LQR controller, using a physically motivated weighting:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9787db61", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Object: control\n", + "Inputs (14): xd[0], xd[1], xd[2], xd[3], xd[4], xd[5], ud[0], ud[1], xh0, xh1, xh2, xh3, xh4, xh5, \n", + "Outputs (2): F1, F2, \n", + "States (0): \n", + "\n", + "A = []\n", + "\n", + "B = []\n", + "\n", + "C = []\n", + "\n", + "D = [[-3.16227766e+00 -1.31948924e-07 8.67680175e+00 -2.35855555e+00\n", + " -6.98881806e-08 1.91220852e+00 1.00000000e+00 0.00000000e+00\n", + " 3.16227766e+00 1.31948924e-07 -8.67680175e+00 2.35855555e+00\n", + " 6.98881806e-08 -1.91220852e+00]\n", + " [-1.31948923e-06 3.16227766e+00 -2.32324805e-07 -2.36396241e-06\n", + " 4.97998224e+00 7.90913288e-08 0.00000000e+00 1.00000000e+00\n", + " 1.31948923e-06 -3.16227766e+00 2.32324805e-07 2.36396241e-06\n", + " -4.97998224e+00 -7.90913288e-08]]\n", + " \n", + "\n", + "Object: xh5\n", + "Inputs (13): xd[0], xd[1], xd[2], xd[3], xd[4], xd[5], ud[0], ud[1], Dx, Dy, Nx, Ny, Nth, \n", + "Outputs (14): x0, x1, x2, x3, x4, x5, F1, F2, xh0, xh1, xh2, xh3, xh4, xh5, \n", + "States (48): noisy_pvtol_x0, noisy_pvtol_x1, noisy_pvtol_x2, noisy_pvtol_x3, noisy_pvtol_x4, noisy_pvtol_x5, sys[3]_x[0], sys[3]_x[1], sys[3]_x[2], sys[3]_x[3], sys[3]_x[4], sys[3]_x[5], sys[3]_x[6], sys[3]_x[7], sys[3]_x[8], sys[3]_x[9], sys[3]_x[10], sys[3]_x[11], sys[3]_x[12], sys[3]_x[13], sys[3]_x[14], sys[3]_x[15], sys[3]_x[16], sys[3]_x[17], sys[3]_x[18], sys[3]_x[19], sys[3]_x[20], sys[3]_x[21], sys[3]_x[22], sys[3]_x[23], sys[3]_x[24], sys[3]_x[25], sys[3]_x[26], sys[3]_x[27], sys[3]_x[28], sys[3]_x[29], sys[3]_x[30], sys[3]_x[31], sys[3]_x[32], sys[3]_x[33], sys[3]_x[34], sys[3]_x[35], sys[3]_x[36], sys[3]_x[37], sys[3]_x[38], sys[3]_x[39], sys[3]_x[40], sys[3]_x[41], \n" + ] + } + ], + "source": [ + "# Shoot for 1 cm error in x, 10 cm error in y. Try to keep the angle\n", + "# less than 5 degrees in making the adjustments. Penalize side forces\n", + "# due to loss in efficiency.\n", + "#\n", + "\n", + "Qx = np.diag([100, 10, (180/np.pi) / 5, 0, 0, 0])\n", + "Qu = np.diag([10, 1])\n", + "K, _, _ = ct.lqr(A, B, Qx, Qu)\n", + "\n", + "#\n", + "# Control system construction: combine LQR w/ EKF\n", + "#\n", + "# Use the linearization around the origin to design the optimal gains\n", + "# to see how they compare to the final value of P for the EKF\n", + "#\n", + "\n", + "# Construct the state feedback controller with estimated state as input\n", + "statefbk, _ = ct.create_statefbk_iosystem(pvtol, K, estimator=estimator)\n", + "print(statefbk, \"\\n\")\n", + "\n", + "# Reconstruct the control system with the noisy version of the process\n", + "# Create a closed loop system around the controller\n", + "clsys = ct.interconnect(\n", + " [noisy_pvtol, statefbk, estimator],\n", + " inplist = statefbk.input_labels[0:pvtol.ninputs + pvtol.nstates] + \\\n", + " noisy_pvtol.input_labels[pvtol.ninputs:],\n", + " inputs = statefbk.input_labels[0:pvtol.ninputs + pvtol.nstates] + \\\n", + " noisy_pvtol.input_labels[pvtol.ninputs:],\n", + " outlist = pvtol.output_labels + statefbk.output_labels + estimator.output_labels,\n", + " outputs = pvtol.output_labels + statefbk.output_labels + estimator.output_labels\n", + ")\n", + "print(clsys)" + ] + }, + { + "cell_type": "markdown", + "id": "7bf558a0", + "metadata": {}, + "source": [ + "## Simulations\n", + "\n", + "We now simulate the response of the system, starting with an instantiation of the noise:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c2583a0e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Create the time vector for the simulation\n", + "Tf = 10\n", + "T = np.linspace(0, Tf, 1000)\n", + "\n", + "# Create representative process disturbance and sensor noise vectors\n", + "np.random.seed(117) # avoid figures changing from run to run\n", + "V = ct.white_noise(T, Qv) # smaller disturbances and noise then design\n", + "W = ct.white_noise(T, Qw)\n", + "plt.plot(T, V[0], label=\"V[0]\")\n", + "plt.plot(T, W[0], label=\"W[0]\")\n", + "plt.legend();" + ] + }, + { + "cell_type": "markdown", + "id": "4d944709", + "metadata": {}, + "source": [ + "### LQR with EKF" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "ad7a9750", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Put together the input for the system\n", + "U = np.vstack([\n", + " np.outer(xe, np.ones_like(T)), # xd\n", + " np.outer(ue, np.ones_like(T)), # ud\n", + " V, W # disturbances and noise\n", + "])\n", + "X0 = np.hstack([x0, np.zeros(pvtol.nstates), P0.reshape(-1)])\n", + "\n", + "# Initial condition response\n", + "resp = ct.input_output_response(clsys, T, U, X0)\n", + "\n", + "# Plot the response\n", + "plot_results(T, resp.states, resp.outputs[pvtol.nstates:])" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c5f24119", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Response of the first two states, including internal estimates\n", + "plt.figure()\n", + "h1, = plt.plot(resp.time, resp.outputs[0], 'b-', linewidth=0.75)\n", + "h2, = plt.plot(resp.time, resp.outputs[1], 'r-', linewidth=0.75)\n", + "\n", + "# Add on the internal estimator states\n", + "xh0 = clsys.find_output('xh0')\n", + "xh1 = clsys.find_output('xh1')\n", + "h3, = plt.plot(resp.time, resp.outputs[xh0], 'k--')\n", + "h4, = plt.plot(resp.time, resp.outputs[xh1], 'k--')\n", + "\n", + "plt.plot([0, 10], [0, 0], 'k--', linewidth=0.5)\n", + "plt.ylabel(\"Position $x$, $y$ [m]\")\n", + "plt.xlabel(\"Time $t$ [s]\")\n", + "plt.legend(\n", + " [h1, h2, h3, h4], ['$x$', '$y$', '$\\hat{x}$', '$\\hat{y}$'], \n", + " loc='upper right', frameon=False, ncol=2)" + ] + }, + { + "cell_type": "markdown", + "id": "0c0d5c99", + "metadata": {}, + "source": [ + "### Full state feedback\n", + "\n", + "As a comparison, we can investigate the response of the system if the exact state was available:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "3b6a1f1c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Compute the full state feedback solution\n", + "lqr_ctrl, _ = ct.create_statefbk_iosystem(pvtol, K)\n", + "\n", + "lqr_clsys = ct.interconnect(\n", + " [noisy_pvtol, lqr_ctrl],\n", + " inplist = lqr_ctrl.input_labels[0:pvtol.ninputs + pvtol.nstates] + \\\n", + " noisy_pvtol.input_labels[pvtol.ninputs:],\n", + " inputs = lqr_ctrl.input_labels[0:pvtol.ninputs + pvtol.nstates] + \\\n", + " noisy_pvtol.input_labels[pvtol.ninputs:],\n", + " outlist = pvtol.output_labels + lqr_ctrl.output_labels,\n", + " outputs = pvtol.output_labels + lqr_ctrl.output_labels\n", + ")\n", + "\n", + "# Put together the input for the system\n", + "U = np.vstack([\n", + " np.outer(xe, np.ones_like(T)), # xd\n", + " np.outer(ue, np.ones_like(T)), # ud\n", + " V, W * 0 # disturbances and noise\n", + "])\n", + "\n", + "# Run a simulation with full state feedback\n", + "lqr_resp = ct.input_output_response(lqr_clsys, T, U, x0)\n", + "\n", + "# Compare the results\n", + "plt.plot(resp.states[0], resp.states[1], 'b-', label=\"Extended KF\")\n", + "plt.plot(lqr_resp.states[0], lqr_resp.states[1], 'r-', label=\"Full state\")\n", + "\n", + "plt.xlabel('$x$ [m]')\n", + "plt.ylabel('$y$ [m]')\n", + "plt.axis('equal')\n", + "plt.legend(frameon=False);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc86067c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/pvtol.py b/examples/pvtol.py new file mode 100644 index 000000000..277d0faa1 --- /dev/null +++ b/examples/pvtol.py @@ -0,0 +1,315 @@ +# pvtol.py - (planar) vertical takeoff and landing system model +# RMM, 19 Jan 2022 +# +# This file contains a model and utility function for a (planar) +# vertical takeoff and landing system, as described in FBS2e and OBC. +# This system is approximately differentially flat and the flat system +# mappings are included. +# + +import numpy as np +import matplotlib.pyplot as plt +import control as ct +import control.flatsys as fs +from math import sin, cos +from warnings import warn + +# PVTOL dynamics +def pvtol_update(t, x, u, params): + # Get the parameter values + m = params.get('m', 4.) # mass of aircraft + J = params.get('J', 0.0475) # inertia around pitch axis + r = params.get('r', 0.25) # distance to center of force + g = params.get('g', 9.8) # gravitational constant + c = params.get('c', 0.05) # damping factor (estimated) + + # Get the inputs and states + x, y, theta, xdot, ydot, thetadot = x + F1, F2 = u + + # Constrain the inputs + F2 = np.clip(F2, 0, 1.5 * m * g) + F1 = np.clip(F1, -0.1 * F2, 0.1 * F2) + + # Dynamics + xddot = (F1 * cos(theta) - F2 * sin(theta) - c * xdot) / m + yddot = (F1 * sin(theta) + F2 * cos(theta) - m * g - c * ydot) / m + thddot = (r * F1) / J + + return np.array([xdot, ydot, thetadot, xddot, yddot, thddot]) + +def pvtol_output(t, x, u, params): + return x + +# PVTOL flat system mappings +def pvtol_flat_forward(states, inputs, params={}): + # Get the parameter values + m = params.get('m', 4.) # mass of aircraft + J = params.get('J', 0.0475) # inertia around pitch axis + r = params.get('r', 0.25) # distance to center of force + g = params.get('g', 9.8) # gravitational constant + c = params.get('c', 0.05) # damping factor (estimated) + + # Make sure that c is zero + if c != 0: + warn("System is only approximately flat (c != 0)") + + # Create a list of arrays to store the flat output and its derivatives + zflag = [np.zeros(5), np.zeros(5)] + + # Store states and inputs in variables to make things easier to read + x, y, theta, xdot, ydot, thdot = states + F1, F2 = inputs + + # Use equations of motion for higher derivates + x1ddot = (F1 * cos(theta) - F2 * sin(theta)) / m + x2ddot = (F1 * sin(theta) + F2 * cos(theta) - m * g) / m + thddot = (r * F1) / J + + # Flat output is a point above the vertical axis + zflag[0][0] = x - (J / (m * r)) * sin(theta) + zflag[1][0] = y + (J / (m * r)) * cos(theta) + + zflag[0][1] = xdot - (J / (m * r)) * cos(theta) * thdot + zflag[1][1] = ydot - (J / (m * r)) * sin(theta) * thdot + + zflag[0][2] = (F1 * cos(theta) - F2 * sin(theta)) / m \ + + (J / (m * r)) * sin(theta) * thdot**2 \ + - (J / (m * r)) * cos(theta) * thddot + zflag[1][2] = (F1 * sin(theta) + F2 * cos(theta) - m * g) / m \ + - (J / (m * r)) * cos(theta) * thdot**2 \ + - (J / (m * r)) * sin(theta) * thddot + + # For the third derivative, assume F1, F2 are constant (also thddot) + zflag[0][3] = (-F1 * sin(theta) - F2 * cos(theta)) * (thdot / m) \ + + (J / (m * r)) * cos(theta) * thdot**3 \ + + 3 * (J / (m * r)) * sin(theta) * thdot * thddot + zflag[1][3] = (F1 * cos(theta) - F2 * sin(theta)) * (thdot / m) \ + + (J / (m * r)) * sin(theta) * thdot**3 \ + - 3 * (J / (m * r)) * cos(theta) * thdot * thddot + + # For the fourth derivative, assume F1, F2 are constant (also thddot) + zflag[0][4] = (-F1 * sin(theta) - F2 * cos(theta)) * (thddot / m) \ + + (-F1 * cos(theta) + F2 * sin(theta)) * (thdot**2 / m) \ + + 6 * (J / (m * r)) * cos(theta) * thdot**2 * thddot \ + + 3 * (J / (m * r)) * sin(theta) * thddot**2 \ + - (J / (m * r)) * sin(theta) * thdot**4 + zflag[1][4] = (F1 * cos(theta) - F2 * sin(theta)) * (thddot / m) \ + + (-F1 * sin(theta) - F2 * cos(theta)) * (thdot**2 / m) \ + - 6 * (J / (m * r)) * sin(theta) * thdot**2 * thddot \ + - 3 * (J / (m * r)) * cos(theta) * thddot**2 \ + + (J / (m * r)) * cos(theta) * thdot**4 + + return zflag + +def pvtol_flat_reverse(zflag, params={}): + # Get the parameter values + m = params.get('m', 4.) # mass of aircraft + J = params.get('J', 0.0475) # inertia around pitch axis + r = params.get('r', 0.25) # distance to center of force + g = params.get('g', 9.8) # gravitational constant + c = params.get('c', 0.05) # damping factor (estimated) + + # Create a vector to store the state and inputs + x = np.zeros(6) + u = np.zeros(2) + + # Given the flat variables, solve for the state + theta = np.arctan2(-zflag[0][2], zflag[1][2] + g) + x = zflag[0][0] + (J / (m * r)) * sin(theta) + y = zflag[1][0] - (J / (m * r)) * cos(theta) + + # Solve for thdot using next derivative + thdot = (zflag[0][3] * cos(theta) + zflag[1][3] * sin(theta)) \ + / (zflag[0][2] * sin(theta) - (zflag[1][2] + g) * cos(theta)) + + # xdot and ydot can be found from first derivative of flat outputs + xdot = zflag[0][1] + (J / (m * r)) * cos(theta) * thdot + ydot = zflag[1][1] + (J / (m * r)) * sin(theta) * thdot + + # Solve for the input forces + F2 = m * ((zflag[1][2] + g) * cos(theta) - zflag[0][2] * sin(theta) + + (J / (m * r)) * thdot**2) + F1 = (J / r) * \ + (zflag[0][4] * cos(theta) + zflag[1][4] * sin(theta) +# - 2 * (zflag[0][3] * sin(theta) - zflag[1][3] * cos(theta)) * thdot \ + - 2 * zflag[0][3] * sin(theta) * thdot \ + + 2 * zflag[1][3] * cos(theta) * thdot \ +# - (zflag[0][2] * cos(theta) +# + (zflag[1][2] + g) * sin(theta)) * thdot**2) \ + - zflag[0][2] * cos(theta) * thdot**2 + - (zflag[1][2] + g) * sin(theta) * thdot**2) \ + / (zflag[0][2] * sin(theta) - (zflag[1][2] + g) * cos(theta)) + + return np.array([x, y, theta, xdot, ydot, thdot]), np.array([F1, F2]) + +pvtol = fs.FlatSystem( + pvtol_flat_forward, pvtol_flat_reverse, name='pvtol', + updfcn=pvtol_update, outfcn=pvtol_output, + states = [f'x{i}' for i in range(6)], + inputs = ['F1', 'F2'], + outputs = [f'x{i}' for i in range(6)], + params = { + 'm': 4., # mass of aircraft + 'J': 0.0475, # inertia around pitch axis + 'r': 0.25, # distance to center of force + 'g': 9.8, # gravitational constant + 'c': 0.05, # damping factor (estimated) + } +) + +# +# PVTOL dynamics with wind +# + +def windy_update(t, x, u, params): + # Get the input vector + F1, F2, d = u + + # Get the system response from the original dynamics + xdot, ydot, thetadot, xddot, yddot, thddot = \ + pvtol_update(t, x, u[0:2], params) + + # Now add the wind term + m = params.get('m', 4.) # mass of aircraft + xddot += d / m + + return np.array([xdot, ydot, thetadot, xddot, yddot, thddot]) + +windy_pvtol = ct.NonlinearIOSystem( + windy_update, pvtol_output, name="windy_pvtol", + states = [f'x{i}' for i in range(6)], + inputs = ['F1', 'F2', 'd'], + outputs = [f'x{i}' for i in range(6)] +) + +# +# PVTOL dynamics with noise and disturbances +# + +def noisy_update(t, x, u, params): + # Get the inputs + F1, F2, Dx, Dy, Nx, Ny, Nth = u + + # Get the system response from the original dynamics + xdot, ydot, thetadot, xddot, yddot, thddot = \ + pvtol_update(t, x, u[0:2], params) + + # Get the parameter values we need + m = params.get('m', 4.) # mass of aircraft + J = params.get('J', 0.0475) # inertia around pitch axis + + # Now add the disturbances + xddot += Dx / m + yddot += Dy / m + + return np.array([xdot, ydot, thetadot, xddot, yddot, thddot]) + +def noisy_output(t, x, u, params): + F1, F2, dx, Dy, Nx, Ny, Nth = u + return x + np.array([Nx, Ny, Nth, 0, 0, 0]) + +noisy_pvtol = ct.NonlinearIOSystem( + noisy_update, noisy_output, name="noisy_pvtol", + states = [f'x{i}' for i in range(6)], + inputs = ['F1', 'F2'] + ['Dx', 'Dy'] + ['Nx', 'Ny', 'Nth'], + outputs = pvtol.state_labels +) + +# Add the linearitizations to the dynamics as additional methods +def noisy_pvtol_A(x, u, params={}): + # Get the parameter values we need + m = params.get('m', 4.) # mass of aircraft + J = params.get('J', 0.0475) # inertia around pitch axis + c = params.get('c', 0.05) # damping factor (estimated) + + # Get the angle and compute sine and cosine + theta = x[[2]] + cth, sth = cos(theta), sin(theta) + + # Return the linearized dynamics matrix + return np.array([ + [0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, (-u[0] * sth - u[1] * cth)/m, -c/m, 0, 0], + [0, 0, ( u[0] * cth - u[1] * sth)/m, 0, -c/m, 0], + [0, 0, 0, 0, 0, 0] + ]) +pvtol.A = noisy_pvtol_A + +# Plot the trajectory in xy coordinates +def plot_results(t, x, u): + # Set the size of the figure + plt.figure(figsize=(10, 6)) + + # Top plot: xy trajectory + plt.subplot(2, 1, 1) + plt.plot(x[0], x[1]) + plt.xlabel('x [m]') + plt.ylabel('y [m]') + plt.axis('equal') + + # Time traces of the state and input + plt.subplot(2, 4, 5) + plt.plot(t, x[1]) + plt.xlabel('Time t [sec]') + plt.ylabel('y [m]') + + plt.subplot(2, 4, 6) + plt.plot(t, x[2]) + plt.xlabel('Time t [sec]') + plt.ylabel('theta [rad]') + + plt.subplot(2, 4, 7) + plt.plot(t, u[0]) + plt.xlabel('Time t [sec]') + plt.ylabel('$F_1$ [N]') + + plt.subplot(2, 4, 8) + plt.plot(t, u[1]) + plt.xlabel('Time t [sec]') + plt.ylabel('$F_2$ [N]') + plt.tight_layout() + +# +# Additional functions for testing +# + +# Check flatness calculations +def _pvtol_check_flat(test_points=None, verbose=False): + if test_points is None: + # If no test points, use internal set + mg = 9.8 * 4 + test_points = [ + ([0, 0, 0, 0, 0, 0], [0, mg]), + ([1, 0, 0, 0, 0, 0], [0, mg]), + ([0, 1, 0, 0, 0, 0], [0, mg]), + ([1, 1, 0.1, 0, 0, 0], [0, mg]), + ([0, 0, 0.1, 0, 0, 0], [0, mg]), + ([0, 0, 0, 1, 0, 0], [0, mg]), + ([0, 0, 0, 0, 1, 0], [0, mg]), + ([0, 0, 0, 0, 0, 0.1], [0, mg]), + ([0, 0, 0, 1, 1, 0.1], [0, mg]), + ([0, 0, 0, 0, 0, 0], [1, mg]), + ([0, 0, 0, 0, 0, 0], [0, mg + 1]), + ([0, 0, 0, 0, 0, 0.1], [1, mg]), + ([0.1, 0.2, 0.3, 0.4, 0.5, 0.6], [0.7, mg + 1]), + ] + elif isinstance(test_points, tuple): + # If we only got one test point, convert to a list + test_points = [test_points] + + for x, u in test_points: + x, u = np.array(x), np.array(u) + flag = pvtol_flat_forward(x, u) + xc, uc = pvtol_flat_reverse(flag) + print(f'({x}, {u}): ', end='') + if verbose: + print(f'\n flag: {flag}') + print(f' check: ({xc}, {uc}): ', end='') + if np.allclose(x, xc) and np.allclose(u, uc): + print("OK") + else: + print("ERR") + diff --git a/examples/stochresp.ipynb b/examples/stochresp.ipynb new file mode 100644 index 000000000..224d7f208 --- /dev/null +++ b/examples/stochresp.ipynb @@ -0,0 +1,292 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "03aa22e7", + "metadata": {}, + "source": [ + "# Stochastic Response\n", + "Richard M. Murray, 6 Feb 2022\n", + "\n", + "This notebook illustrates the implementation of random processes and stochastic response. We focus on a system of the form\n", + "\n", + "$$\n", + " \\dot X = A X + F V \\qquad X \\in {\\mathbb R}^n\n", + "$$\n", + "\n", + "where $V$ is a white noise process and the system is a first order linear system." + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "902af902", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import scipy as sp\n", + "import matplotlib.pyplot as plt\n", + "import control as ct\n", + "from math import sqrt, exp\n", + "\n", + "# Fix random number seed to avoid spurious figure regeneration\n", + "np.random.seed(1)" + ] + }, + { + "cell_type": "markdown", + "id": "d020a2ec", + "metadata": {}, + "source": [ + "We begin by defining a simple first order system\n", + "\n", + "$$\n", + "\\frac{dX}{dt} = - a X + V, \\qquad Y = c X\n", + "$$\n", + "\n", + "and a (scalar) white noise signal $V$ with intensity $Q$." + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "60192a8c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# First order system\n", + "a = 1\n", + "c = 1\n", + "sys = ct.ss([[-a]], [[1]], [[c]], 0)\n", + "\n", + "# Create the time vector that we want to use\n", + "Tf = 5\n", + "T = np.linspace(0, Tf, 1000)\n", + "dt = T[1] - T[0]\n", + "\n", + "# Create the basis for a white noise signal\n", + "Q = np.array([[0.1]])\n", + "V = ct.white_noise(T, Q)\n", + "\n", + "plt.plot(T, V[0])\n", + "plt.xlabel('Time [s]')\n", + "plt.ylabel('$V$');" + ] + }, + { + "cell_type": "markdown", + "id": "b4629e2c", + "metadata": {}, + "source": [ + "Note that the magnitude of the signal seems to be much larger than $Q$. This is because we have a Guassian process $\\implies$ the signal consists of a sequence of \"impulse-like\" functions that have magnitude that increases with the time step $dt$ as $1/\\sqrt{dt}$ (this gives covariance $\\mathbb{E}(V(t_1) V^T(t_2)) = Q \\delta(t_2 - t_1)$." + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "23319dc6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean(V) [0.0] = 0.17348786109316244\n", + "cov(V) * dt [0.1] = 0.09633133133133133\n" + ] + } + ], + "source": [ + "# Calculate the sample properties and make sure they match\n", + "print(\"mean(V) [0.0] = \", np.mean(V))\n", + "print(\"cov(V) * dt [%0.3g] = \" % Q, np.round(np.cov(V), decimals=3) * dt)" + ] + }, + { + "cell_type": "markdown", + "id": "3196c60d", + "metadata": {}, + "source": [ + "The response of the system to white noise can be computed using the `input_output_response` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "2bdaaccf", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Response of the first order system\n", + "T, Y = ct.input_output_response(sys, T, V)\n", + "plt.plot(T, Y)\n", + "plt.xlabel('Time [s]')\n", + "plt.ylabel('$Y$');" + ] + }, + { + "cell_type": "markdown", + "id": "ead0232e", + "metadata": {}, + "source": [ + "This is a first order system, and so we can compute the analytical correlation function and compare this to the sampled data:" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "d31ce324", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* mean(Y) [0] = 0.165\n", + "* cov(Y) [0.05] = 0.0151\n" + ] + } + ], + "source": [ + "# Compare static properties to what we expect analytically\n", + "def r(tau):\n", + " return c**2 * Q / (2 * a) * exp(-a * abs(tau))\n", + " \n", + "print(\"* mean(Y) [%0.3g] = %0.3g\" % (0, np.mean(Y)))\n", + "print(\"* cov(Y) [%0.3g] = %0.3g\" % (r(0), np.cov(Y)))" + ] + }, + { + "cell_type": "markdown", + "id": "28321bee", + "metadata": {}, + "source": [ + "Finally, we look at the correlation function for the input and the output:" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "1cf5a4b1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Correlation function for the input\n", + "tau, r_V = ct.correlation(T, V)\n", + "\n", + "plt.plot(tau, r_V, 'r-')\n", + "plt.xlabel(r'$\\tau$')\n", + "plt.ylabel(r'$r_V(\\tau)$');" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "62af90a4", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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zry5Npzqeov/EgkMGxV9JosVB5N4sJc3zVxrWrucCsvKyuLChQsAvPLKK2zZsoW33nrL0DmGRNWTkZFBSEgId999NxMmTOD06dPWLqnCajs78M8RbTicmMG60KpXf0VIYNigS1N81HZy4IlBraxdToVorfn1119p3749L7zwAgDdunVj4MCB1i1M2CQ3Nzf27NnDW2+9xerVq2nbti0LFiwwfEEmc7u7iydtG7vw3sZI8gurVu0VIYFhgzYePc3WqFRmDvXDrXbVGW4aHh7OyJEjGTNmDLVr12bixInWLklUAU5OTrz66quEhITQpUsX3njjjbKr06rC3k7x4si2nEjL5ps9x61djmEkMGxMdn4hb64Np21jFybf5mPtcky2dOlSOnbsSFBQEB999BFHjhzhtttus3ZZogpp3bo1f/zxB3v27KFu3brk5+czc+ZM4uLirF2aSQa28WBQGw8++P0YieeyrV2OISQwbMziHfGcOp/LW3e2t/mHgc6dO0dCQgIA/fv3Z8aMGURHR/PMM8/IMxaiUpRSeHt7A3D48GEWL16Mv78/jz/+eNm/NVullOLfd3VAo/lo8zFrl2MI2/6NdIvJzi/kq13xDPVvaOg04jcrNTWV119/HR8fn7IlOX19ffn0009l/QphNj169CA6OpopU6awePFiWrVqxfTp07l48aK1S7umZq41ebC3D78cOklMStW6rWYKCQwb8tP+RNKzC3h0QEtrl1KuyMhIpk+fjpeXF2+99RbDhw/n7bfftnZZohpr2rQpX3zxBTExMTzyyCMcOXKEWrVKlgZOTEy0cnXlm9HfFycHOxZuj73xwVWMBIaNyC8sZuH2OLp5u9HNhq4uCgsLKSwsBOCHH35g2bJlPPTQQ4SHh/Pf//6X9u3bW7lCcSto3rw5n376Kbt370YpRWZmJu3ataNnz55899135OXlWbvEMvXrOPO3bl6sOnSS0+dvvBpgVSKBYSNWHkzi1PlcnhxsG8NoY2JiePnll2nevDlr1qwB4JlnniEhIYEFCxbg7+9v5QrFrcjevmTqfkdHR959910yMjKYOHEiTZo04cknnyQ+Pt7KFZZ4pJ8vxRqW7KwaHfamksCwARnZ+bz/exSBXq4MaG29PoDCwkLmzZtH37598fPzY/bs2XTt2rVsjQo3NzfpoxA2oWbNmjzxxBNERETw+++/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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Correlation function for the output\n", + "tau, r_Y = ct.correlation(T, Y)\n", + "plt.plot(tau, r_Y)\n", + "plt.xlabel(r'$\\tau$')\n", + "plt.ylabel(r'$r_Y(\\tau)$')\n", + "\n", + "# Compare to the analytical answer\n", + "plt.plot(tau, [r(t)[0, 0] for t in tau], 'k--');" + ] + }, + { + "cell_type": "markdown", + "id": "2a2785e9", + "metadata": {}, + "source": [ + "The analytical curve may or may not line up that well with the correlation function based on the sample. Try running the code again with a different random seed to see how things change based on the specific random sequence chosen at the start.\n", + "\n", + "Note: the _right_ way to compute the correlation function would be to run a lot of different samples of white noise filtered through the system dynamics and compute $R(t_1, t_2)$ across those samples. The `correlation` function computes the covariance between $Y(t + \\tau)$ and $Y(t)$ by varying $t$ over the time range." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd5dfc75", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/vehicle-steering.png b/examples/vehicle-steering.png new file mode 100644 index 000000000..f10aab853 Binary files /dev/null and b/examples/vehicle-steering.png differ diff --git a/examples/vehicle.py b/examples/vehicle.py new file mode 100644 index 000000000..b316ceced --- /dev/null +++ b/examples/vehicle.py @@ -0,0 +1,111 @@ +# vehicle.py - planar vehicle model (with flatness) +# RMM, 16 Jan 2022 + +import numpy as np +import matplotlib.pyplot as plt +import control as ct +import control.flatsys as fs + +# +# Vehicle dynamics +# + +# Function to take states, inputs and return the flat flag +def _vehicle_flat_forward(x, u, params={}): + # Get the parameter values + b = params.get('wheelbase', 3.) + + # Create a list of arrays to store the flat output and its derivatives + zflag = [np.zeros(3), np.zeros(3)] + + # Flat output is the x, y position of the rear wheels + zflag[0][0] = x[0] + zflag[1][0] = x[1] + + # First derivatives of the flat output + zflag[0][1] = u[0] * np.cos(x[2]) # dx/dt + zflag[1][1] = u[0] * np.sin(x[2]) # dy/dt + + # First derivative of the angle + thdot = (u[0]/b) * np.tan(u[1]) + + # Second derivatives of the flat output (setting vdot = 0) + zflag[0][2] = -u[0] * thdot * np.sin(x[2]) + zflag[1][2] = u[0] * thdot * np.cos(x[2]) + + return zflag + +# Function to take the flat flag and return states, inputs +def _vehicle_flat_reverse(zflag, params={}): + # Get the parameter values + b = params.get('wheelbase', 3.) + dir = params.get('dir', 'f') + + # Create a vector to store the state and inputs + x = np.zeros(3) + u = np.zeros(2) + + # Given the flat variables, solve for the state + x[0] = zflag[0][0] # x position + x[1] = zflag[1][0] # y position + if dir == 'f': + x[2] = np.arctan2(zflag[1][1], zflag[0][1]) # tan(theta) = ydot/xdot + elif dir == 'r': + # Angle is flipped by 180 degrees (since v < 0) + x[2] = np.arctan2(-zflag[1][1], -zflag[0][1]) + else: + raise ValueError("unknown direction:", dir) + + # And next solve for the inputs + u[0] = zflag[0][1] * np.cos(x[2]) + zflag[1][1] * np.sin(x[2]) + thdot_v = zflag[1][2] * np.cos(x[2]) - zflag[0][2] * np.sin(x[2]) + u[1] = np.arctan2(thdot_v, u[0]**2 / b) + + return x, u + +# Function to compute the RHS of the system dynamics +def _vehicle_update(t, x, u, params): + b = params.get('wheelbase', 3.) # get parameter values + dx = np.array([ + np.cos(x[2]) * u[0], + np.sin(x[2]) * u[0], + (u[0]/b) * np.tan(u[1]) + ]) + return dx + +def _vehicle_output(t, x, u, params): + return x # return x, y, theta (full state) + +# Create differentially flat input/output system +vehicle = fs.FlatSystem( + _vehicle_flat_forward, _vehicle_flat_reverse, name="vehicle", + updfcn=_vehicle_update, outfcn=_vehicle_output, + inputs=('v', 'delta'), outputs=('x', 'y', 'theta'), + states=('x', 'y', 'theta')) + +# +# Utility function to plot lane change manuever +# + +def plot_lanechange(t, y, u, figure=None, yf=None): + # Plot the xy trajectory + plt.subplot(3, 1, 1, label='xy') + plt.plot(y[0], y[1]) + plt.xlabel("x [m]") + plt.ylabel("y [m]") + if yf: + plt.plot(yf[0], yf[1], 'ro') + + # Plot the inputs as a function of time + plt.subplot(3, 1, 2, label='v') + plt.plot(t, u[0]) + plt.xlabel("t [sec]") + plt.ylabel("velocity [m/s]") + + plt.subplot(3, 1, 3, label='delta') + plt.plot(t, u[1]) + plt.xlabel("t [sec]") + plt.ylabel("steering [rad/s]") + + plt.suptitle("Lane change manuever") + plt.tight_layout()