Skip to content

Erroneous time-domain sim (because of ss2tf)  #240

Closed

Description

@hungpham2511

Hi, it seems python-control has a weird bug in the pipeline for converting from MIMO transfer function to state-space form. Consider the below gist

import control as co
import numpy as np
from numpy import array

num = [[array([0.]), array([1.0])],
       [array([1.0]), array([0.0])]]


den = [[array([1.]), array([1, 1])],
       [array([  1.        , 4.0]), array([1.0])]]
sys = co.tf(num, den)
t, y = co.step_response(sys, input=0)
print("step response (output 1 from input 0) (old): {:}".format(y[1, -1]))

# slightly change the denominator
den = [[array([1.]), array([1e-10, 1, 1])],
       [array([  1.        , 4.0]), array([1.0])]]
sys = co.tf(num, den)
t, y = co.step_response(sys, input=0)
print("step response (output 1 from input 0) (changed): {:}".format(y[1, -1]))

The output on my computer is

step response (output 1 from input 0) (first): 0.24999999999982692
step response (output 1 from input 0) (second): 0.0

Clearly in the later case, there is a bug in the time-domain simulation function. The DC gain from input 1 to output 1 is 0.25, so the first simulation works alright. But in the second simulation, I obtain zero output. A preliminary investigation suggests that the problem is in the ss2tf procedure, particularly, in the slicot function.

Any suggestions would be great. Current I have to resort to matlab to do the transformation from transfer function to state-space in my application.

Activity

  1. murrayrm commented on Nov 4, 2018

    @murrayrm
    Member

    Confirmed that this is a bug and that the problem is in the conversion to state space form. The following code illustrates the error:

    import control
    import numpy as np
            
    num =  [ [[0], [1]],           [[1],   [0]] ]
    den1 = [ [[1], [1,1]],         [[1,4], [1]] ]
    sys1tf = control.tf(num, den1)
    sys1ss = control.tf2ss(sys1tf)
    
    # slight perturbation
    den2 = [ [[1], [1e-10, 1, 1]], [[1,4], [1]] ]
    sys2tf = control.tf(num, den2)
    sys2ss = control.tf2ss(sys2tf)
    
    # Make sure that the poles match for StateSpace and TransferFunction
    np.testing.assert_array_almost_equal(sys1tf.pole(), sys1ss.pole())
    np.testing.assert_array_almost_equal(sys2tf.pole(), sys2ss.pole())
    

    The poles for sys1tf and sys1ss are -4 and -1. The poles for sys2tf are -1e10, -4, -1 (correct) but for sys2ss they are -1e10, -1 (incorrect). Not clear how/why the pole at -4 is being dropped. The state space realizations are:

    sys1ss
    A = [[-4.,  0.],  [ 0., -1.]]
    B = [[-1.,  0.],  [ 0., -1.]]
    C = [[ 0., -1.], [-1.  0.]]
    D = [[0., 0.], [0. 0.]]
    
    sys2ss
    A = [[-1.e+10,  1.e+05],  [-1.e+05,  0.e+00]]
    B = [[ 0., -1.], [ 0.,  0.]]
    C = [[     0., 100000.],  [     0.,      0.]]
    D = [[0., 0.],  [0., 0.]]
    

    So sys2ss is really wrong...

    I've created unit tests to catch this error, which can be used once it is fixed. Will commit them as part of the fix.

  2. added a commit that references this issue on Nov 4, 2018
  3. murrayrm commented on Nov 4, 2018

    @murrayrm
    Member

    Found the problem. Turns out it was not with slycot (or slicot), but rather with the utility function xferfcn._common_den(). This function is used to create the input for the function slycot.td04ad(), which converts a (MIMO) transfer function to a state space system. There are some tricks in the way the coefficients are padded and these had a bug. PR #242 has a fix.

  4. hungpham2511 commented on Nov 5, 2018

    @hungpham2511
    ContributorAuthor

    Thank you for investigating. Just try a few examples and things seem to be working nicely. I will close this issue.

    By the way, may I know if python-control is accepting pr? I need lft (Linear Fractional Transform) and have implemented the function in my fork. Would love to have it reviewed.

  5. murrayrm commented on Nov 5, 2018

    @murrayrm
    Member

    Reopening: this issue is not actually fixed yet. There is a pull request in the works, but it is having unit test errors. Until it gets sorted out, I'll leave this issue open.

  6. murrayrm commented on Nov 5, 2018

    @murrayrm
    Member

    @hungpham2511 Regarding pull requests: you are welcome to add to code base! Please post a PR when you have a chance and someone will have a look.

  7. added a commit that references this issue on Dec 22, 2018
  8. murrayrm commented on Dec 22, 2018

    @murrayrm
    Member

    Fixed in PR #242, now merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions