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)