Skip to content

td04ad (convert tf to ss) returns incorrect poles #222

@murrayrm

Description

@murrayrm

A bug was reported in python-control issue #935 in which tf2ss returns the incorrect poles.

It looks like the underlying problem is in td04ad. The following code illustrates the bug:

from numpy import array, roots, sort
from numpy.linalg import eig
from numpy.testing import assert_allclose
from slycot import td04ad
from scipy.signal import tf2ss

# Test case #1 (works)

num = array([[[1, 1, 1, 1, 1]]])
den = array([[1, 2, 1, 2, 1]])
denorder = np.array([den.size - 1])

ssout = td04ad('C', 1, 1, denorder, den, num, tol=0)

tf_poles = sort(roots(den[0]))
ss_poles = sort(eig(ssout[1])[0])
assert_allclose(tf_poles, ss_poles)

# Test case #2 (doesn't work)

num = array([[[1.05351324e-02, 2.83623596e-01, 2.44891698e+00, 1.22011448e+01,
               5.34846570e+01, 1.42092310e+02, 2.24627039e+02, 2.54305034e+02,
               2.18224432e+02, 1.24102950e+02, 4.99448809e+01, 1.26651596e+01,
               2.02239050e+00, 1.06681479e-01, 1.56212741e-03, 8.90622718e-06,
               1.77205330e-08]]])
den = array([[1.00000000e+00, 6.41551095e+02, 8.40213016e+03, 5.55121354e+04,
              1.93428590e+05, 1.31800818e+05, 9.20183802e+04, 2.90211403e+04,
              4.54824418e+03, 4.08636727e+02, 1.72367976e+01, 8.91452881e-02,
              1.04426479e-04, 4.32051569e-08, 5.88752872e-12, 3.24913608e-16,
              6.34764375e-21]])
denorder = np.array([den.size - 1])

# Try scipy
A, B, C, D = tf2ss(num[0, 0], den[0])
tf_poles = sort(roots(den[0]))
ss_poles = sort(eig(A)[0])
assert_allclose(tf_poles, ss_poles)

# Now try slycot
ssout = td04ad('C', 1, 1, denorder, den, num, tol=0)
ss_poles = sort(eig(ssout[1])[0])
assert_allclose(tf_poles, ss_poles)

For the second system, the scipy-generated poles match, but some of the the slycot-generated poles are not the same (and one of them is unstable).

It's possible this is a numerical issue (the coefficients span 21 orders of magnitude!), but odd the SciPy gets it right and slycot doesn't. (SciPy uses an observable canonical form-based realization.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions