From: <kk...@us...> - 2011-02-08 22:14:57
|
Revision: 63 http://python-control.svn.sourceforge.net/python-control/?rev=63&view=rev Author: kkchen Date: 2011-02-08 22:14:51 +0000 (Tue, 08 Feb 2011) Log Message: ----------- Implemented xTransferFunction.feedback in xferfcn.py for SISO. Modified bdalg.py for the new feedback functions. Also modified xTransferFunction constructor to change the denominator to 1 whenever the numerator is 0. Various bug fixes, e.g. in convertToTransferFunction. Added feedback test in TestXferFcn.py. Added NotImplementedError in StateSpace.zeros for MIMO. Added NotImplementedError for SS -> TF and TF -> SS conversions. Kevin K. Chen <kk...@pr...> Modified Paths: -------------- branches/control-0.4a/src/TestXferFcn.py branches/control-0.4a/src/statesp.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:46 UTC (rev 62) +++ branches/control-0.4a/src/TestXferFcn.py 2011-02-08 22:14:51 UTC (rev 63) @@ -7,7 +7,8 @@ class TestXferFcn(unittest.TestCase): """These are tests for functionality and correct reporting of the transfer function class. Throughout these tests, we will give different input - formats to the xTranferFunction constructor, to try to break it.""" + formats to the xTranferFunction constructor, to try to break it. These + tests have been verified in MATLAB.""" # Tests for raising exceptions. @@ -211,7 +212,7 @@ [[-4., -3., 2.], [0., 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.]], + den3 = [[[3., -2., -4], [1., 2., 3., 0., 0.], [1]], [[-12., -9., 6., 0., 0.], [2., -1., -1], [1., 0.]]] sys1 = xTransferFunction(num1, den1) @@ -379,6 +380,20 @@ np.testing.assert_array_almost_equal(phase, truephase) np.testing.assert_array_equal(omega, trueomega) - + # Tests for xTransferFunction.feedback. + + def testFeedbackSISO(self): + + sys1 = xTransferFunction([-1., 4.], [1., 3., 5.]) + sys2 = xTransferFunction([2., 3., 0.], [1., -3., 4., 0]) + + sys3 = sys1.feedback(sys2) + sys4 = sys1.feedback(sys2, 1) + + np.testing.assert_array_equal(sys3.num, [[[-1., 7., -16., 16., 0.]]]) + np.testing.assert_array_equal(sys3.den, [[[1., 0., -2., 2., 32., 0.]]]) + np.testing.assert_array_equal(sys4.num, [[[-1., 7., -16., 16., 0.]]]) + np.testing.assert_array_equal(sys4.den, [[[1., 0., 2., -8., 8., 0.]]]) + if __name__ == "__main__": unittest.main() Modified: branches/control-0.4a/src/statesp.py =================================================================== --- branches/control-0.4a/src/statesp.py 2011-02-08 22:14:46 UTC (rev 62) +++ branches/control-0.4a/src/statesp.py 2011-02-08 22:14:51 UTC (rev 63) @@ -120,11 +120,18 @@ # Compute poles and zeros def poles(self): + """Compute the poles of a state space system.""" + return sp.roots(sp.poly(self.A)) def zeros(self): + """Compute the zeros of a state space system.""" + + if self.inputs > 1 or self.outputs > 1: + raise NotImplementedError("StateSpace.zeros is currently \ +implemented only for SISO systems.") + den = sp.poly1d(sp.poly(self.A)) - # Compute the numerator based on zeros #! TODO: This is currently limited to SISO systems num = sp.poly1d(\ @@ -273,12 +280,13 @@ # Already a state space system; just return it return sys elif isinstance(sys, xferfcn.TransferFunction): - pass # TODO: convert SS to TF + raise NotImplementedError("Transfer function to state space conversion \ +is not implemented yet.") elif (isinstance(sys, (int, long, float, complex))): # Generate a simple state space system of the desired dimension # The following Doesn't work due to inconsistencies in ltisys: # return StateSpace([[]], [[]], [[]], sp.eye(outputs, inputs)) - return StateSpace(0, zeros((1, inputs)), zeros((outputs, 1)), + return StateSpace(0., zeros((1, inputs)), zeros((outputs, 1)), sys * sp.eye(outputs, inputs)) else: raise TypeError("Can't convert given type to StateSpace system.") Modified: branches/control-0.4a/src/xferfcn.py =================================================================== --- branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:46 UTC (rev 62) +++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:14:51 UTC (rev 63) @@ -108,8 +108,8 @@ raise ValueError("The numerator has %i output(s), but the \ denominator has %i\noutput(s)." % (outputs, len(den))) - # Make sure that each row has the same number of columns. for i in range(outputs): + # Make sure that each row has the same number of columns. if len(num[i]) != inputs: raise ValueError("Row 0 of the numerator matrix has %i \ elements, but row %i\nhas %i." % (inputs, i, len(num[i]))) @@ -117,17 +117,29 @@ raise ValueError("Row 0 of the denominator matrix has %i \ elements, but row %i\nhas %i." % (inputs, i, len(den[i]))) - # Check that we don't have any zero denominators. + # TODO: Right now these checks are only done during construction. + # It might be worthwhile to think of a way to perform checks if the + # user modifies the transfer function after construction. for j in range(inputs): - iszero = True + # Check that we don't have any zero denominators. + zeroden = True for k in den[i][j]: if k: - iszero = False + zeroden = False break - if iszero: + if zeroden: raise ValueError("Input %i, output %i has a zero \ denominator." % (j + 1, i + 1)) + # If we have zero numerators, set the denominator to 1. + zeronum = True + for k in num[i][j]: + if k: + zeronum = False + break + if zeronum: + den[i][j] = sp.ones(1) + self.num = num self.den = den Lti2.__init__(self, inputs, outputs) @@ -246,7 +258,7 @@ # Convert the second argument to a transfer function. if not isinstance(other, xTransferFunction): - other = convertToTransferFunction(other, self.outputs, self.outputs) + other = convertToTransferFunction(other, self.inputs, self.inputs) # Check that the input-output sizes are consistent. if self.inputs != other.outputs: @@ -352,11 +364,31 @@ pass - def feedback(sys1, sys2, sign=-1): + def feedback(self, other, sign=-1): """Feedback interconnection between two transfer functions.""" - pass + other = convertToTransferFunction(other) + if self.inputs > 1 or self.outputs > 1 or \ + other.inputs > 1 or other.outputs > 1: + raise NotImplementedError("xTransferFunction.feedback is currently \ +only implemented for SISO functions.") + + num1 = self.num[0][0] + den1 = self.den[0][0] + num2 = other.num[0][0] + den2 = other.den[0][0] + + num = sp.polymul(num1, den2) + den = sp.polyadd(sp.polymul(den2, den1), -sign * sp.polymul(num2, num1)) + + return xTransferFunction(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. @@ -593,9 +625,15 @@ if isinstance(sys, xTransferFunction): return sys elif isinstance(sys, statesp.StateSpace): - pass #TODO: convert TF to SS + raise NotImplementedError("State space to transfer function conversion \ +is not implemented yet.") elif isinstance(sys, (int, long, float, complex)): - coeff = sp.eye(outputs, inputs) - return xTransferFunction(sys * coeff, coeff) + # Make an identity system. + num = [[[0] for j in range(inputs)] for i in range(outputs)] + den = [[[1] for j in range(inputs)] for i in range(outputs)] + for i in range(min(inputs, outputs)): + num[i][i] = [sys] + + return xTransferFunction(num, den) else: - raise TypeError("Can't convert given type to StateSpace system.") + raise TypeError("Can't convert given type to xTransferFunction system.") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |