diff --git a/control/tests/convert_test.py b/control/tests/convert_test.py index b395996e0..e95e03bcf 100644 --- a/control/tests/convert_test.py +++ b/control/tests/convert_test.py @@ -206,6 +206,29 @@ def testTf2ssStaticMimo(self): d = np.matrix([[0.5, 30, 0.0625], [-0.5, -1.25, 101.3]]) np.testing.assert_array_equal(d, gmimo.D) + def testSs2tfStaticSiso(self): + """Regression: ss2tf for SISO static gain""" + import control + gsiso = control.ss2tf(control.ss([], [], [], 0.5)) + np.testing.assert_array_equal([[[0.5]]], gsiso.num) + np.testing.assert_array_equal([[[1.]]], gsiso.den) + + def testSs2tfStaticMimo(self): + """Regression: ss2tf for MIMO static gain""" + import control + # 2x3 TFM + a = [] + b = [] + c = [] + d = np.matrix([[0.5, 30, 0.0625], [-0.5, -1.25, 101.3]]) + gtf = control.ss2tf(control.ss(a,b,c,d)) + + # we need a 3x2x1 array to compare with gtf.num + # np.testing.assert_array_equal doesn't seem to like a matrices + # with an extra dimension, so convert to ndarray + numref = np.asarray(d)[...,np.newaxis] + np.testing.assert_array_equal(numref, np.array(gtf.num) / np.array(gtf.den)) + def suite(): return unittest.TestLoader().loadTestsFromTestCase(TestConvert) diff --git a/control/xferfcn.py b/control/xferfcn.py index 1559fa047..be21f8509 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -1098,40 +1098,48 @@ def _convertToTransferFunction(sys, **kw): return sys elif isinstance(sys, StateSpace): - try: - from slycot import tb04ad - if len(kw): - raise TypeError( - "If sys is a StateSpace, " + - "_convertToTransferFunction cannot take keywords.") - - # Use Slycot to make the transformation - # Make sure to convert system matrices to numpy arrays - tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), - array(sys.B), array(sys.C), array(sys.D), tol1=0.0) - - # Preallocate outputs. - num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] - den = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] - - for i in range(sys.outputs): - for j in range(sys.inputs): - num[i][j] = list(tfout[6][i, j, :]) - # Each transfer function matrix row - # has a common denominator. - den[i][j] = list(tfout[5][i, :]) - # print(num) - # print(den) - except ImportError: - # If slycot is not available, use signal.lti (SISO only) - if (sys.inputs != 1 or sys.outputs != 1): - raise TypeError("No support for MIMO without slycot") - - lti_sys = lti(sys.A, sys.B, sys.C, sys.D) - num = squeeze(lti_sys.num) - den = squeeze(lti_sys.den) - # print(num) - # print(den) + + if 0==sys.states: + # Slycot doesn't like static SS->TF conversion, so handle + # it first. Can't join this with the no-Slycot branch, + # since that doesn't handle general MIMO systems + num = [[[sys.D[i,j]] for j in range(sys.inputs)] for i in range(sys.outputs)] + den = [[[1.] for j in range(sys.inputs)] for i in range(sys.outputs)] + else: + try: + from slycot import tb04ad + if len(kw): + raise TypeError( + "If sys is a StateSpace, " + + "_convertToTransferFunction cannot take keywords.") + + # Use Slycot to make the transformation + # Make sure to convert system matrices to numpy arrays + tfout = tb04ad(sys.states, sys.inputs, sys.outputs, array(sys.A), + array(sys.B), array(sys.C), array(sys.D), tol1=0.0) + + # Preallocate outputs. + num = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] + den = [[[] for j in range(sys.inputs)] for i in range(sys.outputs)] + + for i in range(sys.outputs): + for j in range(sys.inputs): + num[i][j] = list(tfout[6][i, j, :]) + # Each transfer function matrix row + # has a common denominator. + den[i][j] = list(tfout[5][i, :]) + # print(num) + # print(den) + except ImportError: + # If slycot is not available, use signal.lti (SISO only) + if (sys.inputs != 1 or sys.outputs != 1): + raise TypeError("No support for MIMO without slycot") + + lti_sys = lti(sys.A, sys.B, sys.C, sys.D) + num = squeeze(lti_sys.num) + den = squeeze(lti_sys.den) + # print(num) + # print(den) return TransferFunction(num, den, sys.dt)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: