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)
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