Skip to content

Unexpected and unwanted behaviour of control.ctrb #1097

Closed

Description

@bwolleswinkel

I have found some unexplainable and unwanted behavior of the control.ctrb functions, which returns a 'controllability matrix' with incorrect dimensions rather than returning an error/warning that the $B$ matrix is not dimensioned properly.

MWE:

import numpy as np
import control as ct

A = np.array([[1, 1], [0, 1]])
b = np.array([1, 1])
C = ct.ctrb(A, b)  # Rather then 1) returning an error that b is not properly dimensioned, or 2) assuming that b is a columns vector, it instead returns a matrix with shape 2 x 4, which makes no sense for a controllability matrix

C_T = ct.ctrb(A, np.atleast_2d(b).T)  # Explicitly specifying that b is a column vector fixes this and C_T is now a 2 x 2 matrix

I believe the behavior is incorrect, and it took me quite some time to understand what was going wrong; any (dis)agreement would be appreciated, thanks.

Activity

  1. roryyorke commented on Jan 19, 2025

    @roryyorke
    Contributor

    the arguments for ctrb and obsv aren't checked for size.

    In [42]: ct.ctrb(np.eye(2), 0.5)
    Out[42]: 
    array([[0.5, 0.5],
           [0.5, 0.5]])
    
    In [43]: ct.ctrb(0.3*np.eye(2), 0.5)
    Out[43]: 
    array([[0.5 , 0.15],
           [0.5 , 0.15]])
    
    In [44]: ct.ctrb(0.1*np.eye(2), 1)
    Out[44]: 
    array([[1. , 0.1],
           [1. , 0.1]])
    
    In [45]: ct.ctrb(0.1*np.eye(2), np.array([1,1]))
    Out[45]: 
    array([[1. , 1. , 0.1, 0.1],
           [1. , 1. , 0.1, 0.1]])
    
    In [46]: ct.obsv(0.1*np.eye(2), 1)
    Out[46]: 
    array([[1. , 1. ],
           [0.1, 0.1]])
    
    In [47]: ct.obsv(0.1*np.eye(2), [1, 1])
    Out[47]: 
    array([[1. , 1. ],
           [0.1, 0.1]])
    
    In [48]: ct.obsv(0.1*np.eye(2), [1, 1, 1])
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    Cell In[48], line 1
    ----> 1 ct.obsv(0.1*np.eye(2), [1, 1, 1])
    
    File ~/miniforge3/envs/work/lib/python3.12/site-packages/control/statefbk.py:1070, in obsv(A, C, t)
       1068 # Construct the observability matrix
       1069 obsv = np.zeros((t * p, n))
    -> 1070 obsv[:p, :] = cmat
       1072 for k in range(1, t):
       1073     obsv[k * p:(k + 1) * p, :] = np.dot(obsv[(k - 1) * p:k * p, :], amat)
    
    ValueError: could not broadcast input array from shape (1,3) into shape (1,2)
    

    The fix seems straightforward -- adapt the _ssmatrix calls and size checks from the statesp.StateSpace.__init__.

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