Example #1
0
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)
Example #2
0
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)
Example #3
0
 def __init__(self, Ts):
     self.A = CTRL.A
     self.B = CTRL.B
     self.C = CTRL.C
     self.L, _, _ = control.lqe(CTRL.A, np.eye(9), CTRL.C, SENSOR.Q_N,
                                SENSOR.R_N)
     self.Ts = Ts
Example #4
0
g = -10
d = 1

# System representation
A = np.array([[0, 1, 0, 0], [0, -d / M, -m * g / M, 0], [0, 0, 0, 1],
              [0, d / (M * L), (m + M) * g / (M * L), 0]])

B = np.array([[0], [1 / M], [0], [-1 / (M * L)]])

C = np.array([[1, 0, 0, 0]])

D = np.zeros(
    (np.size(C, 0),
     np.size(B, 1)))  # D has the same numbers of rows as C, and columns as B

# Disturbance and noise covariances
Vd = 0.1 * np.eye(4)
Vn = 1

# B matrix considering the new inputs (noise and disturbance)
BF = np.column_stack([B, Vd, 0 * B])

sys_single_state = control.ss(A, BF, C, [0, 0, 0, 0, 0, Vn])

sys_full_state = control.ss(A, BF, np.eye(4), np.zeros((4, np.size(BF, 1))))

[Kf, P, E] = control.lqe(A, Vd, C, Vd, Vn)

sys_kf = control.ss(A - Kf * C, np.column_stack([B, Kf]), np.eye(4),
                    0 * (np.column_stack([B, Kf])))
Example #5
0
 def test_LQE(self, matarrayin):
     A, G, C, QN, RN = (matarrayin([[X]]) for X in [0., .1, 1., 10., 2.])
     L, P, poles = lqe(A, G, C, QN, RN)
     self.check_LQE(L, P, poles, G, QN, RN)
    def test_lqr_iosys(self, nstates, ninputs, noutputs, nintegrators, type):
        # Create the system to be controlled (and estimator)
        # TODO: make sure it is controllable?
        if noutputs == 0:
            # Create a system with full state output
            sys = ct.rss(nstates, nstates, ninputs, strictly_proper=True)
            sys.C = np.eye(nstates)
            est = None

        else:
            # Create a system with of the desired size
            sys = ct.rss(nstates, noutputs, ninputs, strictly_proper=True)

            # Create an estimator with different signal names
            L, _, _ = ct.lqe(sys.A, sys.B, sys.C, np.eye(ninputs),
                             np.eye(noutputs))
            est = ss(sys.A - L @ sys.C,
                     np.hstack([L, sys.B]),
                     np.eye(nstates),
                     0,
                     inputs=sys.output_labels + sys.input_labels,
                     outputs=[f'xhat[{i}]' for i in range(nstates)])

        # Decide whether to include integral action
        if nintegrators:
            # Choose the first 'n' outputs as integral terms
            C_int = np.eye(nintegrators, nstates)

            # Set up an augmented system for LQR computation
            # TODO: move this computation into LQR
            A_aug = np.block([[sys.A,
                               np.zeros((sys.nstates, nintegrators))],
                              [C_int,
                               np.zeros((nintegrators, nintegrators))]])
            B_aug = np.vstack([sys.B, np.zeros((nintegrators, ninputs))])
            C_aug = np.hstack(
                [sys.C, np.zeros((sys.C.shape[0], nintegrators))])
            aug = ss(A_aug, B_aug, C_aug, 0)
        else:
            C_int = np.zeros((0, nstates))
            aug = sys

        # Design an LQR controller
        K, _, _ = ct.lqr(aug, np.eye(nstates + nintegrators), np.eye(ninputs))
        Kp, Ki = K[:, :nstates], K[:, nstates:]

        # Create an I/O system for the controller
        ctrl, clsys = ct.create_statefbk_iosystem(sys,
                                                  K,
                                                  integral_action=C_int,
                                                  estimator=est,
                                                  type=type)

        # If we used a nonlinear controller, linearize it for testing
        if type == 'nonlinear':
            clsys = clsys.linearize(0, 0)

        # Make sure the linear system elements are correct
        if noutputs == 0:
            # No estimator
            Ac = np.block([[sys.A - sys.B @ Kp, -sys.B @ Ki],
                           [C_int,
                            np.zeros((nintegrators, nintegrators))]])
            Bc = np.block([[sys.B @ Kp, sys.B],
                           [-C_int, np.zeros((nintegrators, ninputs))]])
            Cc = np.block(
                [[np.eye(nstates),
                  np.zeros((nstates, nintegrators))], [-Kp, -Ki]])
            Dc = np.block([[np.zeros((nstates, nstates + ninputs))],
                           [Kp, np.eye(ninputs)]])
        else:
            # Estimator
            Be1, Be2 = est.B[:, :noutputs], est.B[:, noutputs:]
            Ac = np.block(
                [[sys.A, -sys.B @ Ki, -sys.B @ Kp],
                 [np.zeros((nintegrators, nstates + nintegrators)), C_int],
                 [Be1 @ sys.C, -Be2 @ Ki, est.A - Be2 @ Kp]])
            Bc = np.block([[sys.B @ Kp, sys.B],
                           [-C_int, np.zeros((nintegrators, ninputs))],
                           [Be2 @ Kp, Be2]])
            Cc = np.block(
                [[sys.C, np.zeros((noutputs, nintegrators + nstates))],
                 [np.zeros_like(Kp), -Ki, -Kp]])
            Dc = np.block([[np.zeros((noutputs, nstates + ninputs))],
                           [Kp, np.eye(ninputs)]])

        # Check to make sure everything matches
        np.testing.assert_array_almost_equal(clsys.A, Ac)
        np.testing.assert_array_almost_equal(clsys.B, Bc)
        np.testing.assert_array_almost_equal(clsys.C, Cc)
        np.testing.assert_array_almost_equal(clsys.D, Dc)