Skip to content

Commit cc4b5c7

Browse files
slivingstonmdclemen
authored andcommitted
TEST: On Travis CI, fetch Miniconda using HTTPS
Prefer HTTPS, instead of HTTP, to improve security. The URLs are now https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh and https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh for Python 2 and 3, respectively.
1 parent 2461c07 commit cc4b5c7

File tree

3 files changed

+174
-52
lines changed

3 files changed

+174
-52
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ before_install:
2020
- sh -e /etc/init.d/xvfb start
2121
# use miniconda to install numpy/scipy, to avoid lengthy build from source
2222
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
23-
wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
23+
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
2424
else
25-
wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
25+
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
2626
fi
2727
- bash miniconda.sh -b -p $HOME/miniconda
2828
- export PATH="$HOME/miniconda/bin:$PATH"

control/modelsimp.py

Lines changed: 134 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,48 @@ 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+
200231
def balred(sys, orders, method='truncate'):
201232
"""
202233
Balanced reduced order model of sys of a given order.
203234
States are eliminated based on Hankel singular value.
235+
If sys has unstable modes, they are removed, the
236+
balanced realization is done on the stable part, then
237+
reinserted IAW reference below.
238+
239+
Reference: Hsu,C.S., and Hou,D., 1991,
240+
Reducing unstable linear control systems via real Schur transformation.
241+
Electronics Letters, 27, 984-986.
204242
205243
Parameters
206244
----------
@@ -215,23 +253,39 @@ def balred(sys, orders, method='truncate'):
215253
Returns
216254
-------
217255
rsys: StateSpace
218-
A reduced order model
256+
A reduced order model or a list of reduced order models if orders is a list
219257
220258
Raises
221259
------
222260
ValueError
223-
* if `method` is not ``'truncate'``
224-
* if eigenvalues of `sys.A` are not all in left half plane
225-
(`sys` must be stable)
261+
* if `method` is not ``'truncate'`` or ``'matchdc'``
226262
ImportError
227-
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
228267
229268
Examples
230269
--------
231-
>>> rsys = balred(sys, order, method='truncate')
270+
>>> rsys = balred(sys, orders, method='truncate')
232271
233272
"""
273+
if method!='truncate' and method!='matchdc':
274+
raise ValueError("supported methods are 'truncate' or 'matchdc'")
275+
elif method=='truncate':
276+
try:
277+
from slycot import ab09ad
278+
except ImportError:
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+
234286

287+
from scipy.linalg import schur#, cholesky, svd
288+
from numpy.linalg import cholesky, svd
235289
#Check for ss system object, need a utility for this?
236290

237291
#TODO: Check for continous or discrete, only continuous supported right now
@@ -241,34 +295,81 @@ def balred(sys, orders, method='truncate'):
241295
# dico = 'D'
242296
# else:
243297
dico = 'C'
244-
245-
#Check system is stable
246-
D,V = np.linalg.eig(sys.A)
247-
# print D.shape
248-
# print D
249-
for e in D:
250-
if e.real >= 0:
251-
raise ValueError("Oops, the system is unstable!")
252-
253-
if method=='matchdc':
254-
raise ValueError ("MatchDC not yet supported!")
255-
elif method=='truncate':
256-
try:
257-
from slycot import ab09ad
258-
except ImportError:
259-
raise ControlSlycot("can't find slycot subroutine ab09ad")
260-
job = 'B' # balanced (B) or not (N)
261-
equil = 'N' # scale (S) or not (N)
262-
n = np.size(sys.A,0)
263-
m = np.size(sys.B,1)
264-
p = np.size(sys.C,0)
265-
Nr, Ar, Br, Cr, hsv = ab09ad(dico,job,equil,n,m,p,sys.A,sys.B,sys.C,nr=orders,tol=0.0)
266-
267-
rsys = StateSpace(Ar, Br, Cr, sys.D)
298+
job = 'B' # balanced (B) or not (N)
299+
equil = 'N' # scale (S) or not (N)
300+
301+
rsys = [] #empty list for reduced systems
302+
303+
#check if orders is a list or a scalar
304+
try:
305+
order = iter(orders)
306+
except TypeError: #if orders is a scalar
307+
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
315+
316+
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+
353+
rsys.append(StateSpace(Ar, Br, Cr, sys.D))
354+
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))
366+
367+
#if orders was a scalar, just return the single reduced model, not a list
368+
if len(orders) == 1:
369+
return rsys[0]
370+
#if orders was a list/vector, return a list/vector of systems
268371
else:
269-
raise ValueError("Oops, method is not supported!")
270-
271-
return rsys
372+
return rsys
272373

273374
def minreal(sys, tol=None, verbose=True):
274375
'''

control/statefbk.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ def gram(sys,type):
316316
State-space system to compute Gramian for
317317
type: String
318318
Type of desired computation.
319-
`type` is either 'c' (controllability) or 'o' (observability).
319+
`type` is either 'c' (controllability) or 'o' (observability). To compute the
320+
Cholesky factors of gramians use 'cf' (controllability) or 'of' (observability)
320321
321322
Returns
322323
-------
@@ -327,16 +328,19 @@ def gram(sys,type):
327328
------
328329
ValueError
329330
* if system is not instance of StateSpace class
330-
* if `type` is not 'c' or 'o'
331+
* if `type` is not 'c', 'o', 'cf' or 'of'
331332
* if system is unstable (sys.A has eigenvalues not in left half plane)
332333
333334
ImportError
334-
if slycot routin sb03md cannot be found
335+
if slycot routine sb03md cannot be found
336+
if slycot routine sb03od cannot be found
335337
336338
Examples
337339
--------
338340
>>> Wc = gram(sys,'c')
339341
>>> Wo = gram(sys,'o')
342+
>>> Rc = gram(sys,'cf'), where Wc=Rc'*Rc
343+
>>> Ro = gram(sys,'of'), where Wo=Ro'*Ro
340344
341345
"""
342346

@@ -358,25 +362,42 @@ def gram(sys,type):
358362
for e in D:
359363
if e.real >= 0:
360364
raise ValueError("Oops, the system is unstable!")
361-
if type=='c':
365+
if type=='c' or type=='cf':
362366
tra = 'T'
363-
C = -np.dot(sys.B,sys.B.transpose())
364-
elif type=='o':
367+
if type=='c':
368+
C = -np.dot(sys.B,sys.B.transpose())
369+
elif type=='o' or type=='of':
365370
tra = 'N'
366-
C = -np.dot(sys.C.transpose(),sys.C)
371+
if type=='o':
372+
C = -np.dot(sys.C.transpose(),sys.C)
367373
else:
368374
raise ValueError("Oops, neither observable, nor controllable!")
369375

370376
#Compute Gramian by the Slycot routine sb03md
371377
#make sure Slycot is installed
372-
try:
373-
from slycot import sb03md
374-
except ImportError:
375-
raise ControlSlycot("can't find slycot module 'sb03md'")
376-
n = sys.states
377-
U = np.zeros((n,n))
378-
A = np.array(sys.A) # convert to NumPy array for slycot
379-
X,scale,sep,ferr,w = sb03md(n, C, A, U, dico, job='X', fact='N', trana=tra)
380-
gram = X
381-
return gram
378+
if type=='c' or type=='o':
379+
try:
380+
from slycot import sb03md
381+
except ImportError:
382+
raise ControlSlycot("can't find slycot module 'sb03md'")
383+
n = sys.states
384+
U = np.zeros((n,n))
385+
A = np.array(sys.A) # convert to NumPy array for slycot
386+
X,scale,sep,ferr,w = sb03md(n, C, A, U, dico, job='X', fact='N', trana=tra)
387+
gram = X
388+
return gram
389+
elif type=='cf' or type=='of':
390+
try:
391+
from slycot import sb03od
392+
except ImportError:
393+
raise ControlSlycot("can't find slycot module 'sb03od'")
394+
n = sys.states
395+
Q = np.zeros((n,n))
396+
A = np.array(sys.A) # convert to NumPy array for slycot
397+
B = np.zeros_like(A)
398+
B[0:sys.B.shape[0],0:sys.B.shape[1]] = sys.B
399+
m = sys.B.shape[0]
400+
X,scale,w = sb03od(n, m, A, Q, B, dico, fact='N', trans=tra)
401+
gram = X
402+
return gram
382403

0 commit comments

Comments
 (0)