@@ -197,6 +197,37 @@ def modred(sys, ELIM, method='matchdc'):
197
197
rsys = StateSpace (Ar ,Br ,Cr ,Dr )
198
198
return rsys
199
199
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
+
200
231
def balred (sys ,orders ,method = 'truncate' ):
201
232
"""
202
233
Balanced reduced order model of sys of a given order.
@@ -222,31 +253,39 @@ def balred(sys, orders, method='truncate'):
222
253
Returns
223
254
-------
224
255
rsys: StateSpace
225
- A reduced order model
256
+ A reduced order model or a list of reduced order models if orders is a list
226
257
227
258
Raises
228
259
------
229
260
ValueError
230
- * if `method` is not ``'truncate'``
261
+ * if `method` is not ``'truncate'`` or ``'matchdc'``
231
262
ImportError
232
- if slycot routine ab09ad is not found
263
+ if slycot routine ab09ad or ab09bd is not found
264
+
265
+ ValueError
266
+ if there are more unstable modes than any value in orders
233
267
234
268
Examples
235
269
--------
236
270
>>> rsys = balred(sys, orders, method='truncate')
237
271
238
272
"""
239
- if method = ='matchdc' :
240
- raise ValueError ( "MatchDC not yet supported! " )
273
+ if method != 'truncate' and method ! ='matchdc' :
274
+ raise ValueError ( "supported methods are 'truncate' or 'matchdc' " )
241
275
elif method == 'truncate' :
242
276
try :
243
277
from slycot import ab09ad
244
278
except ImportError :
245
- raise ControlSlycot ("can't find slycot subroutine ab09ad" )
246
- else :
247
- raise ValueError ("Oops, method is not supported!" )
279
+ raise ControlSlycot ("can't find slycot subroutine ab09ad" )
280
+ elif method == 'matchdc' :
281
+ try :
282
+ from slycot import ab09bd
283
+ except ImportError :
284
+ raise ControlSlycot ("can't find slycot subroutine ab09bd" )
285
+
248
286
249
- from scipy .linalg import schur
287
+ from scipy .linalg import schur #, cholesky, svd
288
+ from numpy .linalg import cholesky ,svd
250
289
#Check for ss system object, need a utility for this?
251
290
252
291
#TODO: Check for continous or discrete, only continuous supported right now
@@ -256,6 +295,8 @@ def balred(sys, orders, method='truncate'):
256
295
# dico = 'D'
257
296
# else:
258
297
dico = 'C'
298
+ job = 'B' # balanced (B) or not (N)
299
+ equil = 'N' # scale (S) or not (N)
259
300
260
301
rsys = []#empty list for reduced systems
261
302
@@ -278,39 +319,26 @@ def balred(sys, orders, method='truncate'):
278
319
raise ValueError ("System has %i unstable states which is more than ORDER(%i)" % (nn - l ,i ))
279
320
280
321
for i in orders :
281
- if l > 0 :#handles the stable/unstable decomposition if unstable eigenvalues are found
322
+ if ( nn - l ) > 0 :#handles the stable/unstable decomposition if unstable eigenvalues are found, nn - l is the number of ustable eigenvalues
282
323
#Author: M. Clement (mdclemen@eng.ucsd.edu) 2016
283
324
print ("Unstable eigenvalues found, performing stable/unstable decomposition" )
325
+
284
326
rorder = i - (nn - l )
285
- As = np .asmatrix (T )
286
- Bs = V .T * sys .B
287
- Cs = sys .C * V
288
- #from ref 1 eq(1) As = [A_ Ac], Bs = [B_], and Cs = [C_ C+]; _ denotes stable subsystem
289
- # [0 A+] [B+]
290
- A_ = As [0 :l ,0 :l ]
291
- Ac = As [0 :l ,l ::]
292
- Ap = As [l ::,l ::]
293
-
294
- B_ = Bs [0 :l ,:]
295
- Bp = Bs [l ::,:]
296
-
297
- C_ = Cs [:,0 :l ]
298
- Cp = Cs [:,l ::]
299
- #do some more tricky math IAW ref 1 eq(3)
300
- B_tilde = np .bmat ([[B_ ,Ac ]])
301
- D_tilde = np .bmat ([[np .zeros ((rr ,mm )),Cp ]])
327
+ A_ ,B_tilde ,C_ ,D_tilde ,Ap ,Bp ,Cp = stabsep (T ,V ,sys ,l ,mm ,rr )
302
328
303
329
subSys = StateSpace (A_ ,B_tilde ,C_ ,D_tilde )
304
-
305
- job = 'B' # balanced (B) or not (N)
306
- equil = 'N' # scale (S) or not (N)
307
330
n = np .size (subSys .A ,0 )
308
331
m = np .size (subSys .B ,1 )
309
332
p = np .size (subSys .C ,0 )
310
- Nr ,Ar ,Br ,Cr ,hsv = ab09ad (dico ,job ,equil ,n ,m ,p ,subSys .A ,subSys .B ,subSys .C ,nr = rorder ,tol = 0.0 )
311
333
312
- rsubSys = StateSpace (Ar ,Br ,Cr ,np .zeros ((p ,m )))
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 )))
313
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
+
314
342
A_r = rsubSys .A
315
343
#IAW ref 1 eq(4) B^{tilde}_r = [B_r, Acr]
316
344
B_r = rsubSys .B [:,0 :mm ]
@@ -324,15 +352,17 @@ def balred(sys, orders, method='truncate'):
324
352
325
353
rsys .append (StateSpace (Ar ,Br ,Cr ,sys .D ))
326
354
327
- else :
328
- job = 'B' # balanced (B) or not (N)
329
- equil = 'N' # scale (S) or not (N)
355
+ else :#stable system branch
330
356
n = np .size (sys .A ,0 )
331
357
m = np .size (sys .B ,1 )
332
358
p = np .size (sys .C ,0 )
333
- Nr ,Ar ,Br ,Cr ,hsv = ab09ad (dico ,job ,equil ,n ,m ,p ,sys .A ,sys .B ,sys .C ,nr = i ,tol = 0.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 ))
334
362
335
- rsys .append (StateSpace (Ar ,Br ,Cr ,sys .D ))
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 ))
336
366
337
367
#if orders was a scalar, just return the single reduced model, not a list
338
368
if len (orders )== 1 :