From: <kk...@us...> - 2011-02-08 22:16:43
|
Revision: 84 http://python-control.svn.sourceforge.net/python-control/?rev=84&view=rev Author: kkchen Date: 2011-02-08 22:16:36 +0000 (Tue, 08 Feb 2011) Log Message: ----------- Finished writing TransferFunction._common_den. tf2ss should now work. In initial tests, however, a "nan" appears in some results. This needs to be investigated further. 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:31 UTC (rev 83) +++ branches/control-0.4a/src/statesp.py 2011-02-08 22:16:36 UTC (rev 84) @@ -424,7 +424,7 @@ 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 Modified: branches/control-0.4a/src/xferfcn.py =================================================================== --- branches/control-0.4a/src/xferfcn.py 2011-02-08 22:16:31 UTC (rev 83) +++ branches/control-0.4a/src/xferfcn.py 2011-02-08 22:16:36 UTC (rev 84) @@ -72,8 +72,8 @@ """ # External function declarations -from numpy import angle, array, empty, ndarray, ones, polyadd, polymul, \ - polyval, roots, zeros +from numpy import angle, array, empty, finfo, insert, ndarray, ones, polyadd, \ + polymul, polyval, roots, sort, zeros from scipy.signal import lti from copy import deepcopy from slycot import tb04ad @@ -470,33 +470,108 @@ >>> n, d = sys._common_den() computes the single denominator containing all the poles of sys.den, and - reports it as the array d. + 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. - 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. + # A sorted list to keep track of cumulative poles found as we scan + # self.den. poles = [] - # A 3-D list to keep track of common denominator roots not present in + # A 3-D list to keep track of common denominator poles 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 + for i in range(self.outputs): + for j in range(self.inputs): + # A sorted array of the poles of this SISO denominator. + currentpoles = sort(roots(self.den[i][j])) + cp_ind = 0 # Index in currentpoles. + p_ind = 0 # Index in poles. + + # Crawl along the list of current poles and the list of + # cumulative poles, until one of them reaches the end. Keep in + # mind that both lists are always sorted. + while cp_ind < len(currentpoles) and p_ind < len(poles): + if abs(currentpoles[cp_ind] - poles[p_ind]) < (10 * + finfo(float).eps): + # If the current element of both lists match, then we're + # good. Move to the next pair of elements. + cp_ind += 1 + elif currentpoles[cp_ind] < poles[p_ind]: + # We found a pole in this transfer function that's not + # in the list of cumulative poles. Add it to the list. + poles.insert(p_ind, currentpoles[cp_ind]) + # Now mark this pole as "missing" in all previous + # denominators. + for k in range(i): + for m in range(self.inputs): + # All previous rows. + missingpoles[k][m].append(currentpoles[cp_ind]) + for m in range(j): + # This row only. + missingpoles[i][m].append(currentpoles[cp_ind]) + cp_ind += 1 + else: + # There is a pole in the cumulative list of poles that + # is not in our transfer function denominator. Mark + # this pole as "missing", and do not increment cp_ind. + missingpoles[i][j].append(poles[p_ind]) + p_ind += 1 + + if cp_ind == len(currentpoles) and p_ind < len(poles): + # If we finished scanning currentpoles first, then all the + # remaining cumulative poles are missing poles. + missingpoles[i][j].extend(poles[p_ind:]) + elif cp_ind < len(currentpoles) and p_ind == len(poles): + # If we finished scanning the cumulative poles first, then + # all the reamining currentpoles need to be added to poles. + poles.extend(currentpoles[cp_ind:]) + # Now mark these poles as "missing" in previous + # denominators. + for k in range(i): + for m in range(self.inputs): + # All previous rows. + missingpoles[k][m].extend(currentpoles[cp_ind:]) + for m in range(j): + # This row only. + missingpoles[i][m].extend(currentpoles[cp_ind:]) + + # Construct the common denominator. + den = 1. + for p in poles: + den = polymul(den, [1., -p]) + + # Modify the numerators so that they each take the common denominator. + num = deepcopy(self.num) + for i in range(self.outputs): + for j in range(self.inputs): + # The common denominator has leading coefficient 1. Scale out + # the existing denominator's leading coefficient. + assert self.den[i][j][0], "The i = %i, j = %i denominator has \ +a zero leading coefficient." % (i, j) + num[i][j] = num[i][j] / self.den[i][j][0] + # Multiply in the missing poles. + for p in missingpoles[i][j]: + num[i][j] = polymul(num[i][j], [1., -p]) + # Find the largest numerator polynomial size. + largest = 0 + for i in range(self.outputs): + for j in range(self.inputs): + largest = max(largest, len(num[i][j])) + # Pad all smaller numerator polynomials with zeros. + for i in range(self.outputs): + for j in range(self.inputs): + num[i][j] = insert(num[i][j], zeros(largest - len(num[i][j])), + zeros(largest - len(num[i][j]))) + # Finally, convert the numerator to a 3-D array. + num = array(num) + + return num, den + # 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. |