Пример #1
0
    def test_discrete(self):
        """Test discrete time functionality"""
        # Create some linear and nonlinear systems to play with
        linsys = ct.StateSpace(
            [[-1, 1], [0, -2]], [[0], [1]], [[1, 0]], [[0]], True)
        lnios = ios.LinearIOSystem(linsys)

        # Set up parameters for simulation
        T, U, X0 = self.T, self.U, self.X0

        # Simulate and compare to LTI output
        ios_t, ios_y = ios.input_output_response(lnios, T, U, X0)
        lin_t, lin_y, lin_x = ct.forced_response(linsys, T, U, X0)
        np.testing.assert_array_almost_equal(ios_t, lin_t, decimal=3)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)

        # Test MIMO system, converted to discrete time
        linsys = ct.StateSpace(self.mimo_linsys1)
        linsys.dt = self.T[1] - self.T[0]
        lnios = ios.LinearIOSystem(linsys)

        # Set up parameters for simulation
        T = self.T
        U = [np.sin(T), np.cos(T)]
        X0 = 0

        # Simulate and compare to LTI output
        ios_t, ios_y = ios.input_output_response(lnios, T, U, X0)
        lin_t, lin_y, lin_x = ct.forced_response(linsys, T, U, X0)
        np.testing.assert_array_almost_equal(ios_t, lin_t, decimal=3)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)
Пример #2
0
 def set_poles(self, poles):
     poles = np.asarray(poles)
     self.K_cont = np.asarray(control.place(self.A, self.B, poles))
     self.K_disc = np.asarray(control.place(self.A_d, self.B_d, np.exp(poles * self.Ts)))
     self.A_hat = self.A - self.B @ self.K_cont
     self.sys_cont = control.StateSpace(self.A_hat, self.B, self.C, self.D, remove_useless=False)
     self.A_hat_d = self.A_d - self.B_d @ self.K_disc
     self.sys_disc = control.StateSpace(self.A_hat_d, self.B_d, self.C_d, self.D_d, self.Ts, remove_useless=False)
     return self.K_disc
Пример #3
0
    def test_reduced_order_compensator(self):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            A = np.array([[0., 1., 0., 0.], [0., -25., -0.98, 0.],
                          [0., 0., 0., 1.], [0., 25., 10.78,
                                             0.]]).astype('float')
            B = np.array([[0.], [0.5], [0.], [-0.5]]).reshape(
                (4, 1)).astype('float')
            C = np.array([[1., 0., 0., 0.]]).reshape((1, 4)).astype('float')
            D = np.zeros((1, 1)).astype('float')

            ### Controller ###
            desiredPolesCtrl = np.array([
                -25., -4.,
                np.complex(-2., 2. * np.sqrt(3)),
                np.complex(-2., -2. * np.sqrt(3))
            ])
            G = ch6_utils.bassGura(A, B, desiredPolesCtrl)
            G1 = G[0, 0].reshape((1, 1))
            G2 = G[0, 1:].reshape((1, 3))

            ### Observer ###
            desiredPolesObsv = np.roots(
                np.array([1.0, 2. * 5., 2. * 5.**2, 5.**3]))
            Aaa = np.array(A[0, 0]).reshape((1, 1))
            Aau = np.array(A[0, 1:]).reshape((1, 3))
            Aua = np.array(A[1:, 0]).reshape((3, 1))
            Auu = np.array(A[1:, 1:]).reshape((3, 3))
            Ba = np.array(B[0]).reshape((1, 1))
            Bu = np.array(B[1:]).reshape((3, 1))
            Ca = np.array([[1]]).reshape((1, 1)).astype('float')
            L, Gbb, H = ch7_utils.reducedOrderObserver(Aaa, Aau, Aua, Auu, Ba,
                                                       Bu, Ca,
                                                       desiredPolesObsv)

            ### Compensator ###
            F = Auu - L @ Aau
            Ar = F - H @ G2
            Br = Ar @ L + Gbb - H @ G1
            Cr = G2
            Dr = G1 + G2 @ L
            sysD = control.StateSpace(Ar, Br, Cr, Dr)
            compensatorTF = control.ss2tf(sysD)
            sysplant = control.StateSpace(A, B, C, D)
            openLoopTF = control.ss2tf(sysplant)
            # poles are zeros of return difference
            poles = control.zero(1. + compensatorTF * openLoopTF)
            for p in poles:
                polePresent = any([
                    np.isclose(np.complex(p), np.complex(pt))
                    for pt in np.hstack([desiredPolesCtrl, desiredPolesObsv])
                ])
                self.assertTrue(polePresent)
Пример #4
0
    def test_nonsquare_bdalg(self):
        # Set up parameters for simulation
        T = self.T
        U2 = [np.sin(T), np.cos(T)]
        U3 = [np.sin(T), np.cos(T), T]
        X0 = 0

        # Set up systems to be composed
        linsys_2i3o = ct.StateSpace(
            [[-1, 1, 0], [0, -2, 0], [0, 0, -3]], [[1, 0], [0, 1], [1, 1]],
            [[1, 0, 0], [0, 1, 0], [0, 0, 1]], np.zeros((3, 2)))
        iosys_2i3o = ios.LinearIOSystem(linsys_2i3o)

        linsys_3i2o = ct.StateSpace(
            [[-1, 1, 0], [0, -2, 0], [0, 0, -3]],
            [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
            [[1, 0, 1], [0, 1, -1]], np.zeros((2, 3)))
        iosys_3i2o = ios.LinearIOSystem(linsys_3i2o)

        # Multiplication
        linsys_multiply = linsys_3i2o * linsys_2i3o
        iosys_multiply = iosys_3i2o * iosys_2i3o
        lin_t, lin_y, lin_x = ct.forced_response(linsys_multiply, T, U2, X0)
        ios_t, ios_y = ios.input_output_response(iosys_multiply, T, U2, X0)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)

        linsys_multiply = linsys_2i3o * linsys_3i2o
        iosys_multiply = iosys_2i3o * iosys_3i2o
        lin_t, lin_y, lin_x = ct.forced_response(linsys_multiply, T, U3, X0)
        ios_t, ios_y = ios.input_output_response(iosys_multiply, T, U3, X0)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)

        # Right multiplication
        # TODO: add real tests once conversion from other types is supported
        iosys_multiply = ios.InputOutputSystem.__rmul__(iosys_3i2o, iosys_2i3o)
        ios_t, ios_y = ios.input_output_response(iosys_multiply, T, U3, X0)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)

        # Feedback
        linsys_multiply = ct.feedback(linsys_3i2o, linsys_2i3o)
        iosys_multiply = iosys_3i2o.feedback(iosys_2i3o)
        lin_t, lin_y, lin_x = ct.forced_response(linsys_multiply, T, U3, X0)
        ios_t, ios_y = ios.input_output_response(iosys_multiply, T, U3, X0)
        np.testing.assert_array_almost_equal(ios_y, lin_y, decimal=3)

        # Mismatch should generate exception
        args = (iosys_3i2o, iosys_3i2o)
        self.assertRaises(ValueError, ct.series, *args)
Пример #5
0
def reachable_form(xsys):
    # Check to make sure we have a SISO system
    if not control.issiso(xsys):
        raise control.ControlNotImplemented(
            "Canonical forms for MIMO systems not yet supported")

    # Create a new system, starting with a copy of the old one
    zsys = control.StateSpace(xsys)

    # Generate the system matrices for the desired canonical form
    zsys.B = zeros(shape(xsys.B))
    zsys.B[0, 0] = 1
    zsys.A = zeros(shape(xsys.A))
    Apoly = poly(xsys.A)  # characteristic polynomial
    for i in range(0, xsys.states):
        zsys.A[0, i] = -Apoly[i + 1] / Apoly[0]
        if (i + 1 < xsys.states): zsys.A[i + 1, i] = 1

    # Compute the reachability matrices for each set of states
    Wrx = control.ctrb(xsys.A, xsys.B)
    Wrz = control.ctrb(zsys.A, zsys.B)

    # Transformation from one form to another
    Tzx = Wrz * inv(Wrx)

    # Finally, compute the output matrix
    zsys.C = xsys.C * inv(Tzx)

    return zsys, Tzx
Пример #6
0
    def plot_pzmaps(self):
        """Plots pole-zero maps of open-loop system, closed-loop system, and
        observer poles.
        """
        # Plot pole-zero map of open-loop system
        print("Open-loop poles =", self.sysd.pole())
        print("Open-loop zeroes =", self.sysd.zero())
        plt.subplot(2, 2, 1)
        frccnt.dpzmap(self.sysd, title="Open-loop system")

        # Plot pole-zero map of closed-loop system
        sys = frccnt.closed_loop_ctrl(self)
        print("Closed-loop poles =", sys.pole())
        print("Closed-loop zeroes =", sys.zero())
        plt.subplot(2, 2, 2)
        frccnt.dpzmap(sys, title="Closed-loop system")

        # Plot observer poles
        sys = cnt.StateSpace(self.sysd.A - self.L @ self.sysd.C, self.sysd.B,
                             self.sysd.C, self.sysd.D)
        print("Observer poles =", sys.pole())
        plt.subplot(2, 2, 3)
        frccnt.plot_observer_poles(self)

        plt.tight_layout()
def ApplyBalancedTruncation(SamplingInterval,
                            reducedOrder,
                            A=None,
                            B=None,
                            C=None,
                            D=None,
                            filepath=None):
    r, m, p, n, A, B, C, D = AssignVars(reducedOrder, A, B, C, D, filepath)

    BBT = np.matmul(B, B.transpose())
    CT = C.transpose()

    DiscreteSystem = ct.StateSpace(A, B, CT, D, SamplingInterval)

    # We calculate the cholesky-factors of both Gramians of the system and the Gramians itself.
    Rc = ct.gram(DiscreteSystem, 'cf')
    Wc = np.matmul(Rc, Rc.transpose())
    Ro = ct.gram(DiscreteSystem, 'of')
    Wo = np.matmul(Ro.transpose(), Ro)

    T, T_inv, HSV = SquareRootAlgorithm(Rc, Wc, Ro, Wo)

    PlotData(HSV)

    A_prime, B_prime, C_prime = SimilarityTransform(A, B, CT, T, T_inv)
    A11, B1, C1 = TruncateSystemMatrices(A_prime, B_prime, C_prime, r, m, p)

    return A11, B1, C1
Пример #8
0
def lqr_sys(A, B, C, D, in_q, r=1, num_q=6):
    #parameter
    sys = control.StateSpace(A, B, C, D)
    Q = np.zeros((num_q, num_q))
    R = [r]
    for i in range(num_q):
        Q[i, i] = in_q[i]

    K, solu_R, Eig_sys = control.lqr(sys, Q, r)
    kr = -1 / np.matmul(np.matmul(C, npl.inv((A - np.matmul(B, K)))), B)[0]

    pole, eig_v = npl.eig(A - B * K)
    pole_real = [a.real for a in pole]
    minpol = -3 + min(pole_real)
    repol = []

    for i in range(num_q):
        repol.append(minpol + i + 1)
    repol = np.array(repol)
    L = scis.place_poles(A.transpose(), C.transpose(), repol).gain_matrix
    L = L.transpose()

    upCA = np.column_stack(((A - np.matmul(B, K)), (np.matmul(B, K))))
    downCA = np.column_stack((np.zeros((num_q, num_q)), (A - np.matmul(L, C))))
    CA = np.row_stack((upCA, downCA))
    CB = np.row_stack((B * kr, np.zeros((num_q, 1))))
    CC = np.column_stack((C, np.zeros((1, num_q))))
    CD = np.array([0])

    return CA, CB, CC, CD
    def test_double_integrator(self):
        # Define a second order integrator
        sys = ct.StateSpace([[-1, 1], [0, -2]], [[0], [1]], [[1, 0]], 0)
        flatsys = fs.LinearFlatSystem(sys)

        # Define the endpoints of a trajectory
        x1 = [0, 0]; u1 = [0]; T1 = 1
        x2 = [1, 0]; u2 = [0]; T2 = 2
        x3 = [0, 1]; u3 = [0]; T3 = 3
        x4 = [1, 1]; u4 = [1]; T4 = 4

        # Define the basis set
        poly = fs.PolyFamily(6)

        # Plan trajectories for various combinations
        for x0, u0, xf, uf, Tf in [
            (x1, u1, x2, u2, T2), (x1, u1, x3, u3, T3), (x1, u1, x4, u4, T4)]:
            traj = fs.point_to_point(flatsys, x0, u0, xf, uf, Tf, basis=poly)

            # Verify that the trajectory computation is correct
            x, u = traj.eval([0, Tf])
            np.testing.assert_array_almost_equal(x0, x[:, 0])
            np.testing.assert_array_almost_equal(u0, u[:, 0])
            np.testing.assert_array_almost_equal(xf, x[:, 1])
            np.testing.assert_array_almost_equal(uf, u[:, 1])

            # Simulate the system and make sure we stay close to desired traj
            T = np.linspace(0, Tf, 100)
            xd, ud = traj.eval(T)

            t, y, x = ct.forced_response(sys, T, ud, x0)
            np.testing.assert_array_almost_equal(x, xd, decimal=3)
Пример #10
0
 def test_full_order_compensator(self):
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
         A = np.array([[0., 1., 0., 0.], [0., -25., -0.98, 0.],
                       [0., 0., 0., 1.], [0., 25., 10.78,
                                          0.]]).astype('float')
         B = np.array([[0.], [0.5], [0.], [-0.5]]).astype('float')
         C = np.array([[1., 0., 0., 0.]]).astype('float')
         D = np.zeros((1, 1)).astype('float')
         desiredPolesCtrl = np.array([
             -25., -4.,
             np.complex(-2., 2. * np.sqrt(3)),
             np.complex(-2., -2. * np.sqrt(3))
         ])
         w0 = 5.
         desiredPolesObsv = np.roots(
             np.array([
                 1.0, 2.613 * w0, (2. + np.sqrt(2)) * w0**2, 2.613 * w0**3,
                 w0**4
             ]))
         compensatorTF = fullOrderCompensator(A, B, C, D, desiredPolesCtrl,
                                              desiredPolesObsv)
         openLoopTF = control.ss2tf(control.StateSpace(A, B, C, D))
         # poles are zeros of return difference
         poles = control.zero(1. + compensatorTF * openLoopTF)
         for p in poles:
             polePresent = any([
                 np.isclose(np.complex(p), np.complex(pt))
                 for pt in np.hstack([desiredPolesCtrl, desiredPolesObsv])
             ])
             self.assertTrue(polePresent)
Пример #11
0
 def _reduce_state_space(self):
     x_al    = self.fsf_dict['x_al']
     x_sp_al = self.fsf_dict['x_sp_al']
     x_er_al = self.fsf_dict['x_er_al']
     u_al    = self.fsf_dict['u_al']
     u_sp_al = self.fsf_dict['u_sp_al']
     u_er_al = self.fsf_dict['u_er_al']
     al_sys  = self.fsf_dict['al_sys']
     #Construct reduced state space
     x_ral    = x_al[7:]
     x_sp_ral = x_sp_al[7:]
     x_er_ral = x_er_al[7:]
     u_ral    = u_al[np.ix_([0,1,3,4])]
     u_sp_ral = u_sp_al[np.ix_([0,1,3,4])]
     u_er_ral = u_er_al[np.ix_([0,1,3,4])]
     A        = al_sys.A
     B        = al_sys.B
     C        = al_sys.C
     D        = al_sys.D
     A_ral    = A[np.ix_([7,8,9,10,11,12],[7,8,9,10,11,12])]
     B_ral    = B[np.ix_([7,8,9,10,11,12],[0,1,3,4])]
     C_ral    = C[np.ix_([7,8,9,10,11,12],[7,8,9,10,11,12])]
     D_ral    = D[np.ix_([7,8,9,10,11,12],[0,1,3,4])]
     #Lateral and longitudinal state spaces
     ral_sys = control.StateSpace(A_ral, B_ral, C_ral, D_ral)
     ral_ctrb = control.ctrb(ral_sys.A, ral_sys.B)
     ral_obsv = control.obsv(ral_sys.A, ral_sys.C)
     #Update FSF dictionary
     self.fsf_dict.update(x_ral = x_ral)
     self.fsf_dict.update(x_sp_ral = x_sp_ral)
     self.fsf_dict.update(x_er_ral = x_er_ral)
     self.fsf_dict.update(u_ral = u_ral)
     self.fsf_dict.update(u_sp_ral = u_sp_ral)
     self.fsf_dict.update(u_er_ral = u_er_ral)
     self.fsf_dict.update(ral_sys = ral_sys)
Пример #12
0
    def __init__(self):
        self.fast_d = 0
        self.slow_d = 2
        #define our matrices for the linearized model, which we have
        M = 0.5  #cart mass
        m = 0.2  #pedulum mass
        b = 0.1  #coefficient of friction
        I = 0.006  #inertia
        g = 9.8  #gravity
        l = 0.3  #length of the pendulum
        k = I * (M + m) + M * m * l**2.0
        U2 = (I + m * l**2.0) / k
        U4 = -m * l / k
        TF_2_3 = -(g * m**2.0 * l**2.0) / k
        TF_4_3 = (g * (m + M)) / k
        # TF_4_3 = (m*l*(M+m))*g/k;

        self.B = [[0], [U2], [0], [U4]]
        self.A = [[0, 1, 0, 0], [0, 0, TF_2_3, 0], [0, 0, 0, 1],
                  [0, 0, TF_4_3, 0]]
        self.C = [[1, 0, 0, 0], [0, 0, 1, 0]]
        self.D = [[0], [0]]
        self.sys = control.StateSpace(self.A, self.B, self.C, self.D)
        # R = 1
        # Q = [[20, 0, 0, 0], [0, 0, 0, 0], [0, 0, 3, 0], [0, 0, 0, 0,]]

        #develop our fast dynamic controller (Using pole placement)
        self.K = control.place(self.A, self.B, [-5.1, -5.2, -5.3, -5.4])
        self.K = np.matrix(self.K.tolist()[0])

        #deevelop our slow dynamic controller (PID)
        self.pid = PID(5, 0.1, 0.05)
Пример #13
0
    def objective_func(v):
        A = unpack_v(v, M)
        system_state = x0.reshape((-1, 1))  # make state a column vector
        cov = P0
        meas_err_rec = [0]
        state_rec = [system_state]
        cov_rec = [cov]

        # Convert from cont to disc
        B = np.zeros((system_state.shape[0], 1))
        C = H
        D = np.zeros((1, 1))
        system = control.StateSpace(A, B, C, D)
        dis_system = control.matlab.c2d(system, 8.225e-3)

        for index in range(zk.shape[1] - 1):
            meas_err, system_state, cov = calc_Kalman(dis_system.A, H, Q, R,
                                                      zk[:, index],
                                                      system_state, cov)
            # record and propagate
            meas_err_rec.append(meas_err)
            state_rec.append(system_state)
            cov_rec.append(cov)

        Fest = np.asarray([state[-1] for state in state_rec], dtype=float).T
        sum_state_err = np.linalg.norm(Fest - F_in, 2)
        sum_meas_err = np.linalg.norm(meas_err, 2)

        return sum_state_err + sum_meas_err, state_rec
Пример #14
0
def full_obs(sys,poles):
    """
    Full order observer of the system sys

    Call:
    obs = full_obs(sys,poles)

    Parameters
    ----------
    sys : System in State Space form
    poles: desired observer poles

    Returns
    -------
    obs: ss
    Observer

    """
    if isinstance(sys, ct.TransferFunction):
        "System must be in state space form"
        return
    a = np.mat(sys.A)
    b = np.mat(sys.B)
    c = np.mat(sys.C)
    d = np.mat(sys.D)
    L = ct.place(a.T,c.T,poles)
    L = np.mat(L).T
    Ao = a-L*c
    Bo = np.hstack((b-L*d,L))
    n = np.shape(Ao)
    m = np.shape(Bo)
    Co = np.eye(n[0],n[1])
    Do = np.zeros((n[0],m[1]))
    obs = ct.StateSpace(Ao,Bo,Co,Do,sys.dt)
    return obs
Пример #15
0
def fullOrderCompensator(A, B, C, D, controlPoles, observerPoles):
    """
    combine controller and observer constructions into a compensator design
    currently, supports single-input-single-output systems only

    Inputs:
        A (numpy matrix/array, type=real) - system state matrix
        B (numpy matrix/array, type=real) - system control matrix
        C (numpy matrix/array, type=real) - system measurement matrix
        desiredPoles (numpy matrix/array, type=complex) - desired pole locations
        D (numpy matrix/array, type=real) - direct path from control to measurement matrix
        E (numpy matrix/array, type=real) - (default=None) exogeneous input matrix 
        controlPoles (numpy matrix/array, type=complex) - desired controller system poles
        observerPoles (numpy matrix/array, type=complex) - desired observer system poles

    Returns:
        (control.TransferFunction) - compensator transfer function from input to output

    Raises:
        TypeError - if input system is not SISO
    """
    if B.shape[1] > 1 or C.shape[0] > 1:
        raise TypeError(
            'Only single-input-single-output (SISO) systems are currently supported'
        )
    A = A.astype('float')
    B = B.astype('float')
    C = C.astype('float')
    D = D.astype('float')
    G = ch6_utils.bassGura(A, B, controlPoles)
    K = ch7_utils.obsBassGura(A, C, observerPoles)
    return control.ss2tf(control.StateSpace(A - B @ G - K @ C, K, G, D))
Пример #16
0
    def __init__(self):
        m = 100.0
        b = 20.0
        meas_noise = .001
        self.vel_noise = 0.01
        self.pos_noise = 0.0001
        # meas_noise = 1
        # self.vel_noise = 0.1
        # self.pos_noise = 1

        self.Q = meas_noise
        self.R = np.diag([self.vel_noise,self.pos_noise])

        a = np.array([[-b/m, 0],[1, 0]])
        b = np.array([[1/m], [0]])
        c = np.array([0, 1])
        d = np.array([0])
        self.dt = 0.05

        sysc = control.StateSpace(a, b, c, d)
        sysd = control.c2d(sysc, self.dt)

        self.A = np.array(sysd.A)
        self.B = np.array(sysd.B)
        self.C = np.array(sysd.C)

        given = sio.loadmat('hw1_soln_data.mat')
        self.z = given['z']
        self.xtr = given['xtr']
        self.vtr = given['vtr']
Пример #17
0
def unicycle(states, inputs):
    """Returns the state-space model for a unicycle.

    States: [[x], [y], [theta]]
    Inputs: [[velocity], [angular velocity]]
    Outputs: [[theta]]

    Keyword arguments:
    states -- state vector around which to linearize model
    inputs -- input vector around which to linearize model

    Returns:
    StateSpace instance containing continuous model
    """
    x = states[0, 0]
    y = states[1, 0]
    theta = states[2, 0]
    v = inputs[0, 0]
    omega = inputs[1, 0]
    if abs(v) < 5e-8:
        v = 5e-8
    # fmt: off
    A = np.array([[0, 0, -v * math.sin(theta)], [0, 0, v * math.cos(theta)],
                  [0, 0, 0]])
    B = np.array([[math.cos(theta), 0], [math.sin(theta), 0], [0, 1]])
    C = np.array([[0, 0, 1]])
    D = np.array([[0, 0]])
    # fmt: on

    return ct.StateSpace(A, B, C, D, remove_useless=False)
Пример #18
0
def comp_form_i(sys, obs, K, Cy=[[1]]):
    """Compact form Conroller+Observer+Integral part
    Only for discrete systems!!!

    Call:
    contr = comp_form_i(sys,obs,K [,Cy])

    Parameters
    ----------
    sys : System in State Space form
    obs : Observer in State Space form
    K: State feedback gains
    Cy: feedback matric to choose the output for integral part

    Returns
    -------
    contr: ss
    Controller

    """
    if sys.dt == None:
        print('contr_form_i works only with discrete systems!')
        return

    Ts = sys.dt
    ny = np.shape(sys.C)[0]
    nu = np.shape(sys.B)[1]
    nx = np.shape(sys.A)[0]
    no = np.shape(obs.A)[0]
    ni = np.shape(np.mat(Cy))[0]

    B_obsu = np.mat(obs.B[:, 0:nu])
    B_obsy = np.mat(obs.B[:, nu:nu + ny])
    D_obsu = np.mat(obs.D[:, 0:nu])
    D_obsy = np.mat(obs.D[:, nu:nu + ny])

    k = np.mat(K)
    nk = np.shape(k)[1]
    Ke = k[:, nk - ni:]
    K = k[:, 0:nk - ni]
    X = la.inv(np.eye(nu, nu) + K * D_obsu)

    a = np.mat(obs.A)
    c = np.mat(obs.C)
    Cy = np.mat(Cy)

    tmp1 = np.hstack((a - B_obsu * X * K * c, -B_obsu * X * Ke))

    tmp2 = np.hstack((np.zeros((ni, no)), np.eye(ni, ni)))
    A_ctr = np.vstack((tmp1, tmp2))

    tmp1 = np.hstack((np.zeros((no, ni)), -B_obsu * X * K * D_obsy + B_obsy))
    tmp2 = np.hstack((np.eye(ni, ni) * Ts, -Cy * Ts))
    B_ctr = np.vstack((tmp1, tmp2))

    C_ctr = np.hstack((-X * K * c, -X * Ke))
    D_ctr = np.hstack((np.zeros((nu, ni)), -X * K * D_obsy))

    contr = ct.StateSpace(A_ctr, B_ctr, C_ctr, D_ctr, sys.dt)
    return contr
Пример #19
0
    def parameters(self):
        self.M = 0.5
        self.m = 0.2
        self.b = 0.1
        self.I = 0.006
        self.g = 9.8
        self.l = 0.3
        self.p = self.I*(self.M+self.m)+self.M*self.m*self.l**2; # denominator for the A and B matrices
        self.theta1 = -(self.I+self.m*self.l**2)*self.b/self.p
        self.theta2 = (self.m**2*self.g*self.l**2)/self.p
        self.theta3 = -(self.m*self.l*self.b)/self.p
        self.theta4 = (self.m*self.g*self.l*(self.M+self.m)/self.p)
        self.A = np.asarray([[0,1,0,0],[0,self.theta1,self.theta2,0],
                             [0,0,0,1],[0,self.theta3,self.theta4,0]])
        self.B = np.asarray([[0],[(self.I+self.m*self.l**2)/self.p],
                            [0],[self.m*self.l/self.p]])
        self.C = np.asarray([[1,0,0,0],[0,0,1,0]])
        self.D = np.asarray([[0],[0]])
        self.ssm = control.StateSpace(self.A, self.B, self.C, self.D)
        self.ssmd = self.ssm.sample(self.ts, method='euler')

        self.nx = self.A.shape[0]
        self.ny = self.C.shape[0]
        self.nu = self.B.shape[1]
        self.x0 = np.asarray([0,0,-1,0])
Пример #20
0
    def get_plant_op(self, u_h, reduce_states):
        '''
        Interpolate system matrices using wind speed operating point uh_op = mean(u_h)

        inputs: u_h timeseries of wind speeds

        '''

        uh_op = np.mean(u_h)

        if len(self.u_h) > 1:
            f_A = sp.interpolate.interp1d(self.u_h, self.A_ops)
            f_B = sp.interpolate.interp1d(self.u_h, self.B_ops)
            f_C = sp.interpolate.interp1d(self.u_h, self.C_ops)
            f_D = sp.interpolate.interp1d(self.u_h, self.D_ops)

            f_u = sp.interpolate.interp1d(self.u_h, self.u_ops)
            f_y = sp.interpolate.interp1d(self.u_h, self.y_ops)
            f_x = sp.interpolate.interp1d(self.u_h, self.x_ops)

            A = f_A(uh_op)
            B = f_B(uh_op)
            C = f_C(uh_op)
            D = f_D(uh_op)

            u_op = f_u(uh_op)
            x_op = f_x(uh_op)
            y_op = f_y(uh_op)
        else:
            print('WARNING: Only one linearization, at ' + str(self.u_h[0]) +
                  ' m/s')
            print('Simulation operating point is ' + str(uh_op) + 'm/s')
            print('Results may not be as expected')

            # Set linear system to only linearization
            A = self.A_ops[:, :, 0]
            B = self.B_ops[:, :, 0]
            C = self.C_ops[:, :, 0]
            D = self.D_ops[:, :, 0]

            u_op = self.u_ops[:, 0]
            y_op = self.y_ops[:, 0]
            x_op = self.x_ops[:, 0]

        # form state space model  TODO: generalize using linear description strings
        P_op = co.StateSpace(A, B, C, D)
        if reduce_states:
            P_op = co.minreal(P_op, tol=1e-7, verbose=False)
        P_op.InputName = ['RtVAvgxh', 'BldPitch']
        P_op.OutputName = ['GenSpeed', 'TwrBsMyt', 'PtfmPitch', 'NcIMUTAzs']

        # operating points dict
        ops = {}
        ops['u'] = u_op[self.ind_fast_inps]
        ops['uh'] = uh_op
        ops['y'] = y_op[self.ind_fast_outs]
        ops['x'] = x_op

        return ops, P_op
def differential_drive(motor, num_motors, m, r, rb, J, Gl, Gr, states):
    """Returns the state-space model for a differential drive.

    States: [[x], [y], [theta], [left velocity], [right velocity]]
    Inputs: [[left voltage], [right voltage]]
    Outputs: [[theta], [left velocity], [right velocity]]

    Keyword arguments:
    motor -- instance of DcBrushedMotor
    num_motors -- number of motors driving the mechanism
    m -- mass of robot in kg
    r -- radius of wheels in meters
    rb -- radius of robot in meters
    J -- moment of inertia of the differential drive in kg-m^2
    Gl -- gear ratio of left side of differential drive
    Gr -- gear ratio of right side of differential drive
    states -- state vector around which to linearize model

    Returns:
    StateSpace instance containing continuous model
    """
    motor = fct.models.gearbox(motor, num_motors)

    C1 = -(Gl ** 2) * motor.Kt / (motor.Kv * motor.R * r ** 2)
    C2 = Gl * motor.Kt / (motor.R * r)
    C3 = -(Gr ** 2) * motor.Kt / (motor.Kv * motor.R * r ** 2)
    C4 = Gr * motor.Kt / (motor.R * r)
    x = states[0, 0]
    y = states[1, 0]
    theta = states[2, 0]
    vl = states[3, 0]
    vr = states[4, 0]
    v = (vr + vl) / 2.0
    if abs(v) < 1e-9:
        vl = 1e-9
        vr = 1e-9
        v = 1e-9
    # fmt: off
    A = np.array([[0, 0, 0, 0.5, 0.5],
                  [0, 0, v, 0, 0],
                  [0, 0, 0, -0.5 / rb, 0.5 / rb],
                  [0, 0, 0, (1 / m + rb**2 / J) * C1, (1 / m - rb**2 / J) * C3],
                  [0, 0, 0, (1 / m - rb**2 / J) * C1, (1 / m + rb**2 / J) * C3]])
    B = np.array([[0, 0],
                  [0, 0],
                  [0, 0],
                  [(1 / m + rb**2 / J) * C2, (1 / m - rb**2 / J) * C4],
                  [(1 / m - rb**2 / J) * C2, (1 / m + rb**2 / J) * C4]])
    C = np.array([[0, 0, 1, 0, 0],
                  [0, 0, 0, 1, 0],
                  [0, 0, 0, 0, 1]])
    D = np.array([[0, 0],
                  [0, 0],
                  [0, 0]])
    # fmt: on

    return ct.StateSpace(A, B, C, D, remove_useless=False)
Пример #22
0
def plot_observer_poles(system):
    """Plot discrete observer poles.

    Keyword arguments:
    system -- a System instance
    """
    sys_cl = cnt.StateSpace(system.sysd.A - system.L * system.sysd.C,
                            system.sysd.B, system.sysd.C, system.sysd.D)
    dpzmap(sys_cl, title="Observer poles")
Пример #23
0
def state_space2(CZ0, CXq, CZadot, Cnbdot, Clr, Clda, muc, c, V, CZa, Cmadot,
                 KY2, CXu, CXa, CZq, CZu, CX0, Cmu, Cma, Cmq, CXde, CZde, Cmde,
                 CYbdot, b, mub, KX2, KXZ, KZ2, CYb, Cl, CYp, CYr, Clb, Clp,
                 Cnb, Cnp, Cnr, CYda, Cldr, Cnda, Cndr, CYdr):
    #SYMETRIC FLIGHT CONDITIONS
    CS1 = np.matrix([[-2 * muc * c / V / V, 0, 0, 0],
                     [0, (CZadot - 2 * muc) * c / V, 0, 0], [0, 0, -c / V, 0],
                     [0, Cmadot * c / V, 0, -2 * muc * KY2 * c * c / V / V]])
    CS2 = np.matrix([[CXu / V, CXa, CZ0, CXq * c / V],
                     [CZu / V, CZa, -CX0, c / V * (CZq + 2 * muc)],
                     [0, 0, 0, c / V], [Cmu / V, Cma, 0, Cmq * c / V]])
    CS3 = np.matrix([[CXde], [CZde], [0], [Cmde]])
    A_s = -CS1**(-1) * CS2
    B_s = -CS1**(-1) * CS3
    C_s = np.matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
    D_s = np.matrix([[0], [0], [0], [0]])

    sys_sym = control.StateSpace(A_s, B_s, C_s, D_s)

    #ASYMMETRIC FLIGHT CONDITIONS
    CA1 = np.matrix([[(CYbdot - 2 * mub) * b / V, 0, 0, 0],
                     [0, -b / 2 / V, 0, 0],
                     [
                         0, 0, -4 * mub * KX2 * b * b / 2 / V / V,
                         4 * mub * KXZ * b * b / 2 / V / V
                     ],
                     [
                         Cnb * b / V, 0, 4 * mub * KXZ * b * b / 2 / V / V,
                         -4 * mub * KZ2 * b * b / 2 / V / V
                     ]])
    CA2 = np.matrix([[CYb, Cl, CYp * b / V / 2, (CYr - 4 * mub) * b / 2 / V],
                     [0, 0, b / V / 2, 0],
                     [Clb, 0, Clp * b / 2 / V, Clr * b / 2 / V],
                     [Cnb, 0, Cnp * b / 2 / V, Cnr * b / 2 / V]])
    CA3 = np.matrix([[CYda, CYdr], [0, 0], [Clda, Cldr], [Cnda, Cndr]])

    A_a = -CA1**(-1) * CA2
    B_a = -CA1**(-1) * CA3
    C_a = np.matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
    D_a = np.matrix([[0, 0], [0, 0], [0, 0], [0, 0]])

    sys_asym = control.StateSpace(A_a, B_a, C_a, D_a)

    return sys_sym, sys_asym
    def make_model(self, v):
        A = np.zeros((3, 3))
        if abs(v) < 1e-9:
            v = 1e-9
        A[1, 2] = v
        B = np.array([[1, 0], [0, 0], [0, 1]])
        C = np.array([[0, 0, 1]])
        D = np.array([[0, 0]])

        return ct.StateSpace(A, B, C, D, remove_useless=False)
Пример #25
0
def create_uncertain_copy(nominal_dynamics: Twipr2D, std_dev_mass):
    disturbed_dynamics = copy.deepcopy(nominal_dynamics)
    m_a = abs(std_dev_mass * np.random.randn())
    disturbed_dynamics.model.l = (disturbed_dynamics.model.l*disturbed_dynamics.model.m_b + 0.2 * m_a) / (m_a + disturbed_dynamics.model.m_b)
    disturbed_dynamics.model.I_y = disturbed_dynamics.model.I_y + 0.2**2*m_a
    disturbed_dynamics.model.m_b = disturbed_dynamics.model.m_b + m_a

    disturbed_dynamics.A, disturbed_dynamics.B, disturbed_dynamics.C, disturbed_dynamics.D = disturbed_dynamics.linear_model()
    # generate a linear continious model
    disturbed_dynamics.sys_cont = control.StateSpace(disturbed_dynamics.A, disturbed_dynamics.B, disturbed_dynamics.C, disturbed_dynamics.D, remove_useless=False)
    # convert the continious-time model to discrete-time
    disturbed_dynamics.sys_disc = control.c2d(disturbed_dynamics.sys_cont, disturbed_dynamics.Ts)
    disturbed_dynamics.A_d = np.asarray(disturbed_dynamics.sys_disc.A)
    disturbed_dynamics.B_d = np.asarray(disturbed_dynamics.sys_disc.B)
    disturbed_dynamics.C_d = np.asarray(disturbed_dynamics.sys_disc.C)
    disturbed_dynamics.D_d = np.asarray(disturbed_dynamics.sys_disc.D)

    disturbed_dynamics.A_hat_d = disturbed_dynamics.A_d - disturbed_dynamics.B_d @ disturbed_dynamics.K_disc
    disturbed_dynamics.sys_disc = control.StateSpace(disturbed_dynamics.A_hat_d, disturbed_dynamics.B_d, disturbed_dynamics.C_d, disturbed_dynamics.D_d, disturbed_dynamics.Ts, remove_useless=False)
    return disturbed_dynamics
Пример #26
0
    def setUp(self):
        # Turn off numpy matrix warnings
        import warnings
        warnings.simplefilter('ignore', category=PendingDeprecationWarning)

        # Create a single input/single output linear system
        self.siso_linsys = ct.StateSpace([[-1, 1], [0, -2]], [[0], [1]],
                                         [[1, 0]], [[0]])

        # Create a multi input/multi output linear system
        self.mimo_linsys1 = ct.StateSpace([[-1, 1], [0, -2]], [[1, 0], [0, 1]],
                                          [[1, 0], [0, 1]], np.zeros((2, 2)))

        # Create a multi input/multi output linear system
        self.mimo_linsys2 = ct.StateSpace([[-1, 1], [0, -2]], [[0, 1], [1, 0]],
                                          [[1, 0], [0, 1]], np.zeros((2, 2)))

        # Create simulation parameters
        self.T = np.linspace(0, 10, 100)
        self.U = np.sin(self.T)
        self.X0 = [0, 0]
Пример #27
0
def closed_loop_ctrl(system):
    """Constructs the closed-loop system for a discrete controller.

    Keyword arguments:
    system -- a System instance

    Returns:
    StateSpace instance representing closed-loop controller.
    """
    return cnt.StateSpace(system.sysd.A - system.sysd.B * system.K,
                          system.sysd.B * system.K,
                          system.sysd.C - system.sysd.D * system.K,
                          system.sysd.D * system.K)
Пример #28
0
def GenerateModel(Mass, Stiffness, Damping):
    n = len(Mass)
    M, K, G, T_u, T_w = GenerateMatricess(Mass, Stiffness, Damping)
    A = np.block([[np.zeros((n, n)), np.identity(n)],
                  [-np.linalg.inv(M) @ K, -np.linalg.inv(M) @ G]])
    B_s = np.block([[np.zeros((n, 1))], [-np.linalg.inv(M) @ T_u]])
    print(np)
    E = np.block([[np.zeros((n, 1))], [-T_w]])
    B = np.block([B_s, E])
    D = [1, 0]
    C = np.block([[np.zeros((1, n)), np.ones((1, n))]])
    sys = con.StateSpace(A, B, C, D)
    return sys
Пример #29
0
    def __init__(self, slow_d):
        self.fast_d = 0

        #stay still
        # self.slow_d = -5 + 5*0.2

        #move
        self.slow_d = slow_d

        self.desired_states = np.matrix([[0], [slow_d], [0], [self.fast_d]])
        #define our matrices for the linearized model, which we have
        M = 0.5  #cart mass
        m = 0.2  #pedulum mass
        b = 0.1  #coefficient of friction
        I = 0.006  #inertia
        g = 9.8  #gravity
        l = 0.3  #length of the pendulum
        k = I * (M + m) + M * m * l**2.0
        U2 = (I + m * l**2.0) / k
        U4 = -m * l / k
        TF_2_3 = -(g * m**2.0 * l**2.0) / k
        TF_4_3 = (g * (m + M)) / k
        # TF_4_3 = (m*l*(M+m))*g/k;

        self.B = [[0], [U2], [0], [U4]]
        self.A = [[0, 1, 0, 0], [0, 0, TF_2_3, 0], [0, 0, 0, 1],
                  [0, 0, TF_4_3, 0]]
        self.C = [[1, 0, 0, 0], [0, 0, 1, 0]]
        self.D = [[0], [0]]
        self.sys = control.StateSpace(self.A, self.B, self.C, self.D)
        # R = 1
        # Q = [[20, 0, 0, 0], [0, 0, 0, 0], [0, 0, 3, 0], [0, 0, 0, 0,]]

        #develop our fast dynamic controller (Using pole placement)
        self.K = control.place(self.A, self.B, [-5.1, -5.2, -5.3, -5.4])
        self.K = np.matrix(self.K.tolist()[0])
        print("K = ", np.matrix(self.K))
        print("A = ", np.matrix(self.A))
        # print("B = ",np.matrix(self.B))
        # print(np.linalg.eig(np.subtract(self.A, np.matmul(self.B,self.K))))
        # print(np.subtract(self.A, np.matmul(self.B,self.K)))
        exit()

        self.closed_loop = np.subtract(self.A, np.matmul(self.B, self.K))
        self.K2 = control.place(self.closed_loop, self.B,
                                [-5.1, -5.2, -5.3, -5.4])

        #deevelop our slow dynamic controller (PID)
        self.pid = PID(2, 1, 0.0)
Пример #30
0
def sys_dict():
    sdict = {}
    sdict['ss'] = ct.StateSpace([[-1]], [[1]], [[1]], [[0]])
    sdict['tf'] = ct.TransferFunction([1], [0.5, 1])
    sdict['tfx'] = ct.TransferFunction([1, 1], [1])  # non-proper TF
    sdict['frd'] = ct.frd([10 + 0j, 9 + 1j, 8 + 2j, 7 + 3j], [1, 2, 3, 4])
    sdict['lio'] = ct.LinearIOSystem(ct.ss([[-1]], [[5]], [[5]], [[0]]))
    sdict['ios'] = ct.NonlinearIOSystem(sdict['lio']._rhs,
                                        sdict['lio']._out,
                                        inputs=1,
                                        outputs=1,
                                        states=1)
    sdict['arr'] = np.array([[2.0]])
    sdict['flt'] = 3.
    return sdict