5050from .statesp import StateSpace
5151from .statefbk import gram
5252
53- __all__ = ['hsvd' , 'balred' , 'modred' , 'era' , 'markov' , 'minreal' ]
53+ __all__ = ['hsvd' , 'balred' , 'modred' , 'era' , 'markov' , 'minreal' , ]
5454
5555# Hankel Singular Value Decomposition
5656# The following returns the Hankel singular values, which are singular values
@@ -197,38 +197,7 @@ def modred(sys, ELIM, method='matchdc'):
197197 rsys = StateSpace (Ar ,Br ,Cr ,Dr )
198198 return rsys
199199
200- def stabsep (T_schur , Z_schur , sys , ldim , no_in , no_out ):
201- """
202- Performs stable/unstabe decomposition of sys after Schur forms have been computed for system matrix.
203-
204- Reference: Hsu,C.S., and Hou,D., 1991,
205- Reducing unstable linear control systems via real Schur transformation.
206- Electronics Letters, 27, 984-986.
207-
208- """
209- #Author: M. Clement (mdclemen@eng.ucsd.edu) 2016
210- As = np .asmatrix (T_schur )
211- Bs = Z_schur .T * sys .B
212- Cs = sys .C * Z_schur
213- #from ref 1 eq(1) As = [A_ Ac], Bs = [B_], and Cs = [C_ C+]; _ denotes stable subsystem
214- # [0 A+] [B+]
215- A_ = As [0 :ldim ,0 :ldim ]
216- Ac = As [0 :ldim ,ldim ::]
217- Ap = As [ldim ::,ldim ::]
218-
219- B_ = Bs [0 :ldim ,:]
220- Bp = Bs [ldim ::,:]
221-
222- C_ = Cs [:,0 :ldim ]
223- Cp = Cs [:,ldim ::]
224- #do some more tricky math IAW ref 1 eq(3)
225- B_tilde = np .bmat ([[B_ , Ac ]])
226- D_tilde = np .bmat ([[np .zeros ((no_out , no_in )), Cp ]])
227-
228- return A_ , B_tilde , C_ , D_tilde , Ap , Bp , Cp
229-
230-
231- def balred (sys , orders , method = 'truncate' ):
200+ def balred (sys , orders , method = 'truncate' , alpha = None ):
232201 """
233202 Balanced reduced order model of sys of a given order.
234203 States are eliminated based on Hankel singular value.
@@ -249,6 +218,13 @@ def balred(sys, orders, method='truncate'):
249218 of systems)
250219 method: string
251220 Method of removing states, either ``'truncate'`` or ``'matchdc'``.
221+ alpha: float
222+ Specifies the alpha-stability boundary for the eigenvalues
223+ of the state dynamics matrix A. For a continuous-time
224+ system, alpha <= 0 is the boundary value for the real parts
225+ of eigenvalues, while for a discrete-time system, 0 <= alpha <= 1
226+ represents the boundary value for the moduli of eigenvalues.
227+ The alpha-stability domain does not include the boundary.
252228
253229 Returns
254230 -------
@@ -260,7 +236,7 @@ def balred(sys, orders, method='truncate'):
260236 ValueError
261237 * if `method` is not ``'truncate'`` or ``'matchdc'``
262238 ImportError
263- if slycot routine ab09ad or ab09bd is not found
239+ if slycot routine ab09md or ab09nd is not found
264240
265241 ValueError
266242 if there are more unstable modes than any value in orders
@@ -274,18 +250,15 @@ def balred(sys, orders, method='truncate'):
274250 raise ValueError ("supported methods are 'truncate' or 'matchdc'" )
275251 elif method == 'truncate' :
276252 try :
277- from slycot import ab09ad
253+ from slycot import ab09md
278254 except ImportError :
279- raise ControlSlycot ("can't find slycot subroutine ab09ad " )
255+ raise ControlSlycot ("can't find slycot subroutine ab09md " )
280256 elif method == 'matchdc' :
281257 try :
282- from slycot import ab09bd
258+ from slycot import ab09nd
283259 except ImportError :
284- raise ControlSlycot ("can't find slycot subroutine ab09bd" )
285-
260+ raise ControlSlycot ("can't find slycot subroutine ab09nd" )
286261
287- from scipy .linalg import schur #, cholesky, svd
288- from numpy .linalg import cholesky , svd
289262 #Check for ss system object, need a utility for this?
290263
291264 #TODO: Check for continous or discrete, only continuous supported right now
@@ -297,6 +270,11 @@ def balred(sys, orders, method='truncate'):
297270 dico = 'C'
298271 job = 'B' # balanced (B) or not (N)
299272 equil = 'N' # scale (S) or not (N)
273+ if alpha is None :
274+ if dico == 'C' :
275+ alpha = 0.
276+ elif dico == 'D' :
277+ alpha = 1.
300278
301279 rsys = [] #empty list for reduced systems
302280
@@ -305,64 +283,18 @@ def balred(sys, orders, method='truncate'):
305283 order = iter (orders )
306284 except TypeError : #if orders is a scalar
307285 orders = [orders ]
308-
309- #first get original system order
310- nn = sys .A .shape [0 ] #no. of states
311- mm = sys .B .shape [1 ] #no. of inputs
312- rr = sys .C .shape [0 ] #no. of outputs
313- #first do the schur decomposition
314- T , V , l = schur (sys .A , sort = 'lhp' ) #l will contain the number of eigenvalues in the open left half plane, i.e. no. of stable eigenvalues
315286
316287 for i in orders :
317- rorder = i - (nn - l )
318- if rorder <= 0 :
319- raise ValueError ("System has %i unstable states which is more than ORDER(%i)" % (nn - l , i ))
320-
321- for i in orders :
322- if (nn - l ) > 0 : #handles the stable/unstable decomposition if unstable eigenvalues are found, nn - l is the number of ustable eigenvalues
323- #Author: M. Clement (mdclemen@eng.ucsd.edu) 2016
324- print ("Unstable eigenvalues found, performing stable/unstable decomposition" )
325-
326- rorder = i - (nn - l )
327- A_ , B_tilde , C_ , D_tilde , Ap , Bp , Cp = stabsep (T , V , sys , l , mm , rr )
328-
329- subSys = StateSpace (A_ , B_tilde , C_ , D_tilde )
330- n = np .size (subSys .A ,0 )
331- m = np .size (subSys .B ,1 )
332- p = np .size (subSys .C ,0 )
333-
334- if method == 'truncate' :
335- Nr , Ar , Br , Cr , hsv = ab09ad (dico ,job ,equil ,n ,m ,p ,subSys .A ,subSys .B ,subSys .C ,nr = rorder ,tol = 0.0 )
336- rsubSys = StateSpace (Ar , Br , Cr , np .zeros ((p ,m )))
337-
338- elif method == 'matchdc' :
339- Nr , Ar , Br , Cr , Dr , hsv = ab09bd (dico ,job ,equil ,n ,m ,p ,subSys .A ,subSys .B ,subSys .C ,subSys .D ,nr = rorder ,tol1 = 0.0 ,tol2 = 0.0 )
340- rsubSys = StateSpace (Ar , Br , Cr , Dr )
341-
342- A_r = rsubSys .A
343- #IAW ref 1 eq(4) B^{tilde}_r = [B_r, Acr]
344- B_r = rsubSys .B [:,0 :mm ]
345- Acr = rsubSys .B [:,mm :mm + (nn - l )]
346- C_r = rsubSys .C
347-
348- #now put the unstable subsystem back in
349- Ar = np .bmat ([[A_r , Acr ], [np .zeros ((nn - l ,rorder )), Ap ]])
350- Br = np .bmat ([[B_r ], [Bp ]])
351- Cr = np .bmat ([[C_r , Cp ]])
352-
288+ n = np .size (sys .A ,0 )
289+ m = np .size (sys .B ,1 )
290+ p = np .size (sys .C ,0 )
291+ if method == 'truncate' :
292+ Nr , Ar , Br , Cr , Ns , hsv = ab09md (dico ,job ,equil ,n ,m ,p ,sys .A ,sys .B ,sys .C ,alpha = alpha ,nr = i ,tol = 0.0 )
353293 rsys .append (StateSpace (Ar , Br , Cr , sys .D ))
354294
355- else : #stable system branch
356- n = np .size (sys .A ,0 )
357- m = np .size (sys .B ,1 )
358- p = np .size (sys .C ,0 )
359- if method == 'truncate' :
360- Nr , Ar , Br , Cr , hsv = ab09ad (dico ,job ,equil ,n ,m ,p ,sys .A ,sys .B ,sys .C ,nr = i ,tol = 0.0 )
361- rsys .append (StateSpace (Ar , Br , Cr , sys .D ))
362-
363- elif method == 'matchdc' :
364- Nr , Ar , Br , Cr , Dr , hsv = ab09bd (dico ,job ,equil ,n ,m ,p ,sys .A ,sys .B ,sys .C ,sys .D ,nr = rorder ,tol1 = 0.0 ,tol2 = 0.0 )
365- rsys .append (StateSpace (Ar , Br , Cr , Dr ))
295+ elif method == 'matchdc' :
296+ Nr , Ar , Br , Cr , Dr , Ns , hsv = ab09nd (dico ,job ,equil ,n ,m ,p ,sys .A ,sys .B ,sys .C ,sys .D ,alpha = alpha ,nr = i ,tol1 = 0.0 ,tol2 = 0.0 )
297+ rsys .append (StateSpace (Ar , Br , Cr , Dr ))
366298
367299 #if orders was a scalar, just return the single reduced model, not a list
368300 if len (orders ) == 1 :
0 commit comments