|
From: <kk...@us...> - 2011-02-08 22:16:37
|
Revision: 83
http://python-control.svn.sourceforge.net/python-control/?rev=83&view=rev
Author: kkchen
Date: 2011-02-08 22:16:31 +0000 (Tue, 08 Feb 2011)
Log Message:
-----------
Begun work on tf2ss wrapping. Wrote StateSpace._remove_useless_states.
TransferFunction.pole and convertToStateSpace have been edited to use
TransferFunction._common_den, which returns a common denominator formulation of
a MIMO transfer function. _common_den is not completed yet.
Also, StateSpace._remove_useless_states was written to remove states marked by
entire rows or columns of zeros in the A, B, or C matrix. Now, TestBDAlg.py
passes.
Kevin K. Chen <kk...@pr...>
Modified Paths:
--------------
branches/control-0.4a/src/statesp.py
branches/control-0.4a/src/xferfcn.py
Modified: branches/control-0.4a/src/statesp.py
===================================================================
--- branches/control-0.4a/src/statesp.py 2011-02-08 22:16:26 UTC (rev 82)
+++ branches/control-0.4a/src/statesp.py 2011-02-08 22:16:31 UTC (rev 83)
@@ -68,12 +68,13 @@
"""
-from numpy import angle, any, array, concatenate, cos, dot, empty, exp, eye, \
- ones, pi, poly, poly1d, matrix, roots, sin, zeros
+from numpy import all, angle, any, array, concatenate, cos, delete, dot, \
+ empty, exp, eye, matrix, ones, pi, poly, poly1d, roots, sin, zeros
from numpy.random import rand, randn
from numpy.linalg import inv, det, solve
from numpy.linalg.linalg import LinAlgError
from scipy.signal import lti
+from slycot import td04ad
from lti import Lti
import xferfcn
@@ -121,6 +122,46 @@
if self.outputs != D.shape[0]:
raise ValueError("D must have the same row size as C.")
+ # Check for states that don't do anything, and remove them.
+ self._remove_useless_states()
+
+ def _remove_useless_states(self):
+ """Check for states that don't do anything, and remove them.
+
+ Scan the A, B, and C matrices for rows or columns of zeros. If the
+ zeros are such that a particular state has no effect on the input-output
+ dynamics, then remove that state from the A, B, and C matrices.
+
+ """
+
+ # Indices of useless states.
+ useless = []
+
+ # Search for useless states.
+ for i in range(self.states):
+ if (all(self.A[i, :] == zeros((1, self.states))) and
+ all(self.B[i, :] == zeros((1, self.inputs)))):
+ useless.append(i)
+ # To avoid duplucate indices in useless, jump to the next
+ # iteration.
+ continue
+ if (all(self.A[:, i] == zeros((self.states, 1))) and
+ all(self.C[:, i] == zeros((self.outputs, 1)))):
+ useless.append(i)
+
+ # Remove the useless states.
+ if all(useless == range(self.states)):
+ # All the states were useless.
+ self.A = 0
+ self.B = zeros((1, self.inputs))
+ self.C = zeros((self.outputs, 1))
+ else:
+ # A more typical scenario.
+ self.A = delete(self.A, useless, 0)
+ self.A = delete(self.A, useless, 1)
+ self.B = delete(self.B, useless, 0)
+ self.C = delete(self.C, useless, 1)
+
def __str__(self):
"""String representation of the state space."""
@@ -374,15 +415,23 @@
# Already a state space system; just return it
return sys
elif isinstance(sys, xferfcn.TransferFunction):
- # TODO: Wrap SLICOT to do transfer function to state space conversion.
- raise NotImplementedError("Transfer function to state space conversion \
-is not implemented yet.")
- elif (isinstance(sys, (int, long, float, complex))):
+ # Change the numerator and denominator arrays so that the transfer
+ # function matrix has a common denominator.
+ num, den = sys._common_den()
+ # Make a list of the orders of the denominator polynomials.
+ index = [len(den) for i in range(sys.outputs)]
+ # Repeat the common denominator along the rows.
+ den = array([den for i in range(sys.outputs)])
+
+ ssout = td04ad(sys.inputs, sys.outputs, index, num, den)
+
+ return StateSpace(ssout[1], ssout[2], ssout[3], ssout[4])
+ 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([[]], [[]], [[]], eye(outputs, inputs))
return StateSpace(0., zeros((1, inputs)), zeros((outputs, 1)),
- sys * ones(outputs, inputs))
+ sys * ones((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:16:26 UTC (rev 82)
+++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:16:31 UTC (rev 83)
@@ -26,6 +26,7 @@
TransferFunction.zero
TransferFunction.feedback
TransferFunction.returnScipySignalLti
+TransferFunction._common_den
_tfpolyToString
_addSISO
convertToTransferFunction
@@ -72,7 +73,7 @@
# External function declarations
from numpy import angle, array, empty, ndarray, ones, polyadd, polymul, \
- polyval, zeros
+ polyval, roots, zeros
from scipy.signal import lti
from copy import deepcopy
from slycot import tb04ad
@@ -406,9 +407,9 @@
def pole(self):
"""Compute the poles of a transfer function."""
- raise NotImplementedError("TransferFunction.pole is not implemented \
-yet.")
-
+ num, den = self._common_den()
+ return roots(den)
+
def zero(self):
"""Compute the zeros of a transfer function."""
@@ -463,6 +464,39 @@
return out
+ def _common_den(self):
+ """Compute MIMO common denominator; return it and an adjusted numerator.
+
+ >>> n, d = sys._common_den()
+
+ computes the single denominator containing all the poles of sys.den, and
+ reports it as the array d.
+
+ The output numerator array n is modified to use the common denominator.
+ It is an sys.outputs-by-sys.inputs-by-[something] array.
+
+ """
+
+ # Preallocate some variables. Start by figuring out the maximum number
+ # of numerator coefficients.
+ numcoeffs = 0
+ for i in range(self.outputs):
+ for j in range(self.inputs):
+ numcoeffs = max(numcoeffs, len(self.num[i][j]))
+ # The output 3-D adjusted numerator array.
+ num = empty((i, j, numcoeffs))
+ # A list to keep track of roots found as we scan self.den.
+ poles = []
+ # A 3-D list to keep track of common denominator roots not present in
+ # the self.den[i][j].
+ missingpoles = [[[] for j in range(self.inputs)] for i in
+ range(self.outputs)]
+
+ for i in range(sys.outputs):
+ for j in range(sys.inputs):
+ currentpoles = roots(self.den[i][j])
+ #TODO: finish this
+
# Utility function to convert a transfer function polynomial to a string
# Borrowed from poly1d library
def _tfpolyToString(coeffs, var='s'):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|