def test_nyquist_exceptions(): # MIMO not implemented sys = ct.rss(2, 2, 2) with pytest.raises(ct.exception.ControlMIMONotImplemented, match="only supports SISO"): ct.nyquist_plot(sys) # Legacy keywords for arrow size sys = ct.rss(2, 1, 1) with pytest.warns(FutureWarning, match="use `arrow_size` instead"): ct.nyquist_plot(sys, arrow_width=8, arrow_length=6) # Unknown arrow keyword with pytest.raises(ValueError, match="unsupported arrow location"): ct.nyquist_plot(sys, arrows='uniform') # Bad value for indent direction sys = ct.tf([1], [1, 0, 1]) with pytest.raises(ValueError, match="unknown value for indent"): ct.nyquist_plot(sys, indent_direction='up') # Discrete time system sampled above Nyquist frequency sys = ct.drss(2, 1, 1) sys.dt = 0.01 with pytest.warns(UserWarning, match="above Nyquist"): ct.nyquist_plot(sys, np.logspace(-2, 3))
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_lqr_integral_discrete(self): # Generate a discrete time system for testing sys = ct.drss(4, 4, 2, strictly_proper=True) sys.C = np.eye(4) # reset output to be full state C_int = np.eye(2, 4) # integrate outputs for first two states nintegrators = C_int.shape[0] # Generate a controller with integral action K, _, _ = ct.lqr(sys, np.eye(sys.nstates + nintegrators), np.eye(sys.ninputs), integral_action=C_int) Kp, Ki = K[:, :sys.nstates], K[:, sys.nstates:] # Create an I/O system for the controller ctrl, clsys = ct.create_statefbk_iosystem(sys, K, integral_action=C_int) # Construct the state space matrices by hand A_ctrl = np.eye(nintegrators) B_ctrl = np.block( [[-C_int, np.zeros((nintegrators, sys.ninputs)), C_int]]) C_ctrl = -K[:, sys.nstates:] D_ctrl = np.block([[Kp, np.eye(nintegrators), -Kp]]) # Check to make sure everything matches assert ct.isdtime(clsys) np.testing.assert_array_almost_equal(ctrl.A, A_ctrl) np.testing.assert_array_almost_equal(ctrl.B, B_ctrl) np.testing.assert_array_almost_equal(ctrl.C, C_ctrl) np.testing.assert_array_almost_equal(ctrl.D, D_ctrl)
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 __init__(self, states=1) -> None: """Create random discrete state space system :param states: number of states, defaults to 1 :type states: int, optional """ system = control.drss(states=states) self.A = np.array(system.A) self.B = np.array(system.B) self.C = np.array(system.C) self.D = np.array(system.D) self.x = np.zeros((states, 1), dtype=np.float64)
def test_nyquist_exceptions(): # MIMO not implemented sys = ct.rss(2, 2, 2) with pytest.raises(ct.exception.ControlMIMONotImplemented, match="only supports SISO"): ct.nyquist_plot(sys) # Legacy keywords for arrow size sys = ct.rss(2, 1, 1) with pytest.warns(FutureWarning, match="use `arrow_size` instead"): ct.nyquist_plot(sys, arrow_width=8, arrow_length=6) # Discrete time system sampled above Nyquist frequency sys = ct.drss(2, 1, 1) sys.dt = 0.01 with pytest.warns(UserWarning, match="above Nyquist"): ct.nyquist_plot(sys, np.logspace(-2, 3))
def __init__(self, states=1) -> None: """Create random discrete state space system Args: states (int, optional): number of states. Defaults to 1. Returns: None: [description] """ import control system = control.drss(states=states) self.A = np.array(system.A) self.B = np.array(system.B) self.C = np.array(system.C) self.D = np.array(system.D) self.x = np.zeros((states, 1), dtype=np.float64)
def random_dtime_sys(Nout, Nin, Ts, Nstate=5): np.random.seed(0) sys_ = co.drss(Nstate, Nin, Nout) sys_.dt = Ts sys = co.tf(sys_) return sys