From: <kk...@us...> - 2011-02-08 22:15:13
|
Revision: 66 http://python-control.svn.sourceforge.net/python-control/?rev=66&view=rev Author: kkchen Date: 2011-02-08 22:15:06 +0000 (Tue, 08 Feb 2011) Log Message: ----------- Old TransferFunction class removed from xferfcn.py. The "developer version" xTransferFunction is now renamed TransferFunction. Related fixes in bdalg.py, TestXferFcn.py, and TestBDAlg.py. Kevin K. Chen <kk...@pr...> Modified Paths: -------------- branches/control-0.4a/src/TestBDAlg.py branches/control-0.4a/src/TestXferFcn.py branches/control-0.4a/src/bdalg.py branches/control-0.4a/src/xferfcn.py Modified: branches/control-0.4a/src/TestBDAlg.py =================================================================== --- branches/control-0.4a/src/TestBDAlg.py 2011-02-08 22:15:01 UTC (rev 65) +++ branches/control-0.4a/src/TestBDAlg.py 2011-02-08 22:15:06 UTC (rev 66) @@ -1,7 +1,7 @@ #!/usr/bin/env python import numpy as np -from xferfcn import xTransferFunction +from xferfcn import TransferFunction from statesp import StateSpace from bdalg import feedback import unittest @@ -15,7 +15,7 @@ """This contains some random LTI systems and scalars for testing.""" # Two random SISO systems. - self.sys1 = xTransferFunction([1, 2], [1, 2, 3]) + self.sys1 = TransferFunction([1, 2], [1, 2, 3]) self.sys2 = StateSpace([[1., 4.], [3., 2.]], [[1.], [-4.]], [[1., 0.]], [[0.]]) # Two random scalars. Modified: branches/control-0.4a/src/TestXferFcn.py =================================================================== --- branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:15:01 UTC (rev 65) +++ branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:15:06 UTC (rev 66) @@ -1,7 +1,7 @@ #!/usr/bin/env python import numpy as np -from xferfcn import xTransferFunction +from xferfcn import TransferFunction import unittest class TestXferFcn(unittest.TestCase): @@ -15,42 +15,42 @@ def testBadInputType(self): """Give the constructor invalid input types.""" - self.assertRaises(TypeError, xTransferFunction, [[0., 1.], [2., 3.]], + self.assertRaises(TypeError, TransferFunction, [[0., 1.], [2., 3.]], [[5., 2.], [3., 0.]]) def testInconsistentDimension(self): """Give the constructor a numerator and denominator of different sizes.""" - self.assertRaises(ValueError, xTransferFunction, [[[1.]]], + self.assertRaises(ValueError, TransferFunction, [[[1.]]], [[[1.], [2., 3.]]]) - self.assertRaises(ValueError, xTransferFunction, [[[1.]]], + self.assertRaises(ValueError, TransferFunction, [[[1.]]], [[[1.]], [[2., 3.]]]) - self.assertRaises(ValueError, xTransferFunction, [[[1.]]], + self.assertRaises(ValueError, TransferFunction, [[[1.]]], [[[1.], [1., 2.]], [[5., 2.], [2., 3.]]]) def testInconsistentColumns(self): """Give the constructor inputs that do not have the same number of columns in each row.""" - self.assertRaises(ValueError, xTransferFunction, 1., + self.assertRaises(ValueError, TransferFunction, 1., [[[1.]], [[2.], [3.]]]) - self.assertRaises(ValueError, xTransferFunction, [[[1.]], [[2.], [3.]]], + self.assertRaises(ValueError, TransferFunction, [[[1.]], [[2.], [3.]]], 1.) def testZeroDenominator(self): """Give the constructor a transfer function with a zero denominator.""" - self.assertRaises(ValueError, xTransferFunction, 1., 0.) - self.assertRaises(ValueError, xTransferFunction, + self.assertRaises(ValueError, TransferFunction, 1., 0.) + self.assertRaises(ValueError, TransferFunction, [[[1.], [2., 3.]], [[-1., 4.], [3., 2.]]], [[[1., 0.], [0.]], [[0., 0.], [2.]]]) def testAddInconsistentDimension(self): """Add two transfer function matrices of different sizes.""" - sys1 = xTransferFunction([[[1., 2.]]], [[[4., 5.]]]) - sys2 = xTransferFunction([[[4., 3.]], [[1., 2.]]], + sys1 = TransferFunction([[[1., 2.]]], [[[4., 5.]]]) + sys2 = TransferFunction([[[4., 3.]], [[1., 2.]]], [[[1., 6.]], [[2., 4.]]]) self.assertRaises(ValueError, sys1.__add__, sys2) self.assertRaises(ValueError, sys1.__sub__, sys2) @@ -60,21 +60,21 @@ def testMulInconsistentDimension(self): """Multiply two transfer function matrices of incompatible sizes.""" - sys1 = xTransferFunction([[[1., 2.], [4., 5.]], [[2., 5.], [4., 3.]]], + sys1 = TransferFunction([[[1., 2.], [4., 5.]], [[2., 5.], [4., 3.]]], [[[6., 2.], [4., 1.]], [[6., 7.], [2., 4.]]]) - sys2 = xTransferFunction([[[1.]], [[2.]], [[3.]]], + 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) - # Tests for xTransferFunction._truncatecoeff + # Tests for TransferFunction._truncatecoeff def testTruncateCoeff1(self): """Remove extraneous zeros in polynomial representations.""" - sys1 = xTransferFunction([0., 0., 1., 2.], [[[0., 0., 0., 3., 2., 1.]]]) + sys1 = TransferFunction([0., 0., 1., 2.], [[[0., 0., 0., 3., 2., 1.]]]) np.testing.assert_array_equal(sys1.num, [[[1., 2.]]]) np.testing.assert_array_equal(sys1.den, [[[3., 2., 1.]]]) @@ -82,17 +82,17 @@ def testTruncateCoeff2(self): """Remove extraneous zeros in polynomial representations.""" - sys1 = xTransferFunction([0., 0., 0.], 1.) + sys1 = TransferFunction([0., 0., 0.], 1.) np.testing.assert_array_equal(sys1.num, [[[0.]]]) np.testing.assert_array_equal(sys1.den, [[[1.]]]) - # Tests for xTransferFunction.__neg__ + # Tests for TransferFunction.__neg__ def testNegScalar(self): """Negate a direct feedthrough system.""" - sys1 = xTransferFunction(2., np.array([-3])) + sys1 = TransferFunction(2., np.array([-3])) sys2 = - sys1 np.testing.assert_array_equal(sys2.num, [[[-2.]]]) @@ -101,7 +101,7 @@ def testNegSISO(self): """Negate a SISO system.""" - sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1.]) + sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1.]) sys2 = - sys1 np.testing.assert_array_equal(sys2.num, [[[-1., -3., -5.]]]) @@ -117,22 +117,22 @@ den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], [[3., 0., .0], [2., -1., -1.], [1.]]] - sys1 = xTransferFunction(num1, den1) + sys1 = TransferFunction(num1, den1) sys2 = - sys1 - sys3 = xTransferFunction(num3, den1) + sys3 = TransferFunction(num3, den1) for i in range(sys3.outputs): for j in range(sys3.inputs): np.testing.assert_array_equal(sys2.num[i][j], sys3.num[i][j]) np.testing.assert_array_equal(sys2.den[i][j], sys3.den[i][j]) - # Tests for xTransferFunction.__add__ + # Tests for TransferFunction.__add__ def testAddScalar(self): """Add two direct feedthrough systems.""" - sys1 = xTransferFunction(1., [[[1.]]]) - sys2 = xTransferFunction(np.array([2.]), [1.]) + sys1 = TransferFunction(1., [[[1.]]]) + sys2 = TransferFunction(np.array([2.]), [1.]) sys3 = sys1 + sys2 np.testing.assert_array_equal(sys3.num, 3.) @@ -141,8 +141,8 @@ def testAddSISO(self): """Add two SISO systems.""" - sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = xTransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) + 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! @@ -165,8 +165,8 @@ den3 = [[[3., -2., -4.], [1., 2., 3., 0., 0.], [-2., -1., 1.]], [[-12., -9., 6., 0., 0.], [2., -1., -1.], [1., 0.]]] - sys1 = xTransferFunction(num1, den1) - sys2 = xTransferFunction(num2, den2) + sys1 = TransferFunction(num1, den1) + sys2 = TransferFunction(num2, den2) sys3 = sys1 + sys2 for i in range(sys3.outputs): @@ -174,13 +174,13 @@ np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - # Tests for xTransferFunction.__sub__ + # Tests for TransferFunction.__sub__ def testSubScalar(self): """Add two direct feedthrough systems.""" - sys1 = xTransferFunction(1., [[[1.]]]) - sys2 = xTransferFunction(np.array([2.]), [1.]) + sys1 = TransferFunction(1., [[[1.]]]) + sys2 = TransferFunction(np.array([2.]), [1.]) sys3 = sys1 - sys2 np.testing.assert_array_equal(sys3.num, -1.) @@ -189,8 +189,8 @@ def testSubSISO(self): """Add two SISO systems.""" - sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = xTransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) + sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys2 = TransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) sys3 = sys1 - sys2 sys4 = sys2 - sys1 @@ -215,8 +215,8 @@ den3 = [[[3., -2., -4], [1., 2., 3., 0., 0.], [1]], [[-12., -9., 6., 0., 0.], [2., -1., -1], [1., 0.]]] - sys1 = xTransferFunction(num1, den1) - sys2 = xTransferFunction(num2, den2) + sys1 = TransferFunction(num1, den1) + sys2 = TransferFunction(num2, den2) sys3 = sys1 - sys2 for i in range(sys3.outputs): @@ -224,13 +224,13 @@ np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - # Tests for xTransferFunction.__mul__ + # Tests for TransferFunction.__mul__ def testMulScalar(self): """Multiply two direct feedthrough systems.""" - sys1 = xTransferFunction(2., [1.]) - sys2 = xTransferFunction(1., 4.) + sys1 = TransferFunction(2., [1.]) + sys2 = TransferFunction(1., 4.) sys3 = sys1 * sys2 sys4 = sys1 * sys2 @@ -242,8 +242,8 @@ def testMulSISO(self): """Multiply two SISO systems.""" - sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = xTransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) + sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) sys3 = sys1 * sys2 sys4 = sys2 * sys1 @@ -273,8 +273,8 @@ 0., 0.]], [[-48., 60., 84., -81., -45., 21., 9., 0., 0., 0., 0., 0., 0.]]] - sys1 = xTransferFunction(num1, den1) - sys2 = xTransferFunction(num2, den2) + sys1 = TransferFunction(num1, den1) + sys2 = TransferFunction(num2, den2) sys3 = sys1 * sys2 for i in range(sys3.outputs): @@ -282,13 +282,13 @@ np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - # Tests for xTransferFunction.__div__ + # Tests for TransferFunction.__div__ def testDivScalar(self): """Divide two direct feedthrough systems.""" - sys1 = xTransferFunction(np.array([3.]), -4.) - sys2 = xTransferFunction(5., 2.) + sys1 = TransferFunction(np.array([3.]), -4.) + sys2 = TransferFunction(5., 2.) sys3 = sys1 / sys2 np.testing.assert_array_equal(sys3.num, [[[6.]]]) @@ -297,8 +297,8 @@ def testDivSISO(self): """Divide two SISO systems.""" - sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = xTransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) + sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) sys3 = sys1 / sys2 sys4 = sys2 / sys1 @@ -307,12 +307,12 @@ np.testing.assert_array_equal(sys4.num, sys3.den) np.testing.assert_array_equal(sys4.den, sys3.num) - # Tests for xTransferFunction.evalfr. + # Tests for TransferFunction.evalfr. def testEvalFrSISO(self): """Evaluate the frequency response of a SISO system at one frequency.""" - sys = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) np.testing.assert_array_almost_equal(sys.evalfr(1.), np.array([[-0.5 - 0.5j]])) @@ -326,20 +326,20 @@ [[1.], [4., 0.], [1., -4., 3.]]] den = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], [[3., 0., .0], [2., -1., -1.], [1.]]] - sys = xTransferFunction(num, den) + 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) - # Tests for xTransferFunction.freqresp. + # Tests for TransferFunction.freqresp. def testFreqRespSISO(self): """Evaluate the magnitude and phase of a SISO system at multiple frequencies.""" - sys = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) truemag = [[[4.63507337473906, 0.707106781186548, 0.0866592803995351]]] truephase = [[[-2.89596891081488, -2.35619449019234, @@ -360,7 +360,7 @@ [[1.], [4., 0.], [1., -4., 3.]]] den = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], [[3., 0., .0], [2., -1., -1.], [1.]]] - sys = xTransferFunction(num, den) + sys = TransferFunction(num, den) trueomega = [0.1, 1., 10.] truemag = [[[0.496287094505259, 0.307147558416976, 0.0334738176210382], @@ -380,12 +380,12 @@ np.testing.assert_array_almost_equal(phase, truephase) np.testing.assert_array_equal(omega, trueomega) - # Tests for xTransferFunction.feedback. + # Tests for TransferFunction.feedback. def testFeedbackSISO(self): - sys1 = xTransferFunction([-1., 4.], [1., 3., 5.]) - sys2 = xTransferFunction([2., 3., 0.], [1., -3., 4., 0]) + 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) Modified: branches/control-0.4a/src/bdalg.py =================================================================== --- branches/control-0.4a/src/bdalg.py 2011-02-08 22:15:01 UTC (rev 65) +++ branches/control-0.4a/src/bdalg.py 2011-02-08 22:15:06 UTC (rev 66) @@ -47,6 +47,21 @@ import xferfcn as tf import statesp as ss +def series(sys1, sys2): + """Return the series connection sys1 * sys2 for --> sys2 --> sys1 -->.""" + + return sys1 * sys2 + +def parallel(sys1, sys2): + """Return the parallel connection sys1 + sys2.""" + + return sys1 + sys2 + +def negate(sys): + """Return the negative of a system.""" + + return -sys; + def feedback(sys1, sys2, sign=-1): """Feedback interconnection between two I/O systems. @@ -79,11 +94,11 @@ xferfcn.feedback.""" # Check for correct input types. - if not isinstance(sys1, (int, long, float, complex, tf.xTransferFunction, + if not isinstance(sys1, (int, long, float, complex, tf.TransferFunction, ss.StateSpace)): raise TypeError("sys1 must be a TransferFunction or StateSpace object, \ or a scalar.") - if not isinstance(sys2, (int, long, float, complex, tf.xTransferFunction, + if not isinstance(sys2, (int, long, float, complex, tf.TransferFunction, ss.StateSpace)): raise TypeError("sys2 must be a TransferFunction or StateSpace object, \ or a scalar.") @@ -91,7 +106,7 @@ # If sys1 is a scalar, convert it to the appropriate LTI type so that we can # its feedback member function. if isinstance(sys1, (int, long, float, complex)): - if isinstance(sys2, tf.xTransferFunction): + if isinstance(sys2, tf.TransferFunction): sys1 = tf.convertToTransferFunction(sys1) elif isinstance(sys2, ss.StateSpace): sys1 = ss.convertToStateSpace(sys1) Modified: branches/control-0.4a/src/xferfcn.py =================================================================== --- branches/control-0.4a/src/xferfcn.py 2011-02-08 22:15:01 UTC (rev 65) +++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:15:06 UTC (rev 66) @@ -54,7 +54,7 @@ import statesp from lti2 import Lti2 -class xTransferFunction(Lti2): +class TransferFunction(Lti2): """The TransferFunction class is derived from the Lti2 parent class. The main data members are 'num' and 'den', which are 2-D lists of arrays containing MIMO numerator and denominator coefficients. For example, @@ -210,13 +210,13 @@ for j in range(self.inputs): num[i][j] *= -1 - return xTransferFunction(num, self.den) + return TransferFunction(num, self.den) def __add__(self, other): """Add two transfer functions (parallel connection).""" # Convert the second argument to a transfer function. - if not isinstance(other, xTransferFunction): + if not isinstance(other, TransferFunction): other = convertToTransferFunction(other, self.inputs, self.outputs) # Check that the input-output sizes are consistent. @@ -236,7 +236,7 @@ num[i][j], den[i][j] = _addSISO(self.num[i][j], self.den[i][j], other.num[i][j], other.den[i][j]) - return xTransferFunction(num, den) + return TransferFunction(num, den) def __radd__(self, other): """Add two transfer functions (parallel connection).""" @@ -257,7 +257,7 @@ """Multiply two transfer functions (serial connection).""" # Convert the second argument to a transfer function. - if not isinstance(other, xTransferFunction): + if not isinstance(other, TransferFunction): other = convertToTransferFunction(other, self.inputs, self.inputs) # Check that the input-output sizes are consistent. @@ -285,7 +285,7 @@ num[i][j], den[i][j] = _addSISO(num[i][j], den[i][j], num_summand[k], den_summand[k]) - return xTransferFunction(num, den) + return TransferFunction(num, den) def __rmul__(self, other): """Multiply two transfer functions (serial connection).""" @@ -298,17 +298,17 @@ if self.inputs > 1 or self.outputs > 1 or \ other.inputs > 1 or other.outputs > 1: - raise NotImplementedError("xTransferFunction.__div__ is currently \ + raise NotImplementedError("TransferFunction.__div__ is currently \ implemented only for SISO systems.") # Convert the second argument to a transfer function. - if not isinstance(other, xTransferFunction): + if not isinstance(other, TransferFunction): other = convertToTransferFunction(other, 1, 1) num = sp.polymul(self.num[0][0], other.den[0][0]) den = sp.polymul(self.den[0][0], other.num[0][0]) - return xTransferFunction(num, den) + return TransferFunction(num, den) # TODO: Division of MIMO transfer function objects is quite difficult. def __rdiv__(self, other): @@ -316,7 +316,7 @@ if self.inputs > 1 or self.outputs > 1 or \ other.inputs > 1 or other.outputs > 1: - raise NotImplementedError("xTransferFunction.__rdiv__ is currently \ + raise NotImplementedError("TransferFunction.__rdiv__ is currently \ implemented only for SISO systems.") return other / self @@ -371,7 +371,7 @@ if self.inputs > 1 or self.outputs > 1 or \ other.inputs > 1 or other.outputs > 1: - raise NotImplementedError("xTransferFunction.feedback is currently \ + raise NotImplementedError("TransferFunction.feedback is currently \ only implemented for SISO functions.") num1 = self.num[0][0] @@ -382,185 +382,13 @@ num = sp.polymul(num1, den2) den = sp.polyadd(sp.polymul(den2, den1), -sign * sp.polymul(num2, num1)) - return xTransferFunction(num, den) + return TransferFunction(num, den) # For MIMO or SISO systems, the analytic expression is # self / (1 - sign * other * self) # But this does not work correctly because the state size will be too # large. -# This is the old TransferFunction class. It will be superceded by the -# xTransferFunction class (which will be renamed TransferFunction) when it is -# completed. -class TransferFunction(signal.lti): - """The TransferFunction class is used to represent linear - input/output systems via its transfer function. - """ - # Constructor - def __init__(self, *args, **keywords): - # First initialize the parent object - signal.lti.__init__(self, *args, **keywords) - - # Make sure that this is only a SISO function - if (self.inputs != 1 or self.outputs != 1): - raise NotImplementedError("MIMO transfer functions not supported") - - # Now add a few more attributes - self.variable = 's' - - # Style to use for printing (similar to MATLAB) - def __str__(self): - labstr = "" - outstr = "" - for i in range(self.inputs): - for j in range(self.outputs): - # Create a label for the transfer function and extract - # numerator polynomial (depends on number of inputs/outputs) - if (self.inputs > 1 and self.outputs > 1): - labstr = "H[] = "; lablen = 7; - numstr = _tfpolyToString(self.num[i,j], self.variable); - elif (self.inputs > 1): - labstr = "H[] = "; lablen = 7; - numstr = _tfpolyToString(self.num[i], self.variable); - elif (self.outputs > 1): - labstr = "H[] = "; lablen = 7; - numstr = _tfpolyToString(self.num[j], self.variable); - else: - labstr = ""; lablen = 0; - numstr = _tfpolyToString(self.num, self.variable); - - # Convert the (common) denominator polynomials to strings - denstr = _tfpolyToString(self.den, self.variable); - - # Figure out the length of the separating line - dashcount = max(len(numstr), len(denstr)) - dashes = labstr + '-' * dashcount - - # Center the numerator or denominator - if (len(numstr) < dashcount): - numstr = ' ' * \ - int(round((dashcount - len(numstr))/2) + lablen) + \ - numstr - if (len(denstr) < dashcount): - denstr = ' ' * \ - int(round((dashcount - len(denstr))/2) + lablen) + \ - denstr - - outstr += "\n" + numstr + "\n" + dashes + "\n" + denstr + "\n" - return outstr - - # Negation of a transfer function - def __neg__(self): - """Negate a transfer function""" - return TransferFunction(-self.num, self.den) - - # Subtraction (use addition) - def __sub__(self, other): - """Subtract two transfer functions""" - return self + (-other) - - def __rsub__(self, other): - """Subtract two transfer functions""" - return other + (-self) - - # Addition of two transfer functions (parallel interconnection) - def __add__(self, sys): - """Add two transfer functions (parallel connection)""" - # Convert the second argument to a transfer function - other = convertToTransferFunction(sys) - - # Compute the numerator and denominator of the sum - den = sp.polymul(self.den, other.den) - num = sp.polyadd(sp.polymul(self.num, other.den), \ - sp.polymul(other.num, self.den)) - - return TransferFunction(num, den) - - # Reverse addition - just switch the order - def __radd__(self, other): - """Add two transfer functions (parallel connection)""" - return self + other; - - # Multiplication of two transfer functions (series interconnection) - def __mul__(self, sys): - """Multiply two transfer functions (serial connection)""" - # Make sure we have a transfer function (or convert to one) - other = convertToTransferFunction(sys) - - # Compute the product of the transfer functions - num = sp.polymul(self.num, other.num) - den = sp.polymul(self.den, other.den) - return TransferFunction(num, den) - - # Reverse multiplication - switch order (works for SISO) - def __rmul__(self, other): - """Multiply two transfer functions (serial connection)""" - return self * other - - # Division between transfer functions - def __div__(self, sys): - """Divide two transfer functions""" - other = convertToTransferFunction(sys); - return TransferFunction(sp.polymul(self.num, other.den), - sp.polymul(self.den, other.num)); - - # Reverse division - def __rdiv__(self, sys): - """Divide two transfer functions""" - other = convertToTransferFunction(sys); - return TransferFunction(sp.polymul(other.num, self.den), - sp.polymul(other.den, self.num)); - - # Method for evaluating a transfer function at one frequency - def evalfr(self, freq): - """Evaluate a transfer function at a single frequency""" - return sp.polyval(self.num, freq*1j) / sp.polyval(self.den, freq*1j) - - # Method for generating the frequency response of the system - def freqresp(self, omega): - """Evaluate a transfer function at a list of frequencies""" - # Convert numerator and denomintator to 1D polynomials - num = sp.poly1d(self.num) - den = sp.poly1d(self.den) - - # Generate the frequency response at each frequency - fresp = map(lambda w: num(w*1j) / den(w*1j), omega) - - mag = sp.sqrt(sp.multiply(fresp, sp.conjugate(fresp))); - phase = sp.angle(fresp) - - return mag, phase, omega - - # Compute poles and zeros - def poles(self): return sp.roots(self.den) - def zeros(self): return sp.roots(self.num) - - # Feedback around a transfer function - def feedback(sys1, sys2, sign=-1): - """Feedback interconnection between two transfer functions""" - # Get the numerator and denominator of the first system - if (isinstance(sys1, (int, long, float, complex))): - num1 = sys1; den1 = 1; - elif (isinstance(sys1, TransferFunction)): - num1 = sys1.num; den1 = sys1.den; - else: - raise TypeError - - # Get the numerator and denominator of the second system - if (isinstance(sys2, (int, long, float, complex))): - num2 = sys2; den2 = 1; - elif (isinstance(sys2, TransferFunction)): - num2 = sys2.num; den2 = sys2.den; - else: - raise TypeError - - # Compute sys1/(1 - sign*sys1*sys2) - num = sp.polymul(num1, den2); - den = sp.polysub(sp.polymul(den1, den2), sign * sp.polymul(num1, num2)) - - # Return the result as a transfer function - return TransferFunction(num, den) - # Utility function to convert a transfer function polynomial to a string # Borrowed from poly1d library def _tfpolyToString(coeffs, var='s'): @@ -622,7 +450,7 @@ def convertToTransferFunction(sys, inputs=1, outputs=1): """Convert a system to transfer function form (if needed.)""" - if isinstance(sys, xTransferFunction): + if isinstance(sys, TransferFunction): return sys elif isinstance(sys, statesp.StateSpace): raise NotImplementedError("State space to transfer function conversion \ @@ -634,6 +462,6 @@ for i in range(min(inputs, outputs)): num[i][i] = [sys] - return xTransferFunction(num, den) + return TransferFunction(num, den) else: - raise TypeError("Can't convert given type to xTransferFunction system.") + raise TypeError("Can't convert given type to TransferFunction system.") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |