Skip to content

Commit 1029410

Browse files
author
Benjamin Greiner
committed
reintroduce the use of imag_tol, get rid of polyfromroots
renamed the np variable because that is used as numpy otherwise
1 parent d09472c commit 1029410

File tree

1 file changed

+32
-38
lines changed

1 file changed

+32
-38
lines changed

control/xferfcn.py

+32-38
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
polyadd, polymul, polyval, roots, sqrt, zeros, squeeze, exp, pi, \
5858
where, delete, real, poly, nonzero
5959
import scipy as sp
60-
from numpy.polynomial.polynomial import polyfromroots
6160
from scipy.signal import lti, tf2zpk, zpk2tf, cont2discrete
6261
from copy import deepcopy
6362
from warnings import warn
@@ -803,8 +802,6 @@ def _common_den(self, imag_tol=None):
803802
output numerator array num is modified to use the common
804803
denominator for this input/column; the coefficient arrays are also
805804
padded with zeros to be the same size for all num/den.
806-
num is an sys.outputs by sys.inputs
807-
by len(d) array.
808805
809806
Parameters
810807
----------
@@ -815,17 +812,20 @@ def _common_den(self, imag_tol=None):
815812
Returns
816813
-------
817814
num: array
818-
Multi-dimensional array of numerator coefficients. num[i][j]
819-
gives the numerator coefficient array for the ith input and jth
820-
output, also prepared for use in td04ad; matches the denorder
821-
order; highest coefficient starts on the left.
815+
n by n by kd where n = max(sys.outputs,sys.inputs)
816+
kd = max(denorder)+1
817+
Multi-dimensional array of numerator coefficients. num[i,j]
818+
gives the numerator coefficient array for the ith output and jth
819+
input; padded for use in td04ad ('C' option); matches the
820+
denorder order; highest coefficient starts on the left.
822821
823822
den: array
823+
sys.inputs by kd
824824
Multi-dimensional array of coefficients for common denominator
825825
polynomial, one row per input. The array is prepared for use in
826826
slycot td04ad, the first element is the highest-order polynomial
827-
coefficiend of s, matching the order in denorder, if denorder <
828-
number of columns in den, the den is padded with zeros
827+
coefficient of s, matching the order in denorder. If denorder <
828+
number of columns in den, the den is padded with zeros.
829829
830830
denorder: array of int, orders of den, one per input
831831
@@ -839,16 +839,18 @@ def _common_den(self, imag_tol=None):
839839

840840
# Machine precision for floats.
841841
eps = finfo(float).eps
842+
real_tol = sqrt(eps * self.inputs * self.outputs)
842843

843-
# Decide on the tolerance to use in deciding if a pole is complex
844+
# The tolerance to use in deciding if a pole is complex
844845
if (imag_tol is None):
845-
imag_tol = 1e-8 # TODO: figure out the right number to use
846+
imag_tol = 2 * real_tol
846847

847848
# A list to keep track of cumulative poles found as we scan
848849
# self.den[..][..]
849850
poles = [[] for j in range(self.inputs)]
850851

851852
# RvP, new implementation 180526, issue #194
853+
# BG, modification, issue #343, PR #354
852854

853855
# pre-calculate the poles for all num, den
854856
# has zeros, poles, gain, list for pole indices not in den,
@@ -867,31 +869,34 @@ def _common_den(self, imag_tol=None):
867869
poleset[-1].append([z, p, k, [], 0])
868870

869871
# collect all individual poles
870-
epsnm = eps * self.inputs * self.outputs
871872
for j in range(self.inputs):
872873
for i in range(self.outputs):
873874
currentpoles = poleset[i][j][1]
874875
nothave = ones(currentpoles.shape, dtype=bool)
875876
for ip, p in enumerate(poles[j]):
876-
idx, = nonzero(
877-
(abs(currentpoles - p) < sqrt(epsnm)) * nothave)
878-
if len(idx):
879-
nothave[idx[0]] = False
877+
collect = ((abs(currentpoles.real - p.real) < real_tol) &
878+
(abs(currentpoles.imag - p.imag) < imag_tol) &
879+
nothave)
880+
if np.any(collect):
881+
# mark first found pole as already collected
882+
nothave[nonzero(collect)[0][0]] = False
880883
else:
881884
# remember id of pole not in tf
882885
poleset[i][j][3].append(ip)
883886
for h, c in zip(nothave, currentpoles):
884887
if h:
888+
if abs(c.imag) < imag_tol:
889+
c = c.real
885890
poles[j].append(c)
886891
# remember how many poles now known
887892
poleset[i][j][4] = len(poles[j])
888893

889894
# figure out maximum number of poles, for sizing the den
890-
npmax = max([len(p) for p in poles])
891-
den = zeros((self.inputs, npmax + 1), dtype=float)
895+
maxindex = max([len(p) for p in poles])
896+
den = zeros((self.inputs, maxindex + 1), dtype=float)
892897
num = zeros((max(1, self.outputs, self.inputs),
893898
max(1, self.outputs, self.inputs),
894-
npmax + 1),
899+
maxindex + 1),
895900
dtype=float)
896901
denorder = zeros((self.inputs,), dtype=int)
897902

@@ -903,18 +908,10 @@ def _common_den(self, imag_tol=None):
903908
num[i, j, 0] = poleset[i][j][2]
904909
else:
905910
# create the denominator matching this input
906-
# polyfromroots gives coeffs in opposite order from what we use
907-
# coefficients should be padded on right, ending at np
908-
np = len(poles[j])
909-
denpoly = polyfromroots(poles[j])
910-
if (abs(denpoly.imag) > imag_tol).any():
911-
warn("The denominator of the transfer function "
912-
"for input {j} to output {i} has a nontrivial "
913-
"imaginary part of {imag}, which was removed".format(
914-
i=i, j=j, imag=max(denpoly.imag)))
915-
denpoly = denpoly.real
916-
den[j, np::-1] = denpoly
917-
denorder[j] = np
911+
# coefficients should be padded on right, ending at maxindex
912+
maxindex = len(poles[j])
913+
den[j, :maxindex+1] = poly(poles[j])
914+
denorder[j] = maxindex
918915

919916
# now create the numerator, also padded on the right
920917
for i in range(self.outputs):
@@ -923,20 +920,17 @@ def _common_den(self, imag_tol=None):
923920
# add all poles not found in the original denominator,
924921
# and the ones later added from other denominators
925922
for ip in chain(poleset[i][j][3],
926-
range(poleset[i][j][4], np)):
923+
range(poleset[i][j][4], maxindex)):
927924
nwzeros.append(poles[j][ip])
928925

929-
numpoly = poleset[i][j][2] * polyfromroots(nwzeros).real
930-
# print(numpoly, den[j])
931-
# polyfromroots gives coeffs in opposite order => invert
926+
numpoly = poleset[i][j][2] * np.atleast_1d(poly(nwzeros))
932927
# numerator polynomial should be padded on left and right
933-
# ending at np to line up with what td04ad expects...
934-
num[i, j, np + 1 - len(numpoly):np + 1] = numpoly[::-1]
928+
# ending at maxindex to line up with what td04ad expects.
929+
num[i, j, maxindex+1-len(numpoly):maxindex+1] = numpoly
935930
# print(num[i, j])
936931

937932
return num, den, denorder
938933

939-
940934
def sample(self, Ts, method='zoh', alpha=None):
941935
"""Convert a continuous-time system to discrete time
942936

0 commit comments

Comments
 (0)