def test_evalfr_siso(self): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) np.testing.assert_array_almost_equal(evalfr(sys, 1j), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal(evalfr(sys, 32j), np.array([[0.00281959302585077 - 0.030628473607392j]])) # Test call version as well np.testing.assert_almost_equal(sys(1.j), -0.5 - 0.5j) np.testing.assert_almost_equal(sys(32.j), 0.00281959302585077 - 0.030628473607392j) # Test internal version (with real argument) np.testing.assert_array_almost_equal(sys._evalfr(1.), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal(sys._evalfr(32.), np.array([[0.00281959302585077 - 0.030628473607392j]])) # Deprecated version of the call (should generate warning) import warnings with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") sys.evalfr(1.) assert len(w) == 1 assert issubclass(w[-1].category, PendingDeprecationWarning)
def test_mag_phase_omega(): """Test for bug reported in gh-58""" sys = TransferFunction(15, [1, 6, 11, 6]) out = stability_margins(sys) omega = np.logspace(-2, 2, 1000) mag, phase, omega = sys.freqresp(omega) out2 = stability_margins((mag, phase * 180 / np.pi, omega)) ind = [0, 1, 3, 4] # indices of gm, pm, wg, wp -- ignore sm marg1 = np.array(out)[ind] marg2 = np.array(out2)[ind] assert_allclose(marg1, marg2, atol=1.5e-3)
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_array_equal(sys3.num, [[[1., 3., 4., -3., -5.]]]) np.testing.assert_array_equal(sys3.den, [[[-1., -3., 16., 7., -3.]]]) np.testing.assert_array_equal(sys4.num, sys3.den) np.testing.assert_array_equal(sys4.den, sys3.num)
def testEvalFrSISO(self): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1.0, 3.0, 5], [1.0, 6.0, 2.0, -1]) np.testing.assert_array_almost_equal(sys.evalfr(1.0), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal(sys.evalfr(32.0), np.array([[0.00281959302585077 - 0.030628473607392j]])) # Test call version as well np.testing.assert_almost_equal(sys(1.0j), -0.5 - 0.5j) np.testing.assert_almost_equal(sys(32.0j), 0.00281959302585077 - 0.030628473607392j)
def test_dcgain(self): sys = TransferFunction(6, 3) np.testing.assert_equal(sys.dcgain(), 2) sys2 = TransferFunction(6, [1, 3]) np.testing.assert_equal(sys2.dcgain(), 2) sys3 = TransferFunction(6, [1, 0]) np.testing.assert_equal(sys3.dcgain(), np.inf) num = [[[15], [21], [33]], [[10], [14], [22]]] den = [[[1, 3], [2, 3], [3, 3]], [[1, 5], [2, 7], [3, 11]]] sys4 = TransferFunction(num, den) expected = [[5, 7, 11], [2, 2, 2]] np.testing.assert_array_equal(sys4.dcgain(), expected)
def testFeedback(self): h1 = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 10) f1 = FRD(h1, omega) np.testing.assert_array_almost_equal( f1.feedback(1).freqresp([0.1, 1.0, 10])[0], h1.feedback(1).freqresp([0.1, 1.0, 10])[0])
def testFreqRespMIMO(self): """Evaluate the magnitude and phase of a MIMO system at multiple frequencies.""" num = [[[1.0, 2.0], [0.0, 3.0], [2.0, -1.0]], [[1.0], [4.0, 0.0], [1.0, -4.0, 3.0]]] den = [[[-3.0, 2.0, 4.0], [1.0, 0.0, 0.0], [2.0, -1.0]], [[3.0, 0.0, 0.0], [2.0, -1.0, -1.0], [1.0]]] sys = TransferFunction(num, den) trueomega = [0.1, 1.0, 10.0] truemag = [ [[0.496287094505259, 0.307147558416976, 0.0334738176210382], [300.0, 3.0, 0.03], [1.0, 1.0, 1.0]], [ [33.3333333333333, 0.333333333333333, 0.00333333333333333], [0.390285696125482, 1.26491106406735, 0.198759144198533], [3.01663720059274, 4.47213595499958, 104.92378186093], ], ] truephase = [ [[3.7128711165168e-4, 0.185347949995695, 1.30770596539255], [-np.pi, -np.pi, -np.pi], [0.0, 0.0, 0.0]], [ [-np.pi, -np.pi, -np.pi], [-1.66852323415362, -1.89254688119154, -1.62050658356412], [-0.132989648369409, -1.1071487177940, -2.7504672066207], ], ] mag, phase, omega = sys.freqresp(trueomega) np.testing.assert_array_almost_equal(mag, truemag) np.testing.assert_array_almost_equal(phase, truephase) np.testing.assert_array_equal(omega, trueomega)
def test_freqresp_mimo(self): """Evaluate the magnitude and phase of a MIMO system 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.freqresp(true_omega) np.testing.assert_array_almost_equal(mag, true_mag) np.testing.assert_array_almost_equal(phase, true_phase) np.testing.assert_array_equal(omega, true_omega)
def testPoleMIMO(self): """Test for correct MIMO poles.""" sys = TransferFunction([[[1.], [1.]], [[1.], [1.]]], [[[1., 2.], [1., 3.]], [[1., 4., 4.], [1., 9., 14.]]]) p = sys.pole() np.testing.assert_array_almost_equal(p, [-7., -3., -2., -2.])
def testEvalFrSISO(self): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) np.testing.assert_array_almost_equal(sys.evalfr(1.), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal(sys.evalfr(32.), np.array([[0.00281959302585077 - 0.030628473607392j]]))
def testPoleMIMO(self): """Test for correct MIMO poles.""" sys = TransferFunction( [[[1.0], [1.0]], [[1.0], [1.0]]], [[[1.0, 2.0], [1.0, 3.0]], [[1.0, 4.0, 4.0], [1.0, 9.0, 14.0]]] ) p = sys.pole() np.testing.assert_array_almost_equal(p, [-7.0, -3.0, -2.0, -2.0])
def testSISOtf(self): # get a SISO transfer function h = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 10) frd = FRD(h, omega) assert isinstance(frd, FRD) np.testing.assert_array_almost_equal( frd.freqresp([1.0]), h.freqresp([1.0]))
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_array_equal(sys3.num, [[[-1., 0., 4., 15.]]]) np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) np.testing.assert_array_equal(sys3.num, sys4.num) np.testing.assert_array_equal(sys3.den, sys4.den)
def testMulInconsistentDimension(self): """Multiply two transfer function matrices of incompatible sizes.""" sys1 = TransferFunction([[[1., 2.], [4., 5.]], [[2., 5.], [4., 3.]]], [[[6., 2.], [4., 1.]], [[6., 7.], [2., 4.]]]) sys2 = TransferFunction([[[1.]], [[2.]], [[3.]]], [[[4.]], [[5.]], [[6.]]]) self.assertRaises(ValueError, sys1.__mul__, sys2) self.assertRaises(ValueError, sys2.__mul__, sys1) self.assertRaises(ValueError, sys1.__rmul__, sys2) self.assertRaises(ValueError, sys2.__rmul__, sys1)
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_array_equal(sys3.num, [[[2.]]]) np.testing.assert_array_equal(sys3.den, [[[4.]]]) np.testing.assert_array_equal(sys3.num, sys4.num) np.testing.assert_array_equal(sys3.den, sys4.den)
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_array_equal(sys3.num, [[[2., 6., -12., -10., -2.]]]) np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) np.testing.assert_array_equal(sys4.num, [[[-2., -6., 12., 10., 2.]]]) np.testing.assert_array_equal(sys4.den, [[[1., 6., 1., -7., -2., 1.]]])
def test_mag_phase_omega(self): # test for bug reported in gh-58 sys = TransferFunction(15, [1, 6, 11, 6]) out = stability_margins(sys) omega = np.logspace(-1,1,100) mag, phase, omega = sys.freqresp(omega) out2 = stability_margins((mag, phase*180/np.pi, omega)) ind = [0,1,3,4] # indices of gm, pm, wg, wp -- ignore sm marg1 = np.array(out)[ind] marg2 = np.array(out2)[ind] np.testing.assert_array_almost_equal(marg1, marg2, 4)
def testFeedback(self): h1 = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 10) f1 = FRD(h1, omega) np.testing.assert_array_almost_equal( f1.feedback(1).frequency_response([0.1, 1.0, 10])[0], h1.feedback(1).frequency_response([0.1, 1.0, 10])[0]) # Make sure default argument also works np.testing.assert_array_almost_equal( f1.feedback().frequency_response([0.1, 1.0, 10])[0], h1.feedback().frequency_response([0.1, 1.0, 10])[0])
def test_mag_phase_omega(self): # test for bug reported in gh-58 sys = TransferFunction(15, [1, 6, 11, 6]) out = stability_margins(sys) omega = np.logspace(-2, 2, 1000) mag, phase, omega = sys.freqresp(omega) #print( mag, phase, omega) out2 = stability_margins((mag, phase * 180 / np.pi, omega)) ind = [0, 1, 3, 4] # indices of gm, pm, wg, wp -- ignore sm marg1 = np.array(out)[ind] marg2 = np.array(out2)[ind] assert_array_almost_equal(marg1, marg2, 4)
def testSISOtf(self): # get a SISO transfer function h = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 10) frd = FRD(h, omega) assert isinstance(frd, FRD) mag1, phase1, omega1 = frd.frequency_response([1.0]) mag2, phase2, omega2 = h.frequency_response([1.0]) np.testing.assert_array_almost_equal(mag1, mag2) np.testing.assert_array_almost_equal(phase1, phase2) np.testing.assert_array_almost_equal(omega1, omega2)
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_array_equal(sys3.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_array_equal(sys3.den, [[[1., 0., -2., 2., 32., 0.]]]) np.testing.assert_array_equal(sys4.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_array_equal(sys4.den, [[[1., 0., 2., -8., 8., 0.]]])
def testFeedbackSISO(self): """Test for correct SISO transfer function feedback.""" sys1 = TransferFunction([-1.0, 4.0], [1.0, 3.0, 5.0]) sys2 = TransferFunction([2.0, 3.0, 0.0], [1.0, -3.0, 4.0, 0]) sys3 = sys1.feedback(sys2) sys4 = sys1.feedback(sys2, 1) np.testing.assert_array_equal(sys3.num, [[[-1.0, 7.0, -16.0, 16.0, 0.0]]]) np.testing.assert_array_equal(sys3.den, [[[1.0, 0.0, -2.0, 2.0, 32.0, 0.0]]]) np.testing.assert_array_equal(sys4.num, [[[-1.0, 7.0, -16.0, 16.0, 0.0]]]) np.testing.assert_array_equal(sys4.den, [[[1.0, 0.0, 2.0, -8.0, 8.0, 0.0]]])
def testEvalFrMIMO(self): """Evaluate the frequency response of a MIMO system at one frequency.""" 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) resp = [[0.147058823529412 + 0.0882352941176471j, -0.75, 1.], [-0.083333333333333, -0.188235294117647 - 0.847058823529412j, -1. - 8.j]] np.testing.assert_array_almost_equal(sys.evalfr(2.), resp)
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 sys = TransferFunction(sysin) assert sys.dt == defaults['control.default_dt'] # test for static gain sysin = TransferFunction([[[2.], [3.]]], [[[1.], [.1]]]) del sysin.dt sys = TransferFunction(sysin) assert sys.dt is None
def testFeedbackSISO(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_array_equal(sys3.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_array_equal(sys3.den, [[[1., 0., -2., 2., 32., 0.]]]) np.testing.assert_array_equal(sys4.num, [[[-1., 7., -16., 16., 0.]]]) np.testing.assert_array_equal(sys4.den, [[[1., 0., 2., -8., 8., 0.]]])
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_freqresp_siso(self): """Evaluate the SISO magnitude and phase 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.freqresp(trueomega) 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 testEvalFrSISO(self): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) np.testing.assert_array_almost_equal(sys.evalfr(1.), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal(sys.evalfr(32.), np.array([[0.00281959302585077 - 0.030628473607392j]])) # Test call version as well np.testing.assert_almost_equal(sys(1.j), -0.5 - 0.5j) np.testing.assert_almost_equal(sys(32.j), 0.00281959302585077 - 0.030628473607392j)
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 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 plant(self, request): plants = { 'syscont': TransferFunction(1, [1, 3, 0]), 'sysdisc1': c2d(TransferFunction(1, [1, 3, 0]), .1), 'syscont221': StateSpace([[-.3, 0], [1, 0]], [[ -1, ], [ .1, ]], [0, -.3], 0) } return plants[request.param]
def test_step_robustness(self): "Unit test: https://github.com/python-control/python-control/issues/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) # Compute step response from input 1 to output 1, 2 t1, y1 = step_response(sys1, input=0) t2, y2 = step_response(sys2, input=0) np.testing.assert_array_almost_equal(y1, y2)
def testFreqRespSISO(self): """Evaluate the magnitude and phase of a SISO system at multiple frequencies.""" sys = TransferFunction([1.0, 3.0, 5], [1.0, 6.0, 2.0, -1]) truemag = [[[4.63507337473906, 0.707106781186548, 0.0866592803995351]]] truephase = [[[-2.89596891081488, -2.35619449019234, -1.32655885133871]]] trueomega = [0.1, 1.0, 10.0] mag, phase, omega = sys.freqresp(trueomega) 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 testEvalFrMIMO(self): """Evaluate the frequency response of a MIMO system at one frequency.""" num = [[[1.0, 2.0], [0.0, 3.0], [2.0, -1.0]], [[1.0], [4.0, 0.0], [1.0, -4.0, 3.0]]] den = [[[-3.0, 2.0, 4.0], [1.0, 0.0, 0.0], [2.0, -1.0]], [[3.0, 0.0, 0.0], [2.0, -1.0, -1.0], [1.0]]] sys = TransferFunction(num, den) resp = [ [0.147058823529412 + 0.0882352941176471j, -0.75, 1.0], [-0.083333333333333, -0.188235294117647 - 0.847058823529412j, -1.0 - 8.0j], ] np.testing.assert_array_almost_equal(sys.evalfr(2.0), resp) # Test call version as well np.testing.assert_array_almost_equal(sys(2.0j), resp)
def test_evalfr_mimo(self): """Evaluate the frequency response of a MIMO system at a freq""" 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) resp = [[0.147058823529412 + 0.0882352941176471j, -0.75, 1.], [-0.083333333333333, -0.188235294117647 - 0.847058823529412j, -1. - 8.j]] np.testing.assert_array_almost_equal(sys._evalfr(2.), resp) # Test call version as well np.testing.assert_array_almost_equal(sys(2.j), resp)
def testTruncateCoeff2(self): """Remove extraneous zeros in polynomial representations.""" sys1 = TransferFunction([0., 0., 0.], 1.) np.testing.assert_array_equal(sys1.num, [[[0.]]]) np.testing.assert_array_equal(sys1.den, [[[1.]]])
def test_slice(self): sys = TransferFunction( [[[1], [2], [3]], [[3], [4], [5]]], [[[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]]]) sys1 = sys[1:, 1:] self.assertEqual((sys1.inputs, sys1.outputs), (2, 1)) sys2 = sys[:2, :2] self.assertEqual((sys2.inputs, sys2.outputs), (2, 2)) sys = TransferFunction( [[[1], [2], [3]], [[3], [4], [5]]], [[[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]]], 0.5) sys1 = sys[1:, 1:] self.assertEqual((sys1.inputs, sys1.outputs), (2, 1)) self.assertEqual(sys1.dt, 0.5)
def test_frd(self): f = np.array([ 0.005, 0.010, 0.020, 0.030, 0.040, 0.050, 0.060, 0.070, 0.080, 0.090, 0.100, 0.200, 0.300, 0.400, 0.500, 0.750, 1.000, 1.250, 1.500, 1.750, 2.000, 2.250, 2.500, 2.750, 3.000, 3.250, 3.500, 3.750, 4.000, 4.250, 4.500, 4.750, 5.000, 6.000, 7.000, 8.000, 9.000, 10.000 ]) gain = np.array([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.2, 0.3, 0.5, 0.5, -0.4, -2.3, -4.8, -7.3, -9.6, -11.7, -13.6, -15.3, -16.9, -18.3, -19.6, -20.8, -22.0, -23.1, -24.1, -25.0, -25.9, -29.1, -31.9, -34.2, -36.2, -38.1 ]) phase = np.array([ 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -19, -29, -40, -51, -81, -114, -144, -168, -187, -202, -214, -224, -233, -240, -247, -253, -259, -264, -269, -273, -277, -280, -292, -301, -307, -313, -317 ]) # calculate response as complex number resp = 10**(gain / 20) * np.exp(1j * phase / (180. / np.pi)) # frequency response data fresp = FRD(resp, f * 2 * np.pi, smooth=True) s = TransferFunction([1, 0], [1]) G = 1. / (s**2) K = 1. C = K * (1 + 1.9 * s) TFopen = fresp * C * G gm, pm, sm, wg, wp, ws = stability_margins(TFopen) assert_array_almost_equal([pm], [44.55], 2)
def test_root_locus_zoom(self): """Check the zooming functionality of the Root locus plot""" system = TransferFunction([1000], [1, 25, 100, 0]) plt.figure() root_locus(system) fig = plt.gcf() ax_rlocus = fig.axes[0] event = type( 'test', (object, ), { 'xdata': 14.7607954359, 'ydata': -35.6171379864, 'inaxes': ax_rlocus.axes })() ax_rlocus.set_xlim((-10.813628105112421, 14.760795435937652)) ax_rlocus.set_ylim((-35.61713798641108, 33.879716621220311)) plt.get_current_fig_manager().toolbar.mode = 'zoom rect' _RLClickDispatcher(event, system, fig, ax_rlocus, '-') zoom_x = ax_rlocus.lines[-2].get_data()[0][0:5] zoom_y = ax_rlocus.lines[-2].get_data()[1][0:5] zoom_y = [abs(y) for y in zoom_y] zoom_x_valid = [ -5., -4.61281263, -4.16689986, -4.04122642, -3.90736502 ] zoom_y_valid = [0., 0., 0., 0., 0.] assert_array_almost_equal(zoom_x, zoom_x_valid) assert_array_almost_equal(zoom_y, zoom_y_valid)
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_slice(self): sys = TransferFunction( [ [ [1], [2], [3]], [ [3], [4], [5]] ], [ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ]) sys1 = sys[1:, 1:] assert (sys1.ninputs, sys1.noutputs) == (2, 1) sys2 = sys[:2, :2] assert (sys2.ninputs, sys2.noutputs) == (2, 2) sys = TransferFunction( [ [ [1], [2], [3]], [ [3], [4], [5]] ], [ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ], 0.5) sys1 = sys[1:, 1:] assert (sys1.ninputs, sys1.noutputs) == (2, 1) assert sys1.dt == 0.5
def test_reverse_sign_siso(self): """Negate a SISO system.""" sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1.]) sys2 = - sys1 np.testing.assert_array_equal(sys2.num, [[[-1., -3., -5.]]]) np.testing.assert_array_equal(sys2.den, [[[1., 6., 2., -1.]]])
def test_reverse_sign_scalar(self): """Negate a direct feedthrough system.""" sys1 = TransferFunction(2., np.array([-3.])) sys2 = - sys1 np.testing.assert_array_equal(sys2.num, [[[-2.]]]) np.testing.assert_array_equal(sys2.den, [[[-3.]]])
def test_truncate_coefficients_null_numerator(self): """Remove extraneous zeros in polynomial representations.""" sys1 = TransferFunction([0., 0., 0.], 1.) np.testing.assert_array_equal(sys1.num, [[[0.]]]) np.testing.assert_array_equal(sys1.den, [[[1.]]])
def test_phase_crossover_frequencies(self): omega, gain = phase_crossover_frequencies(self.sys2) np.testing.assert_array_almost_equal(omega, [1.73205, 0.]) np.testing.assert_array_almost_equal(gain, [-0.5, 0.25]) tf = TransferFunction([1], [1, 1]) omega, gain = phase_crossover_frequencies(tf) np.testing.assert_array_almost_equal(omega, [0.]) np.testing.assert_array_almost_equal(gain, [1.]) # testing MIMO, only (0,0) element is considered tf = TransferFunction([[[1], [2]], [[3], [4]]], [[[1, 2, 3, 4], [1, 1]], [[1, 1], [1, 1]]]) omega, gain = phase_crossover_frequencies(tf) np.testing.assert_array_almost_equal(omega, [1.73205081, 0.]) np.testing.assert_array_almost_equal(gain, [-0.5, 0.25])
def test_constructor_double_dt(self): """Test that providing dt as arg and kwarg prefers arg with warning""" with pytest.warns(UserWarning, match="received multiple dt.*" "using positional arg"): sys = TransferFunction(1, [1, 2, 3], 0.1, dt=0.2) assert sys.dt == 0.1
def test_evalfr_siso(self): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) np.testing.assert_array_almost_equal(evalfr(sys, 1j), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal( evalfr(sys, 32j), np.array([[0.00281959302585077 - 0.030628473607392j]])) # Test call version as well np.testing.assert_almost_equal(sys(1.j), -0.5 - 0.5j) np.testing.assert_almost_equal( sys(32.j), 0.00281959302585077 - 0.030628473607392j) # Test internal version (with real argument) np.testing.assert_array_almost_equal( sys._evalfr(1.), np.array([[-0.5 - 0.5j]])) np.testing.assert_array_almost_equal( sys._evalfr(32.), np.array([[0.00281959302585077 - 0.030628473607392j]]))
def test_dcgain_discr(self): """Test DC gain for discrete-time transfer functions""" # static gain sys = TransferFunction(6, 3, True) np.testing.assert_equal(sys.dcgain(), 2) # averaging filter sys = TransferFunction(0.5, [1, -0.5], True) np.testing.assert_almost_equal(sys.dcgain(), 1) # differencer sys = TransferFunction(1, [1, -1], True) np.testing.assert_equal(sys.dcgain(), np.inf) # summer # causes a RuntimeWarning due to the divide by zero sys = TransferFunction([1,-1], [1], True) np.testing.assert_equal(sys.dcgain(), 0)
def test_div(self): # Make sure that sampling times work correctly sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], True) sys3 = sys1 / sys2 self.assertEqual(sys3.dt, True) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], 0.5) sys3 = sys1 / sys2 self.assertEqual(sys3.dt, 0.5) sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1], 0.1) self.assertRaises(ValueError, TransferFunction.__truediv__, sys1, sys2) sys1 = sample_system(rss(4, 1, 1), 0.5) sys3 = TransferFunction.__rtruediv__(sys2, sys1) self.assertEqual(sys3.dt, 0.5)
def test_double_cancelling_poles_siso(self): H = TransferFunction([1, 1], [1, 2, 1]) p = H.pole() np.testing.assert_array_almost_equal(p, [-1, -1])