def test_constructor_inconsistent_columns(self): """Give the constructor inputs that do not have the same number of columns in each row.""" with pytest.raises(ValueError): TransferFunction(1., [[[1.]], [[2.], [3.]]]) with pytest.raises(ValueError): TransferFunction([[[1.]], [[2.], [3.]]], 1.)
def setUp(self): """Set up a SISO and MIMO system to test operations on.""" # Single input, single output continuous and discrete time systems sys = matlab.rss(3, 1, 1) self.siso_ss1 = StateSpace(sys.A, sys.B, sys.C, sys.D) self.siso_ss1c = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.0) self.siso_ss1d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.1) self.siso_ss2d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.2) self.siso_ss3d = StateSpace(sys.A, sys.B, sys.C, sys.D, True) # Two input, two output continuous time system A = [[-3., 4., 2.], [-1., -3., 0.], [2., 5., 3.]] B = [[1., 4.], [-3., -3.], [-2., 1.]] C = [[4., 2., -3.], [1., 4., 3.]] D = [[-2., 4.], [0., 1.]] self.mimo_ss1 = StateSpace(A, B, C, D) self.mimo_ss1c = StateSpace(A, B, C, D, 0) # Two input, two output discrete time system self.mimo_ss1d = StateSpace(A, B, C, D, 0.1) # Same system, but with a different sampling time self.mimo_ss2d = StateSpace(A, B, C, D, 0.2) # Single input, single output continuus and discrete transfer function self.siso_tf1 = TransferFunction([1, 1], [1, 2, 1]) self.siso_tf1c = TransferFunction([1, 1], [1, 2, 1], 0) self.siso_tf1d = TransferFunction([1, 1], [1, 2, 1], 0.1) self.siso_tf2d = TransferFunction([1, 1], [1, 2, 1], 0.2) self.siso_tf3d = TransferFunction([1, 1], [1, 2, 1], True)
def test_freqresp_mimo(self): """Evaluate the MIMO magnitude and phase at multiple frequencies.""" num = [[[1., 2.], [0., 3.], [2., -1.]], [[1.], [4., 0.], [1., -4., 3.]]] den = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], [[3., 0., .0], [2., -1., -1.], [1.]]] sys = TransferFunction(num, den) true_omega = [0.1, 1., 10.] true_mag = [[[0.49628709, 0.30714755, 0.03347381], [300., 3., 0.03], [1., 1., 1.]], [[33.333333, 0.33333333, 0.00333333], [0.39028569, 1.26491106, 0.19875914], [3.01663720, 4.47213595, 104.92378186]]] true_phase = [[[3.7128711e-4, 0.18534794, 1.30770596], [-np.pi, -np.pi, -np.pi], [0., 0., 0.]], [[-np.pi, -np.pi, -np.pi], [-1.66852323, -1.89254688, -1.62050658], [-0.13298964, -1.10714871, -2.75046720]]] mag, phase, omega = sys.frequency_response(true_omega) np.testing.assert_array_almost_equal(mag, true_mag) np.testing.assert_array_almost_equal(phase, true_phase) np.testing.assert_allclose(omega, true_omega)
def winding_number_condition(plant_1: TransferFunction, plant_2: TransferFunction) -> bool: """ :param plant_1: Transferfunction of linearized SISO plant :param plant_2: Transferfunction of linearized SISO plant returns: True if plant_1 and plant_2 satisfy the winding number condition. (False if not) """ plant_2_c = conjugate_plant(plant_2) def f(x): p = abs(evalfr(1 + plant_2_c * plant_1, 1j * x)) return p min_obj = minimize_scalar(f, method="golden") if f(min_obj.x) == 0: return False wno = nyquist_plot(1 + plant_2_c * plant_1) eta_0 = 0 eta_1 = 0 eta_2 = 0 plant_1_poles = plant_1.pole() plant_2_poles = plant_2.pole() for p in plant_1_poles: if np.real(p) > 0: eta_1 = eta_1 + 1 for p in plant_2_poles: if np.real(p) > 0: eta_2 = eta_2 + 1 if np.real(p) == 0: eta_0 = eta_0 + 1 return wno + eta_1 - eta_2 - eta_0 == 0
def test_constructor_zero_denominator(self): """Give the constructor a transfer function with a zero denominator.""" with pytest.raises(ValueError): TransferFunction(1., 0.) with pytest.raises(ValueError): TransferFunction([[[1.], [2., 3.]], [[-1., 4.], [3., 2.]]], [[[1., 0.], [0.]], [[0., 0.], [2.]]])
def testSystemInitialization(self, tsys): # Check to make sure systems are discrete time with proper variables assert tsys.siso_ss1.dt is None assert tsys.siso_ss1c.dt == 0 assert tsys.siso_ss1d.dt == 0.1 assert tsys.siso_ss2d.dt == 0.2 assert tsys.siso_ss3d.dt is True assert tsys.mimo_ss1c.dt == 0 assert tsys.mimo_ss1d.dt == 0.1 assert tsys.mimo_ss2d.dt == 0.2 assert tsys.siso_tf1.dt is None assert tsys.siso_tf1c.dt == 0 assert tsys.siso_tf1d.dt == 0.1 assert tsys.siso_tf2d.dt == 0.2 assert tsys.siso_tf3d.dt is True # keyword argument check # dynamic systems assert TransferFunction(1, [1, 1], dt=0.1).dt == 0.1 assert TransferFunction(1, [1, 1], 0.1).dt == 0.1 assert StateSpace(1,1,1,1, dt=0.1).dt == 0.1 assert StateSpace(1,1,1,1, 0.1).dt == 0.1 # static gain system, dt argument should still override default dt assert TransferFunction(1, [1,], dt=0.1).dt == 0.1 assert TransferFunction(1, [1,], 0.1).dt == 0.1 assert StateSpace(0,0,1,1, dt=0.1).dt == 0.1 assert StateSpace(0,0,1,1, 0.1).dt == 0.1
def tsys(self): """Create some systems for testing""" class Tsys: pass T = Tsys() # Single input, single output continuous and discrete time systems sys = rss(3, 1, 1) T.siso_ss1 = StateSpace(sys.A, sys.B, sys.C, sys.D, None) T.siso_ss1c = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.0) T.siso_ss1d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.1) T.siso_ss2d = StateSpace(sys.A, sys.B, sys.C, sys.D, 0.2) T.siso_ss3d = StateSpace(sys.A, sys.B, sys.C, sys.D, True) # Two input, two output continuous time system A = [[-3., 4., 2.], [-1., -3., 0.], [2., 5., 3.]] B = [[1., 4.], [-3., -3.], [-2., 1.]] C = [[4., 2., -3.], [1., 4., 3.]] D = [[-2., 4.], [0., 1.]] T.mimo_ss1 = StateSpace(A, B, C, D, None) T.mimo_ss1c = StateSpace(A, B, C, D, 0) # Two input, two output discrete time system T.mimo_ss1d = StateSpace(A, B, C, D, 0.1) # Same system, but with a different sampling time T.mimo_ss2d = StateSpace(A, B, C, D, 0.2) # Single input, single output continuus and discrete transfer function T.siso_tf1 = TransferFunction([1, 1], [1, 2, 1], None) T.siso_tf1c = TransferFunction([1, 1], [1, 2, 1], 0) T.siso_tf1d = TransferFunction([1, 1], [1, 2, 1], 0.1) T.siso_tf2d = TransferFunction([1, 1], [1, 2, 1], 0.2) T.siso_tf3d = TransferFunction([1, 1], [1, 2, 1], True) return T
def test_multiply_mimo(self): """Multiply two MIMO systems.""" num1 = [[[1., 2.], [0., 3.], [2., -1.]], [[1.], [4., 0.], [1., -4., 3.]]] den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], [[3., 0., .0], [2., -1., -1.], [1.]]] num2 = [[[0., 1., 2.]], [[1., -5.]], [[-2., 1., 4.]]] den2 = [[[1., 0., 0., 0.]], [[-2., 1., 3.]], [[4., -1., -1., 0.]]] num3 = [[[-24., 52., -14., 245., -490., -115., 467., -95., -56., 12., 0., 0., 0.]], [[24., -132., 138., 345., -768., -106., 510., 41., -79., -69., -23., 17., 6., 0.]]] den3 = [[[48., -92., -84., 183., 44., -97., -2., 12., 0., 0., 0., 0., 0., 0.]], [[-48., 60., 84., -81., -45., 21., 9., 0., 0., 0., 0., 0., 0.]]] sys1 = TransferFunction(num1, den1) sys2 = TransferFunction(num2, den2) sys3 = sys1 * sys2 for i in range(sys3.noutputs): for j in range(sys3.ninputs): np.testing.assert_allclose(sys3.num[i][j], num3[i][j]) np.testing.assert_allclose(sys3.den[i][j], den3[i][j])
def test_divide_scalar(self): """Divide two direct feedthrough systems.""" sys1 = TransferFunction(np.array([3.]), -4.) sys2 = TransferFunction(5., 2.) sys3 = sys1 / sys2 np.testing.assert_allclose(sys3.num, [[[6.]]]) np.testing.assert_allclose(sys3.den, [[[-20.]]])
def test_subtract_scalar(self): """Subtract two direct feedthrough systems.""" sys1 = TransferFunction(1., [[[1.]]]) sys2 = TransferFunction(np.array([2.]), [1.]) sys3 = sys1 - sys2 np.testing.assert_allclose(sys3.num, -1.) np.testing.assert_allclose(sys3.den, 1.)
def test_timebase_conversions(self, tsys): '''Check to make sure timebases transfer properly''' tf1 = TransferFunction([1, 1], [1, 2, 3], None) # unspecified tf2 = TransferFunction([1, 1], [1, 2, 3], 0) # cont time tf3 = TransferFunction([1, 1], [1, 2, 3], True) # dtime, unspec tf4 = TransferFunction([1, 1], [1, 2, 3], .1) # dtime, dt=.1 # Make sure unspecified timebase is converted correctly assert timebase(tf1*tf1) == timebase(tf1) assert timebase(tf1*tf2) == timebase(tf2) assert timebase(tf1*tf3) == timebase(tf3) assert timebase(tf1*tf4) == timebase(tf4) assert timebase(tf3*tf4) == timebase(tf4) assert timebase(tf2*tf1) == timebase(tf2) assert timebase(tf3*tf1) == timebase(tf3) assert timebase(tf4*tf1) == timebase(tf4) assert timebase(tf1+tf1) == timebase(tf1) assert timebase(tf1+tf2) == timebase(tf2) assert timebase(tf1+tf3) == timebase(tf3) assert timebase(tf1+tf4) == timebase(tf4) assert timebase(feedback(tf1, tf1)) == timebase(tf1) assert timebase(feedback(tf1, tf2)) == timebase(tf2) assert timebase(feedback(tf1, tf3)) == timebase(tf3) assert timebase(feedback(tf1, tf4)) == timebase(tf4) # Make sure discrete time without sampling is converted correctly assert timebase(tf3*tf3) == timebase(tf3) assert timebase(tf3*tf4) == timebase(tf4) assert timebase(tf3+tf3) == timebase(tf3) assert timebase(tf3+tf4) == timebase(tf4) assert timebase(feedback(tf3, tf3)) == timebase(tf3) assert timebase(feedback(tf3, tf4)) == timebase(tf4) # Make sure all other combinations are errors with pytest.raises(ValueError, match="incompatible timebases"): tf2 * tf3 with pytest.raises(ValueError, match="incompatible timebases"): tf3 * tf2 with pytest.raises(ValueError, match="incompatible timebases"): tf2 * tf4 with pytest.raises(ValueError, match="incompatible timebases"): tf4 * tf2 with pytest.raises(ValueError, match="incompatible timebases"): tf2 + tf3 with pytest.raises(ValueError, match="incompatible timebases"): tf3 + tf2 with pytest.raises(ValueError, match="incompatible timebases"): tf2 + tf4 with pytest.raises(ValueError, match="incompatible timebases"): tf4 + tf2 with pytest.raises(ValueError, match="incompatible timebases"): feedback(tf2, tf3) with pytest.raises(ValueError, match="incompatible timebases"): feedback(tf3, tf2) with pytest.raises(ValueError, match="incompatible timebases"): feedback(tf2, tf4) with pytest.raises(ValueError, match="incompatible timebases"): feedback(tf4, tf2)
def test_add_siso(self): """Add two SISO systems.""" sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) sys3 = sys1 + sys2 # If sys3.num is [[[0., 20., 4., -8.]]], then this is wrong! np.testing.assert_allclose(sys3.num, [[[20., 4., -8]]]) np.testing.assert_allclose(sys3.den, [[[1., 6., 1., -7., -2., 1.]]])
def test_minreal_4(self): """Check minreal on discrete TFs.""" T = 0.01 z = TransferFunction([1, 0], [1], T) h = (z - 1.00000000001) * (z + 1.0000000001) / (z**2 - 1) hm = h.minreal() hr = TransferFunction([1], [1], T) np.testing.assert_allclose(hm.num[0][0], hr.num[0][0]) np.testing.assert_allclose(hr.dt, hm.dt)
def test_constructor_inconsistent_dimension(self): """Give constructor numerators, denominators of different sizes.""" with pytest.raises(ValueError): TransferFunction([[[1.]]], [[[1.], [2., 3.]]]) with pytest.raises(ValueError): TransferFunction([[[1.]]], [[[1.]], [[2., 3.]]]) with pytest.raises(ValueError): TransferFunction([[[1.]]], [[[1.], [1., 2.]], [[5., 2.], [2., 3.]]])
def test_subtract_siso(self): """Subtract two SISO systems.""" sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) sys3 = sys1 - sys2 sys4 = sys2 - sys1 np.testing.assert_allclose(sys3.num, [[[2., 6., -12., -10., -2.]]]) np.testing.assert_allclose(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) np.testing.assert_allclose(sys4.num, [[[-2., -6., 12., 10., 2.]]]) np.testing.assert_allclose(sys4.den, [[[1., 6., 1., -7., -2., 1.]]])
def test_multiply_siso(self): """Multiply two SISO systems.""" sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) sys3 = sys1 * sys2 sys4 = sys2 * sys1 np.testing.assert_allclose(sys3.num, [[[-1., 0., 4., 15.]]]) np.testing.assert_allclose(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) np.testing.assert_allclose(sys3.num, sys4.num) np.testing.assert_allclose(sys3.den, sys4.den)
def test_multiply_scalar(self): """Multiply two direct feedthrough systems.""" sys1 = TransferFunction(2., [1.]) sys2 = TransferFunction(1., 4.) sys3 = sys1 * sys2 sys4 = sys1 * sys2 np.testing.assert_allclose(sys3.num, [[[2.]]]) np.testing.assert_allclose(sys3.den, [[[4.]]]) np.testing.assert_allclose(sys3.num, sys4.num) np.testing.assert_allclose(sys3.den, sys4.den)
def test_divide_siso(self): """Divide two SISO systems.""" sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) sys3 = sys1 / sys2 sys4 = sys2 / sys1 np.testing.assert_allclose(sys3.num, [[[1., 3., 4., -3., -5.]]]) np.testing.assert_allclose(sys3.den, [[[-1., -3., 16., 7., -3.]]]) np.testing.assert_allclose(sys4.num, sys3.den) np.testing.assert_allclose(sys4.den, sys3.num)
def calc_psi_and_phi_lists(s1, TF): zeros_a = TF.zero() #this returns an array zeros = zeros_a.tolist() zeros.reverse() #arrays don't have the reverse method that lists do poles_a = TF.pole() poles = poles_a.tolist() poles.reverse() psi_list = calc_angle_list(s1, zeros) phi_list = calc_angle_list(s1, poles) return psi_list, phi_list
def calc_psi_and_phi_lists(s1, TF): zeros_a = TF.zero()#this returns an array zeros = zeros_a.tolist() zeros.reverse()#arrays don't have the reverse method that lists do poles_a = TF.pole() poles = poles_a.tolist() poles.reverse() psi_list = calc_angle_list(s1, zeros) phi_list = calc_angle_list(s1, poles) return psi_list, phi_list
def test_feedback_siso(self): """Test for correct SISO transfer function feedback.""" sys1 = TransferFunction([-1., 4.], [1., 3., 5.]) sys2 = TransferFunction([2., 3., 0.], [1., -3., 4., 0]) sys3 = sys1.feedback(sys2) sys4 = sys1.feedback(sys2, 1) np.testing.assert_allclose(sys3.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_allclose(sys3.den, [[[1., 0., -2., 2., 32., 0.]]]) np.testing.assert_allclose(sys4.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_allclose(sys4.den, [[[1., 0., 2., -8., 8., 0.]]])
def test_constructor_nodt(self): """Test the constructor when an object without dt is passed""" sysin = TransferFunction([[[0., 1.], [2., 3.]]], [[[5., 2.], [3., 0.]]]) del sysin.dt # this doesn't make sense and now breaks sys = TransferFunction(sysin) assert sys.dt == defaults['control.default_dt'] # test for static gain sysin = TransferFunction([[[2.], [3.]]], [[[1.], [.1]]]) del sysin.dt # this doesn't make sense and now breaks sys = TransferFunction(sysin) assert sys.dt is None
def test__isstatic(self): numstatic = 1.1 denstatic = 1.2 numdynamic = [1, 1] dendynamic = [2, 1] numstaticmimo = [[[ 1.1, ], [ 1.2, ]], [[ 1.2, ], [ 0.8, ]]] denstaticmimo = [[[ 1.9, ], [ 1.2, ]], [[ 1.2, ], [ 0.8, ]]] numdynamicmimo = [[[1.1, 0.9], [1.2]], [[1.2], [0.8]]] dendynamicmimo = [[[1.1, 0.7], [0.2]], [[1.2], [0.8]]] assert TransferFunction(numstatic, denstatic)._isstatic() assert TransferFunction(numstaticmimo, denstaticmimo)._isstatic() assert not TransferFunction(numstatic, dendynamic)._isstatic() assert not TransferFunction(numdynamic, dendynamic)._isstatic() assert not TransferFunction(numdynamic, denstatic)._isstatic() assert not TransferFunction(numstatic, dendynamic)._isstatic() assert not TransferFunction(numstaticmimo, dendynamicmimo)._isstatic() assert not TransferFunction(numdynamicmimo, denstaticmimo)._isstatic()
def test_step_robustness(self): "Test robustness os step_response against denomiantors: gh-240" # Create 2 input, 2 output system num = [[[0], [1]], [[1], [0]]] den1 = [[[1], [1,1]], [[1, 4], [1]]] sys1 = TransferFunction(num, den1) den2 = [[[1], [1e-10, 1, 1]], [[1, 4], [1]]] # slight perturbation sys2 = TransferFunction(num, den2) t1, y1 = step_response(sys1, input=0, T=2, T_num=100) t2, y2 = step_response(sys2, input=0, T=2, T_num=100) np.testing.assert_array_almost_equal(y1, y2)
def test_repr(self, Hargs, ref): """Test __repr__ printout.""" H = TransferFunction(*Hargs) assert repr(H) == ref # and reading back array = np.array # noqa H2 = eval(H.__repr__()) for p in range(len(H.num)): for m in range(len(H.num[0])): np.testing.assert_array_almost_equal(H.num[p][m], H2.num[p][m]) np.testing.assert_array_almost_equal(H.den[p][m], H2.den[p][m]) assert H.dt == H2.dt
def test_common_den(self): """ Test the helper function to compute common denomitators.""" # _common_den() computes the common denominator per input/column. # The testing columns are: # 0: no common poles # 1: regular common poles # 2: poles with multiplicity, # 3: complex poles # 4: complex poles below threshold eps = np.finfo(float).eps tol_imag = np.sqrt(eps * 5 * 2 * 2) * 0.9 numin = [[[1.], [1.], [1.], [1.], [1.]], [[1.], [1.], [1.], [1.], [1.]]] denin = [ [ [1., 3., 2.], # 0: poles: [-1, -2] [1., 6., 11., 6.], # 1: poles: [-1, -2, -3] [1., 6., 11., 6.], # 2: poles: [-1, -2, -3] [1., 6., 11., 6.], # 3: poles: [-1, -2, -3] [1., 6., 11., 6.] ], # 4: poles: [-1, -2, -3], [ [1., 12., 47., 60.], # 0: poles: [-3, -4, -5] [1., 9., 26., 24.], # 1: poles: [-2, -3, -4] [1., 7., 16., 12.], # 2: poles: [-2, -2, -3] [1., 7., 17., 15.], # 3: poles: [-2+1J, -2-1J, -3], np.poly([-2 + tol_imag * 1J, -2 - tol_imag * 1J, -3]) ] ] numref = np.array([[[0., 0., 1., 12., 47., 60.], [0., 0., 0., 1., 4., 0.], [0., 0., 0., 1., 2., 0.], [0., 0., 0., 1., 4., 5.], [0., 0., 0., 1., 2., 0.]], [[0., 0., 0., 1., 3., 2.], [0., 0., 0., 1., 1., 0.], [0., 0., 0., 1., 1., 0.], [0., 0., 0., 1., 3., 2.], [0., 0., 0., 1., 1., 0.]]]) denref = np.array([[1., 15., 85., 225., 274., 120.], [1., 10., 35., 50., 24., 0.], [1., 8., 23., 28., 12., 0.], [1., 10., 40., 80., 79., 30.], [1., 8., 23., 28., 12., 0.]]) sys = TransferFunction(numin, denin) num, den, denorder = sys._common_den() np.testing.assert_array_almost_equal(num[:2, :, :], numref) np.testing.assert_array_almost_equal(num[2:, :, :], np.zeros( (3, 5, 6))) np.testing.assert_array_almost_equal(den, denref)
def testCopyConstructor(self, tsys): for sys in (tsys.siso_ss1, tsys.siso_ss1c, tsys.siso_ss1d): newsys = StateSpace(sys) assert sys.dt == newsys.dt for sys in (tsys.siso_tf1, tsys.siso_tf1c, tsys.siso_tf1d): newsys = TransferFunction(sys) assert sys.dt == newsys.dt
def test_call_siso(self, dt, omega, resp): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) if dt: sys = sample_system(sys, dt) s = np.exp(omega * 1j * dt) else: s = omega * 1j # Correct versions of the call np.testing.assert_allclose(evalfr(sys, s), resp, atol=1e-3) np.testing.assert_allclose(sys(s), resp, atol=1e-3) # Deprecated version of the call (should generate exception) with pytest.raises(AttributeError): np.testing.assert_allclose(sys.evalfr(omega), resp, atol=1e-3)
def test_frequency_response_siso(self): """Evaluate the magnitude and phase of a SISO system at multiple frequencies.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) truemag = [[[4.63507337473906, 0.707106781186548, 0.0866592803995351]]] truephase = [[[-2.89596891081488, -2.35619449019234, -1.32655885133871]]] trueomega = [0.1, 1., 10.] mag, phase, omega = sys.frequency_response(trueomega, squeeze=False) np.testing.assert_array_almost_equal(mag, truemag) np.testing.assert_array_almost_equal(phase, truephase) np.testing.assert_array_almost_equal(omega, trueomega)
def test_step_info(self): # From matlab docs: sys = TransferFunction([1, 5, 5], [1, 1.65, 5, 6.5, 2]) Strue = { 'RiseTime': 3.8456, 'SettlingTime': 27.9762, 'SettlingMin': 2.0689, 'SettlingMax': 2.6873, 'Overshoot': 7.4915, 'Undershoot': 0, 'Peak': 2.6873, 'PeakTime': 8.0530, 'SteadyStateValue': 2.50 } S = step_info(sys) Sk = sorted(S.keys()) Sktrue = sorted(Strue.keys()) assert Sk == Sktrue # Very arbitrary tolerance because I don't know if the # response from the MATLAB is really that accurate. # maybe it is a good idea to change the Strue to match # but I didn't do it because I don't know if it is # accurate either... rtol = 2e-2 np.testing.assert_allclose([S[k] for k in Sk], [Strue[k] for k in Sktrue], rtol=rtol)
def testCopyConstructor(self): for sys in (self.siso_ss1, self.siso_ss1c, self.siso_ss1d): newsys = StateSpace(sys) self.assertEqual(sys.dt, newsys.dt) for sys in (self.siso_tf1, self.siso_tf1c, self.siso_tf1d): newsys = TransferFunction(sys) self.assertEqual(sys.dt, newsys.dt)