|
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.
|