Example #1
0
def gram(sys, type):
    """Gramian (controllability or observability)

    Parameters
    ----------
    sys : StateSpace
        System description
    type : String
        Type of desired computation.  `type` is either 'c' (controllability)
        or 'o' (observability). To compute the Cholesky factors of Gramians
        use 'cf' (controllability) or 'of' (observability)

    Returns
    -------
    gram : 2D array (or matrix)
        Gramian of system

    Raises
    ------
    ValueError
        * if system is not instance of StateSpace class
        * if `type` is not 'c', 'o', 'cf' or 'of'
        * if system is unstable (sys.A has eigenvalues not in left half plane)

    ControlSlycot
        if slycot routine sb03md cannot be found
        if slycot routine sb03od cannot be found

    Notes
    -----
    The return type for 2D arrays depends on the default class set for
    state space operations.  See :func:`~control.use_numpy_matrix`.

    Examples
    --------
    >>> Wc = gram(sys, 'c')
    >>> Wo = gram(sys, 'o')
    >>> Rc = gram(sys, 'cf'), where Wc = Rc' * Rc
    >>> Ro = gram(sys, 'of'), where Wo = Ro' * Ro

    """

    # Check for ss system object
    if not isinstance(sys, statesp.StateSpace):
        raise ValueError("System must be StateSpace!")
    if type not in ['c', 'o', 'cf', 'of']:
        raise ValueError("That type is not supported!")

    # TODO: Check for continuous or discrete, only continuous supported for now
        # if isCont():
        #    dico = 'C'
        # elif isDisc():
        #    dico = 'D'
        # else:
    dico = 'C'

    # TODO: Check system is stable, perhaps a utility in ctrlutil.py
    # or a method of the StateSpace class?
    if np.any(np.linalg.eigvals(sys.A).real >= 0.0):
        raise ValueError("Oops, the system is unstable!")

    if type == 'c' or type == 'o':
        # Compute Gramian by the Slycot routine sb03md
        # make sure Slycot is installed
        if sb03md is None:
            raise ControlSlycot("can't find slycot module 'sb03md'")
        if type == 'c':
            tra = 'T'
            C = -sys.B @ sys.B.T
        elif type == 'o':
            tra = 'N'
            C = -sys.C.T @ sys.C
        n = sys.nstates
        U = np.zeros((n, n))
        A = np.array(sys.A)         # convert to NumPy array for slycot
        X, scale, sep, ferr, w = sb03md(
            n, C, A, U, dico, job='X', fact='N', trana=tra)
        gram = X
        return _ssmatrix(gram)

    elif type == 'cf' or type == 'of':
        # Compute cholesky factored gramian from slycot routine sb03od
        if sb03od is None:
            raise ControlSlycot("can't find slycot module 'sb03od'")
        tra = 'N'
        n = sys.nstates
        Q = np.zeros((n, n))
        A = np.array(sys.A)         # convert to NumPy array for slycot
        if type == 'cf':
            m = sys.B.shape[1]
            B = np.zeros_like(A)
            B[0:m, 0:n] = sys.B.transpose()
            X, scale, w = sb03od(
                n, m, A.transpose(), Q, B, dico, fact='N', trans=tra)
        elif type == 'of':
            m = sys.C.shape[0]
            C = np.zeros_like(A)
            C[0:n, 0:m] = sys.C.transpose()
            X, scale, w = sb03od(
                n, m, A, Q, C.transpose(), dico, fact='N', trans=tra)
        gram = X
        return _ssmatrix(gram)
Example #2
0
def gram(sys,type):
    """Gramian (controllability or observability)

    Parameters
    ----------
    sys: StateSpace
        State-space system to compute Gramian for
    type: String
        Type of desired computation.
        `type` is either 'c' (controllability) or 'o' (observability). To compute the
        Cholesky factors of gramians use 'cf' (controllability) or 'of' (observability)

    Returns
    -------
    gram: array
        Gramian of system

    Raises
    ------
    ValueError
        * if system is not instance of StateSpace class
        * if `type` is not 'c', 'o', 'cf' or 'of'
        * if system is unstable (sys.A has eigenvalues not in left half plane)

    ImportError
        if slycot routine sb03md cannot be found
        if slycot routine sb03od cannot be found

    Examples
    --------
    >>> Wc = gram(sys,'c')
    >>> Wo = gram(sys,'o')
    >>> Rc = gram(sys,'cf'), where Wc=Rc'*Rc
    >>> Ro = gram(sys,'of'), where Wo=Ro'*Ro

    """

    #Check for ss system object
    if not isinstance(sys,statesp.StateSpace):
        raise ValueError("System must be StateSpace!")
    if type not in ['c', 'o', 'cf', 'of']:
        raise ValueError("That type is not supported!")

    #TODO: Check for continous or discrete, only continuous supported right now
        # if isCont():
        #    dico = 'C'
        # elif isDisc():
        #    dico = 'D'
        # else:
    dico = 'C'

    #TODO: Check system is stable, perhaps a utility in ctrlutil.py
        # or a method of the StateSpace class?
    if np.any(np.linalg.eigvals(sys.A).real >= 0.0):
        raise ValueError("Oops, the system is unstable!")

    if type=='c' or type=='o':
        #Compute Gramian by the Slycot routine sb03md
        #make sure Slycot is installed
        try:
            from slycot import sb03md
        except ImportError:
            raise ControlSlycot("can't find slycot module 'sb03md'")
        if type=='c':
            tra = 'T'
            C = -np.dot(sys.B,sys.B.transpose())
        elif type=='o':
            tra = 'N'
            C = -np.dot(sys.C.transpose(),sys.C)
        n = sys.states
        U = np.zeros((n,n))
        A = np.array(sys.A)         # convert to NumPy array for slycot
        X,scale,sep,ferr,w = sb03md(n, C, A, U, dico, job='X', fact='N', trana=tra)
        gram = X
        return gram

    elif type=='cf' or type=='of':
        #Compute cholesky factored gramian from slycot routine sb03od
        try:
            from slycot import sb03od
        except ImportError:
            raise ControlSlycot("can't find slycot module 'sb03od'")
        tra='N'
        n = sys.states
        Q = np.zeros((n,n))
        A = np.array(sys.A)         # convert to NumPy array for slycot
        if type=='cf':
            m = sys.B.shape[1]
            B = np.zeros_like(A)
            B[0:m,0:n] = sys.B.transpose()
            X,scale,w = sb03od(n, m, A.transpose(), Q, B, dico, fact='N', trans=tra)
        elif type=='of':
            m = sys.C.shape[0]
            C = np.zeros_like(A)
            C[0:n,0:m] = sys.C.transpose()
            X,scale,w = sb03od(n, m, A, Q, C.transpose(), dico, fact='N', trans=tra)
        gram = X
        return gram