From: <kk...@us...> - 2011-02-08 22:14:33
|
Revision: 58 http://python-control.svn.sourceforge.net/python-control/?rev=58&view=rev Author: kkchen Date: 2011-02-08 22:14:27 +0000 (Tue, 08 Feb 2011) Log Message: ----------- Bug fix in xTransferFunction._truncatecoeff; miscellaneous other fixes in xferfcn.py. Also added tests for exceptions in TestXferFcn.py. Kevin K. Chen <kk...@pr...> Modified Paths: -------------- branches/control-0.4a/src/TestXferFcn.py branches/control-0.4a/src/xferfcn.py Modified: branches/control-0.4a/src/TestXferFcn.py =================================================================== --- branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:14:22 UTC (rev 57) +++ branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:14:27 UTC (rev 58) @@ -9,14 +9,85 @@ function class. Throughout these tests, we will give different input formats to the xTranferFunction constructor, to try to break it.""" - def testTruncateCoeff(self): + # Tests for raising exceptions. + + def testBadInputType(self): + """Give the constructor invalid input types.""" + + self.assertRaises(ValueError, xTransferFunction, [[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.]]], + [[[1.], [2., 3.]]]) + self.assertRaises(ValueError, xTransferFunction, [[[1.]]], + [[[1.]], [[2., 3.]]]) + self.assertRaises(ValueError, xTransferFunction, [[[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., + [[[1.]], [[2.], [3.]]]) + self.assertRaises(ValueError, xTransferFunction, [[[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, + [[[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.]]], + [[[1., 6.]], [[2., 4.]]]) + self.assertRaises(ValueError, sys1.__add__, sys2) + self.assertRaises(ValueError, sys1.__sub__, sys2) + self.assertRaises(ValueError, sys1.__radd__, sys2) + self.assertRaises(ValueError, sys1.__rsub__, sys2) + + def testMulInconsistentDimension(self): + """Multiply two transfer function matrices of incompatible sizes.""" + + sys1 = xTransferFunction([[[1., 2.], [4., 5.]], [[2., 5.], [4., 3.]]], + [[[6., 2.], [4., 1.]], [[6., 7.], [2., 4.]]]) + sys2 = xTransferFunction([[[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 + + def testTruncateCoeff1(self): """Remove extraneous zeros in polynomial representations.""" sys1 = xTransferFunction([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.]]]) + + def testTruncateCoeff2(self): + """Remove extraneous zeros in polynomial representations.""" + + sys1 = xTransferFunction([0., 0., 0.], 1.) + + np.testing.assert_array_equal(sys1.num, [[[0.]]]) + np.testing.assert_array_equal(sys1.den, [[[1.]]]) + # Tests for xTransferFunction.__neg__ + def testNegScalar(self): """Negate a direct feedthrough system.""" @@ -53,7 +124,9 @@ 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__ + def testAddScalar(self): """Add two direct feedthrough systems.""" @@ -100,6 +173,8 @@ 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__ + def testSubScalar(self): """Add two direct feedthrough systems.""" @@ -134,20 +209,22 @@ [[1., 2.], [-1., -2.], [4.]]] den2 = [[[-1.], [1., 2., 3.], [-1., -1.]], [[-4., -3., 2.], [0., 1.], [1., 0.]]] - num3 = [[[3., -3., -6], [5., 6., 9.], [-4., -2., 2]], - [[3., 2., -3., 2], [-2., -3., 7., 2.], [1., -4., 3., 4]]] - den3 = [[[3., -2., -4.], [1., 2., 3., 0., 0.], [-2., -1., 1.]], - [[-12., -9., 6., 0., 0.], [2., -1., -1.], [1., 0.]]] + num3 = [[[-3., 1., 2.], [1., 6., 9.], [0.]], + [[-3., -10., -3., 2], [2., 3., 1., -2], [1., -4., 3., -4]]] + 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) - sys3 = sys1 + sys2 + sys3 = sys1 - sys2 for i in range(sys3.outputs): for j in range(sys3.inputs): 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__ + def testMulScalar(self): """Multiply two direct feedthrough systems.""" @@ -204,6 +281,8 @@ 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__ + def testDivScalar(self): """Divide two direct feedthrough systems.""" Modified: branches/control-0.4a/src/xferfcn.py =================================================================== --- branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:22 UTC (rev 57) +++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:27 UTC (rev 58) @@ -172,18 +172,24 @@ """Remove extraneous zero coefficients from polynomials in numerator and denominator matrices.""" - # Beware: this is a shallow copy. + # Beware: this is a shallow copy. This should be okay. data = [self.num, self.den] for p in range(len(data)): for i in range(self.outputs): for j in range(self.inputs): # Find the first nontrivial coefficient. - k = 0 - while not data[p][i][j][k]: - k += 1 - - # Now truncate the trivial coefficients. - data[p][i][j] = data[p][i][j][k:] + nonzero = None + for k in range(data[p][i][j].size): + if data[p][i][j][k]: + nonzero = k + break + + if nonzero is None: + # The array is all zeros. + data[p][i][j] = sp.zeros(1) + else: + # Truncate the trivial coefficients. + data[p][i][j] = data[p][i][j][nonzero:] [self.num, self.den] = data def __neg__(self): @@ -205,11 +211,11 @@ # Check that the input-output sizes are consistent. if self.inputs != other.inputs: - raise ValueError("The first summand has %i input(s), but the second \ -has %i." % (self.inputs, other.inputs)) + raise ValueError("The first summand has %i input(s), but the \ +second has %i." % (self.inputs, other.inputs)) if self.outputs != other.outputs: - raise ValueError("The first summand has %i output(s), but the second \ -has %i." % (self.outputs, other.outputs)) + raise ValueError("The first summand has %i output(s), but the \ +second has %i." % (self.outputs, other.outputs)) # Preallocate the numerator and denominator of the sum. num = [[[] for j in range(self.inputs)] for i in range(self.outputs)] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |