From: <kk...@us...> - 2011-02-08 22:14:14
|
Revision: 54 http://python-control.svn.sourceforge.net/python-control/?rev=54&view=rev Author: kkchen Date: 2011-02-08 22:14:08 +0000 (Tue, 08 Feb 2011) Log Message: ----------- Worked on xTransferFunction.__add__ and __mul__ in xferfcn.py. Also added tests in TestXferFcn.py. Minor edit in statesp.py. Kevin K. Chen <kk...@pr...> Modified Paths: -------------- branches/control-0.4a/src/statesp.py branches/control-0.4a/src/xferfcn.py Added Paths: ----------- branches/control-0.4a/src/TestXferFcn.py Added: branches/control-0.4a/src/TestXferFcn.py =================================================================== --- branches/control-0.4a/src/TestXferFcn.py (rev 0) +++ branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:14:08 UTC (rev 54) @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +import numpy as np +from xferfcn import xTransferFunction +import unittest + +class TestXferFcn(unittest.TestCase): + """These are tests for functionality and correct reporting of the transfer + function class.""" + + def testTruncateCoeff(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 testAddSISO1(self): + """Add two direct feedthrough systems.""" + + # Try different input formats, too. + sys1 = xTransferFunction(1., [[[1.]]]) + sys2 = xTransferFunction([2.], [1.]) + sys3 = sys1 + sys2 + + np.testing.assert_array_equal(sys3.num, 3.) + np.testing.assert_array_equal(sys3.den, 1.) + + def testAddSISO2(self): + """Add two SISO systems.""" + + # Try different input formats, too. + sys1 = xTransferFunction([1., 3., 5], [1., 6., 2., -1]) + sys2 = xTransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) + sys3 = sys1 + sys2 + + # If sys3.num is [[[0., 20., 4., -8.]]], then this is wrong! + np.testing.assert_array_equal(sys3.num, [[[20., 4., -8]]]) + np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) + + def testAddMIMO(self): + """Add two MIMO systems.""" + + num1 = [[[1., 2.], [0., 3.], [2., -1.]], + [[1.], [4., 0.], [1., -4., 3.]]] + den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], + [[3., 0., .0], [2., -1., -1.], [1.]]] + num2 = [[[0., 0., -1], [2.], [-1., -1.]], + [[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.]]] + + sys1 = xTransferFunction(num1, den1) + sys2 = xTransferFunction(num2, den2) + + 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]) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file Property changes on: branches/control-0.4a/src/TestXferFcn.py ___________________________________________________________________ Added: svn:executable + * Modified: branches/control-0.4a/src/statesp.py =================================================================== --- branches/control-0.4a/src/statesp.py 2011-02-08 22:14:03 UTC (rev 53) +++ branches/control-0.4a/src/statesp.py 2011-02-08 22:14:08 UTC (rev 54) @@ -195,7 +195,7 @@ # Check to make sure the dimensions are OK if (self.outputs != other.inputs): raise ValueError, "Number of first's outputs must match number \ - of second's inputs." +of second's inputs." # Concatenate the various arrays A = concatenate(( @@ -236,7 +236,7 @@ # Check to make sure the dimensions are OK if ((self.inputs != other.outputs) or (self.outputs != other.inputs)): raise ValueError, "State space systems don't have compatible \ - inputs/outputs for feedback." +inputs/outputs for feedback." # note that if there is an algebraic loop then this matrix inversion # won't work Modified: branches/control-0.4a/src/xferfcn.py =================================================================== --- branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:03 UTC (rev 53) +++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:08 UTC (rev 54) @@ -111,11 +111,32 @@ self.den = den Lti2.__init__(self, inputs, outputs) + self.truncatecoeff() + def __str__(self): """String representation of the transfer function.""" pass + def truncatecoeff(self): + """Remove extraneous zero coefficients from polynomials in numerator and + denominator matrices.""" + + 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:] + + [self.num, self.den] = data + def __neg__(self): """Negate a transfer function.""" @@ -128,16 +149,22 @@ if not isinstance(other, xTransferFunction): other = ss2tf(other) + # Check that the input-output sizes are consistent. + if self.inputs != other.inputs: + raise ValueError("The two systems to be added must have the same \ +input size.") + if self.outputs != other.outputs: + raise ValueError("The two systems to be added must have the same \ +output size.") + # Preallocate the numerator and denominator of the sum. num = [[[] for j in range(self.inputs)] for i in range(self.outputs)] den = [[[] for j in range(self.inputs)] for i in range(self.outputs)] for i in range(self.outputs): for j in range(self.inputs): - num[i][j] = sp.polyadd( - sp.polymul(self.num[i][j], other.den[i][j]), - sp.polymul(other.num[i][j], self.den[i][j])) - den[i][j] = sp.polymul(self.den[i][j], other.den[i][j]) + 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) @@ -156,11 +183,40 @@ return other + (-self) - def __mul__(self, sys): + def __mul__(self, other): """Multiply two transfer functions (serial connection)""" - pass + # Convert the second argument to a transfer function. + if not isinstance(other, xTransferFunction): + other = ss2tf(other) + + # Check that the input-output sizes are consistent. + if self.inputs != other.outputs: + raise ValueError("C = A * B: A must have the same number of \ +columns (inputs) as B has\nrows (outputs).") + inputs = other.inputs + outputs = self.outputs + + # Preallocate the numerator and denominator of the sum. + num = [[[0] for j in range(inputs)] for i in range(outputs)] + den = [[[0] for j in range(inputs)] for i in range(outputs)] + + # Temporary storage for the summands needed to find the (i, j)th element + # of the product. + num_summand = [[] for k in range(self.inputs)] + den_summand = [[] for k in range(self.inputs)] + + for i in range(outputs): # Iterate through rows of product. + for j in range(inputs): # Iterate through columns of product. + for k in range(self.inputs): # Multiply & add. + num_summand[k] = sp.polymul(self.num[i][k], other.num[k][j]) + den_summand[k] = sp.polymul(self.den[i][k], other.den[k][j]) + num[i][j], den[i][j] = addSISO(num[i][j], den[i][j], + num_summand[k], den_summand[k]) + + return xTransferFunction(num, den) + def __rmul__(self, other): """Multiply two transfer functions (serial connection)""" @@ -371,11 +427,6 @@ # Return the result as a transfer function return TransferFunction(num, den) -def ss2tf(sys): - """Convert a state space object to a transfer function object.""" - - pass - # Utility function to convert a transfer function polynomial to a string # Borrowed from poly1d library def _tfpolyToString(coeffs, var='s'): @@ -424,3 +475,17 @@ else: thestr = newstr return thestr + +def addSISO(num1, den1, num2, den2): + """Return num/den = num1/den1 + num2/den2, where each numerator and + denominator is a list of polynomial coefficients.""" + + num = sp.polyadd(sp.polymul(num1, den2), sp.polymul(num2, den1)) + den = sp.polymul(den1, den2) + + return num, den + +def ss2tf(sys): + """Convert a state space object to a transfer function object.""" + + pass \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |