Beispiel #1
0
def get_double_mechanical(m1=1, k1=1, b1=1, m2=1, k2=0, b2=0):
    # TODO: determine good default values for m1, k1, b1, m2?
    N = 4
    sys = LTISystem(
        np.c_[  # A
            [0, -k1/m1, 0, k1/m2],
            [1, -b1/m1, 0, b1/m2],
            [0, k1/m1, 0, -(k1+k2)/m2],
            [0, b1/m1, 1, -(b1+b2)/m2]
        ],
        np.r_[0, 1/m1, 0, 0],  # B
        # np.r_[0, 0, 1, 0],  # C
    )
    sys.initial_condition = np.r_[
        0.5/k1 if k1 else 0,
        0,
        0.5/k2 if k2 else 0,
        0
    ]

    def ref_func(*args):
        if len(args) == 1:
            x = np.zeros(N)
        else:
            x = args[1]
        return np.zeros(N)-x
    ref = SystemFromCallable(ref_func, N, N)

    return sys, ref
Beispiel #2
0
def control_systems(request):
    ct_sys, ref = request.param
    Ac, Bc, Cc = ct_sys.data
    Dc = np.zeros((Cc.shape[0], 1))

    Q = np.eye(Ac.shape[0])
    R = np.eye(Bc.shape[1] if len(Bc.shape) > 1 else 1)

    Sc = linalg.solve_continuous_are(Ac, Bc.reshape(-1, 1), Q, R,)
    Kc = linalg.solve(R, Bc.T @ Sc).reshape(1, -1)
    ct_ctr = LTISystem(Kc)

    evals = np.sort(np.abs(
        linalg.eig(Ac, left=False, right=False, check_finite=False)
    ))
    dT = 1/(2*evals[-1])

    Tsim = (8/np.min(evals[~np.isclose(evals, 0)])
            if np.sum(np.isclose(evals[np.nonzero(evals)], 0)) > 0
            else 8
            )

    dt_data = signal.cont2discrete((Ac, Bc.reshape(-1, 1), Cc, Dc), dT)
    Ad, Bd, Cd, Dd = dt_data[:-1]
    Sd = linalg.solve_discrete_are(Ad, Bd.reshape(-1, 1), Q, R,)
    Kd = linalg.solve(Bd.T @ Sd @ Bd + R, Bd.T @ Sd @ Ad)

    dt_sys = LTISystem(Ad, Bd, dt=dT)
    dt_sys.initial_condition = ct_sys.initial_condition
    dt_ctr = LTISystem(Kd, dt=dT)

    yield ct_sys, ct_ctr, dt_sys, dt_ctr, ref, Tsim
Beispiel #3
0
def test_abc():
    for n in range(1, max_n + 1):
        for m in range(1, max_m + 1):
            for p in range(1, max_p + 1):

                A = elem_min + (elem_max - elem_min) * np.random.rand(n, n)
                B = elem_min + (elem_max - elem_min) * np.random.rand(n, m)
                C = elem_min + (elem_max - elem_min) * np.random.rand(p, n)
                x = elem_min + (elem_max - elem_min) * np.random.rand(n)
                u = elem_min + (elem_max - elem_min) * np.random.rand(m)
                if p != n:
                    with pytest.raises(AssertionError):
                        LTISystem(A, B, np.random.rand(n, p))

                sys = LTISystem(A, B, C)
                assert sys.dim_state == n
                assert sys.dim_output == p
                assert sys.dim_input == m

                npt.assert_allclose(
                    sys.state_equation_function(n * max_m + m, x, u),
                    A @ x + B @ u)

                npt.assert_allclose(
                    sys.output_equation_function(n * max_m + m, x), C @ x)
Beispiel #4
0
def test_k():
    for m in range(1, max_m + 1):
        for p in range(1, max_p + 1):
            K = elem_min + (elem_max - elem_min) * np.random.rand(p, m)
            u = elem_min + (elem_max - elem_min) * np.random.rand(m)
            sys = LTISystem(K)
            assert sys.dim_state == 0
            assert sys.dim_input == m
            assert sys.dim_output == p
            npt.assert_allclose(sys.output_equation_function(p * max_m + m, u),
                                K @ u)
Beispiel #5
0
def test_mixed_dts(simulation_results):
    """
    A DT equivalent that is sampled twice as fast should match original DT
    equivalent exactly at t= k*dT under the same inputs.
    """
    results, ct_sys, ct_ctr, dt_sys, dt_ctr, ref, Tsim, tspan, intname = \
        simulation_results
    Ac, Bc, Cc = ct_sys.data
    Dc = np.zeros((Cc.shape[0], 1))

    dt_unique_t, dt_unique_t_idx = np.unique(
        results[0].t, return_index=True
    )
    discrete_sel = dt_unique_t_idx[
        (dt_unique_t < (Tsim*7/8)) & (dt_unique_t % dt_sys.dt == 0)
    ]

    scale_factor = 1/2
    Ad, Bd, Cd, Dd, dT = signal.cont2discrete(
        (Ac, Bc.reshape(-1, 1), Cc, Dc),
        dt_sys.dt*scale_factor
    )
    dt_sys2 = LTISystem(Ad, Bd, dt=dT)
    dt_sys2.initial_condition = ct_sys.initial_condition

    intopts = block_diagram.DEFAULT_INTEGRATOR_OPTIONS.copy()
    intopts['name'] = intname

    bd = BlockDiagram(dt_sys2, ref, dt_ctr)
    bd.connect(dt_sys2, ref)
    bd.connect(ref, dt_ctr)
    bd.connect(dt_ctr, dt_sys2)
    res = bd.simulate(tspan, integrator_options=intopts)

    mixed_t_discrete_t_equal_idx = np.where(
        np.equal(*np.meshgrid(res.t, results[0].t[discrete_sel]))
    )[1]

    mixed_unique_t, mixed_unique_t_idx_rev = np.unique(
        res.t[mixed_t_discrete_t_equal_idx][::-1], return_index=True
    )
    mixed_unique_t_idx = (len(mixed_t_discrete_t_equal_idx)
                          - mixed_unique_t_idx_rev - 1)
    mixed_sel = mixed_t_discrete_t_equal_idx[mixed_unique_t_idx]

    npt.assert_allclose(
        res.x[mixed_sel, :], results[0].x[discrete_sel, :],
        atol=TEST_ATOL, rtol=TEST_RTOL
    )
Beispiel #6
0
def get_cart_pendulum(m=1, M=3, L=0.5, g=9.81, pedant=False):
    N = 4
    sys = LTISystem(
        np.c_[  # A
            [0, 0, 0, 0], [1, 0, 0, 0],
            [0, m * g / M, 0,
             (-1)**(pedant) * (m + M) * g / (M * L)], [0, 0, 1, 0]],
        np.r_[0, 1 / M, 0, 1 / (M * L)],  # B
        # np.r_[1, 0, 1, 0]  # C
    )
    sys.initial_condition = np.r_[0, 0, np.pi / 3, 0]

    def ref_func(*args):
        if len(args) == 1:
            x = np.zeros(N)
        else:
            x = args[1]
        return np.zeros(N) - x

    ref = SystemFromCallable(ref_func, N, N)

    return sys, ref
Beispiel #7
0
def get_electromechanical(b=1, R=1, L=1, K=np.pi / 5, M=1):
    # TODO: determine good reference and/or initial_condition
    # TODO: determine good default values for b, R, L, M
    N = 3
    sys = LTISystem(
        np.c_[  # A
            [0, 0, 0], [1, -b / M, -K / L], [0, K / M, -R / L]],
        np.r_[0, 0, 1 / L],  # B
        # np.r_[1, 0, 0],  # C
    )
    sys.initial_condition = np.ones(N)

    def ref_func(*args):
        if len(args) == 1:
            x = np.zeros(N)
        else:
            x = args[1]
        return np.r_[0, 0, 0] - x

    ref = SystemFromCallable(ref_func, N, N)

    return sys, ref
Beispiel #8
0
def get_double_integrator(m=1000, b=50, d=1):
    N = 2
    sys = LTISystem(
        np.c_[[0, 1], [1, -b/m]],  # A
        np.r_[0, d/m],  # B
        # np.r_[0, 1],  # C
    )

    def ref_func(*args):
        if len(args) == 1:
            x = np.zeros(N)
        else:
            x = args[1]
        return np.r_[d/m, 0]-x
    ref = SystemFromCallable(ref_func, N, N)

    return sys, ref
Beispiel #9
0
def test_feedback_equivalent(simulation_results):
    # (A-BK) should be exactly same as system A,B under feedback K
    results, ct_sys, ct_ctr, dt_sys, dt_ctr, ref, Tsim, tspan, intname = \
        simulation_results

    intopts = block_diagram.DEFAULT_INTEGRATOR_OPTIONS.copy()
    intopts['name'] = intname

    dt_equiv_sys = LTISystem(dt_sys.F + dt_sys.G @ dt_ctr.K,
                             -dt_sys.G @ dt_ctr.K, dt=dt_sys.dt)
    dt_equiv_sys.initial_condition = dt_sys.initial_condition

    dt_bd = BlockDiagram(dt_equiv_sys, ref)
    dt_bd.connect(ref, dt_equiv_sys)
    dt_equiv_res = dt_bd.simulate(tspan, integrator_options=intopts)

    mixed_t_discrete_t_equal_idx = np.where(
        np.equal(*np.meshgrid(dt_equiv_res.t, results[0].t))
    )[1]


    npt.assert_allclose(
        dt_equiv_res.x, results[0].x,
        atol=TEST_ATOL, rtol=TEST_RTOL
    )

    ct_equiv_sys = LTISystem(ct_sys.F + ct_sys.G @ ct_ctr.K,
                             -ct_sys.G @ ct_ctr.K)
    ct_equiv_sys.initial_condition = ct_sys.initial_condition

    ct_bd = BlockDiagram(ct_equiv_sys, ref)
    ct_bd.connect(ref, ct_equiv_sys)
    ct_equiv_res = ct_bd.simulate(tspan, integrator_options=intopts)
    unique_t, unique_t_sel = np.unique(ct_equiv_res.t, return_index=True)
    ct_res = callable_from_trajectory(
        unique_t,
        ct_equiv_res.x[unique_t_sel, :]
    )

    npt.assert_allclose(
        ct_res(results[1].t), results[1].x,
        atol=TEST_ATOL, rtol=TEST_RTOL
    )
Beispiel #10
0
def test_ab():
    for n in range(1, max_n + 1):
        for m in range(1, max_m + 1):
            A = elem_min + (elem_max - elem_min) * np.random.rand(n, n)
            B = elem_min + (elem_max - elem_min) * np.random.rand(n, m)
            x = elem_min + (elem_max - elem_min) * np.random.rand(n)
            u = elem_min + (elem_max - elem_min) * np.random.rand(m)
            if n != m:
                with pytest.raises(AssertionError):
                    LTISystem(np.random.rand(n, m), B)
                with pytest.raises(AssertionError):
                    LTISystem(A, np.random.rand(m, n))

            sys = LTISystem(A, B)
            assert sys.dim_state == n
            assert sys.dim_output == n
            assert sys.dim_input == m

            npt.assert_allclose(
                sys.state_equation_function(n * max_m + m, x, u),
                A @ x + B @ u)

            npt.assert_allclose(sys.output_equation_function(n * max_m + m, x),
                                x)
Beispiel #11
0
# construct second order system state and input matrices
m = 1
d = 1
b = 1
k = 1
Ac = np.c_[[0, -k / m], [1, -b / m]]
Bc = np.r_[0, d / m].reshape(-1, 1)

# augment state and input matrices to add integral error state
A_aug = np.hstack((np.zeros((3, 1)), np.vstack((np.r_[1, 0], Ac))))
B_aug = np.hstack((np.vstack((0, Bc)), -np.eye(3, 1)))

# construct system
aug_sys = LTISystem(
    A_aug,
    B_aug,
)

# construct PID system
Kc = 1
tau_I = 1
tau_D = 1
K = -np.r_[Kc / tau_I, Kc, Kc * tau_D].reshape((1, 3))
pid = LTISystem(K)

# construct reference
ref = SystemFromCallable(lambda *args: np.ones(1), 0, 1)

# create block diagram
BD = BlockDiagram(aug_sys, pid, ref)
BD.connect(aug_sys, pid)  # PID requires feedback
Beispiel #12
0
         (-1)**(pedant) * (m + M) * g / (M * L)], [0, 0, 1, 0]]
    Bc = np.r_[0, 1 / M, 0, 1 / (M * L)].reshape(-1, 1)
    Cc = np.eye(4)
    Dc = np.zeros((4, 1))
    ic = np.r_[0, 0, np.pi / 3, 0]
elif use_model == 1:
    m = 1
    d = 1
    b = 1
    Ac = np.c_[[0, 1], [1, -b / m]]
    Bc = np.r_[0, d / m].reshape(-1, 1)
    Cc = np.eye(2)
    Dc = np.zeros((2, 1))
    ic = np.r_[1, 0]

ct_sys = LTISystem(Ac, Bc, Cc)
ct_sys.initial_condition = ic

n, m = Bc.shape

evals = np.sort(
    np.abs(linalg.eig(Ac, left=False, right=False, check_finite=False)))
dT = 1 / (2 * evals[-1])
Tsim = (8 / np.min(evals[~np.isclose(evals[np.nonzero(evals)], 0)])
        if np.sum(np.isclose(evals[np.nonzero(evals)], 0)) > 0 else 8)

Ad, Bd, Cd, Dd, dT = signal.cont2discrete((Ac, Bc, Cc, Dc), dT)
dt_sys = LTISystem(Ad, Bd, Cd, dt=dT)
dt_sys.initial_condition = ic

Q = np.eye(Ac.shape[0])
Beispiel #13
0
plt.show()

# Plot G components
plt.figure()
plt.plot(sg_sim_res.t, mat_sg_result(sg_sim_res.t)[:, :, -1])
plt.title('forced component of solution to Riccatti differential equation')
plt.legend(['$g_1$', '$g_2$'])
plt.xlabel('$t$, s')
plt.ylabel('$g_{i}(t)$')
plt.show()

# Construct controller from solution to riccati differential algebraic equation
tracking_controller = SystemFromCallable(
    lambda t, xx: -Rn**-1 @ Bn.T @ (mat_sg_result(t)[:, :-1] @ xx +
                                    mat_sg_result(t)[:, -1]), 2, 1)
sys = LTISystem(An, Bn)  # plant system
sys.initial_condition = np.zeros((2, 1))

# simulate controller and plant
control_BD = BlockDiagram(sys, tracking_controller)
control_BD.connect(sys, tracking_controller)
control_BD.connect(tracking_controller, sys)
control_res = control_BD.simulate(tF)

# plot states and reference
plt.figure()
plt.plot(control_res.t, control_res.x, control_res.t, 2 * control_res.t)
plt.title('reference and state vs. time')
plt.xlabel('$t$, s')
plt.legend([r'$x_1$', r'$x_2$', r'$r_1$'])
plt.ylabel('$x_{i}(t)$')
Beispiel #14
0
x0 = np.zeros((3, 1))
u0 = 0
A = sys.state_jacobian_equation_function(t0, x0, u0)
B = sys.input_jacobian_equation_function(t0, x0, u0)

# LQR gain
Q = np.matlib.eye(3)
R = np.matrix([1])
S = linalg.solve_continuous_are(
    A,
    B,
    Q,
    R,
)
K = linalg.solve(R, B.T @ S).reshape(1, -1)
ctr_sys = LTISystem(-K)

# Construct block diagram
BD = BlockDiagram(sys, ctr_sys)
BD.connect(sys, ctr_sys)
BD.connect(ctr_sys, sys)

# case 1 - un-recoverable
sys.initial_condition = np.r_[1, 1, 2.25]
result1 = BD.simulate(tF)
plt.figure()
plt.plot(result1.t, result1.y)
plt.legend(legends)
plt.title('controlled system with unstable initial conditions')
plt.xlabel('$t$, s')
plt.tight_layout()