Skip to content

Commit 6099374

Browse files
committed
Merge remote-tracking branch 'upstream/master' into sisotool_final
2 parents 5ced53a + ace1683 commit 6099374

22 files changed

Lines changed: 689 additions & 543 deletions

.travis.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
sudo: false
22
language: python
3+
dist: xenial
4+
5+
services:
6+
- xvfb
37

48
cache:
59
apt: true
@@ -9,8 +13,8 @@ cache:
913
- $HOME/.local
1014

1115
python:
16+
- "3.7"
1217
- "3.6"
13-
- "3.5"
1418
- "2.7"
1519

1620
# Test against multiple version of SciPy, with and without slycot
@@ -32,9 +36,6 @@ before_install:
3236
sudo apt-get update -qq;
3337
sudo apt-get install gfortran;
3438
fi
35-
# Install display manager to allow testing of plotting functions
36-
- export DISPLAY=:99.0
37-
- sh -e /etc/init.d/xvfb start
3839
# use miniconda to install numpy/scipy, to avoid lengthy build from source
3940
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
4041
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;

README.rst

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,32 @@ https://github.com/python-control/Slycot
4646
Installation
4747
============
4848

49-
The package may be installed using pip, conda, or distutils.
49+
Conda and conda-forge
50+
---------------------
51+
52+
The easiest way to get started with the Control Systems library is
53+
using `Conda <https://conda.io>`_.
54+
55+
The Control Systems library has been packages for the `conda-forge
56+
<https://conda-forge.org>`_ Conda channel, and as of Slycot version
57+
0.3.4, binaries for that package are available for 64-bit Windows,
58+
OSX, and Linux.
59+
60+
To install both the Control Systems library and Slycot in an existing
61+
conda environment, run::
62+
63+
conda install -c conda-forge control slycot
5064

5165
Pip
5266
---
5367

5468
To install using pip::
5569

56-
pip install slycot # optional
70+
pip install slycot # optional; see below
5771
pip install control
5872

59-
conda-forge
60-
-----------
61-
62-
Binaries are available from conda-forge for selected platforms (Linux and
63-
MacOS). Install using
64-
65-
conda install -c conda-forge control
73+
If you install Slycot using pip you'll need a development environment
74+
(e.g., Python development files, C and Fortran compilers).
6675

6776
Distutils
6877
---------

control/lti.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ def isdtime(self, strict=False):
5454
5555
Parameters
5656
----------
57-
strict: bool (default = False)
58-
If strict is True, make sure that timebase is not None
57+
strict: bool, optional
58+
If strict is True, make sure that timebase is not None. Default
59+
is False.
5960
"""
6061

6162
# If no timebase is given, answer depends on strict flag
@@ -73,8 +74,9 @@ def isctime(self, strict=False):
7374
----------
7475
sys : LTI system
7576
System to be checked
76-
strict: bool (default = False)
77-
If strict is True, make sure that timebase is not None
77+
strict: bool, optional
78+
If strict is True, make sure that timebase is not None. Default
79+
is False.
7880
"""
7981
# If no timebase is given, answer depends on strict flag
8082
if self.dt is None:

control/modelsimp.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,12 @@ def modred(sys, ELIM, method='matchdc'):
125125
Raises
126126
------
127127
ValueError
128-
- if `method` is not either ``'matchdc'`` or ``'truncate'``
129-
- if eigenvalues of `sys.A` are not all in left half plane
130-
(`sys` must be stable)
128+
Raised under the following conditions:
129+
130+
* if `method` is not either ``'matchdc'`` or ``'truncate'``
131+
132+
* if eigenvalues of `sys.A` are not all in left half plane
133+
(`sys` must be stable)
131134
132135
Examples
133136
--------

control/phaseplot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def phase_plot(odefun, X=None, Y=None, scale=1, X0=None, T=None,
118118
119119
See also
120120
--------
121-
box_grid(X, Y): construct box-shaped grid of initial conditions
121+
box_grid : construct box-shaped grid of initial conditions
122122
123123
Examples
124124
--------

control/robust.py

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
from .statesp import StateSpace
4646
from .statefbk import *
4747

48-
def h2syn(P,nmeas,ncon):
48+
49+
def h2syn(P, nmeas, ncon):
4950
"""H_2 control synthesis for plant P.
5051
5152
Parameters
@@ -72,25 +73,25 @@ def h2syn(P,nmeas,ncon):
7273
>>> K = h2syn(P,nmeas,ncon)
7374
7475
"""
75-
#Check for ss system object, need a utility for this?
76-
77-
#TODO: Check for continous or discrete, only continuous supported right now
78-
# if isCont():
79-
# dico = 'C'
80-
# elif isDisc():
81-
# dico = 'D'
82-
# else:
76+
# Check for ss system object, need a utility for this?
77+
78+
# TODO: Check for continous or discrete, only continuous supported right now
79+
# if isCont():
80+
# dico = 'C'
81+
# elif isDisc():
82+
# dico = 'D'
83+
# else:
8384
dico = 'C'
8485

8586
try:
8687
from slycot import sb10hd
8788
except ImportError:
8889
raise ControlSlycot("can't find slycot subroutine sb10hd")
8990

90-
n = np.size(P.A,0)
91-
m = np.size(P.B,1)
92-
np_ = np.size(P.C,0)
93-
out = sb10hd(n,m,np_,ncon,nmeas,P.A,P.B,P.C,P.D)
91+
n = np.size(P.A, 0)
92+
m = np.size(P.B, 1)
93+
np_ = np.size(P.C, 0)
94+
out = sb10hd(n, m, np_, ncon, nmeas, P.A, P.B, P.C, P.D)
9495
Ak = out[0]
9596
Bk = out[1]
9697
Ck = out[2]
@@ -100,7 +101,8 @@ def h2syn(P,nmeas,ncon):
100101

101102
return K
102103

103-
def hinfsyn(P,nmeas,ncon):
104+
105+
def hinfsyn(P, nmeas, ncon):
104106
"""H_{inf} control synthesis for plant P.
105107
106108
Parameters
@@ -136,26 +138,26 @@ def hinfsyn(P,nmeas,ncon):
136138
137139
"""
138140

139-
#Check for ss system object, need a utility for this?
141+
# Check for ss system object, need a utility for this?
140142

141-
#TODO: Check for continous or discrete, only continuous supported right now
142-
# if isCont():
143-
# dico = 'C'
144-
# elif isDisc():
145-
# dico = 'D'
146-
# else:
143+
# TODO: Check for continous or discrete, only continuous supported right now
144+
# if isCont():
145+
# dico = 'C'
146+
# elif isDisc():
147+
# dico = 'D'
148+
# else:
147149
dico = 'C'
148150

149151
try:
150152
from slycot import sb10ad
151153
except ImportError:
152154
raise ControlSlycot("can't find slycot subroutine sb10ad")
153155

154-
n = np.size(P.A,0)
155-
m = np.size(P.B,1)
156-
np_ = np.size(P.C,0)
156+
n = np.size(P.A, 0)
157+
m = np.size(P.B, 1)
158+
np_ = np.size(P.C, 0)
157159
gamma = 1.e100
158-
out = sb10ad(n,m,np_,ncon,nmeas,gamma,P.A,P.B,P.C,P.D)
160+
out = sb10ad(n, m, np_, ncon, nmeas, gamma, P.A, P.B, P.C, P.D)
159161
gam = out[0]
160162
Ak = out[1]
161163
Bk = out[2]
@@ -202,21 +204,21 @@ def _size_as_needed(w, wname, n):
202204
"""
203205
from . import append, ss
204206
if w is not None:
205-
if not isinstance(w,StateSpace):
207+
if not isinstance(w, StateSpace):
206208
w = ss(w)
207-
if 1==w.inputs and 1==w.outputs:
208-
w = append(*(w,)*n)
209+
if 1 == w.inputs and 1 == w.outputs:
210+
w = append(*(w,) * n)
209211
else:
210212
if w.inputs != n:
211-
msg=("{}: weighting function has {} inputs, expected {}".
212-
format(wname,w.inputs,n))
213+
msg = ("{}: weighting function has {} inputs, expected {}".
214+
format(wname, w.inputs, n))
213215
raise ValueError(msg)
214216
else:
215-
w = ss([],[],[],[])
217+
w = ss([], [], [], [])
216218
return w
217219

218220

219-
def augw(g,w1=None,w2=None,w3=None):
221+
def augw(g, w1=None, w2=None, w3=None):
220222
"""Augment plant for mixed sensitivity problem.
221223
222224
Parameters
@@ -254,12 +256,12 @@ def augw(g,w1=None,w2=None,w3=None):
254256
ny = g.outputs
255257
nu = g.inputs
256258

257-
w1,w2,w3 = [_size_as_needed(w,wname,n)
258-
for w,wname,n in zip((w1,w2,w3),
259-
('w1','w2','w3'),
260-
(ny,nu,ny))]
259+
w1, w2, w3 = [_size_as_needed(w, wname, n)
260+
for w, wname, n in zip((w1, w2, w3),
261+
('w1', 'w2', 'w3'),
262+
(ny, nu, ny))]
261263

262-
if not isinstance(g,StateSpace):
264+
if not isinstance(g, StateSpace):
263265
g = ss(g)
264266

265267
# w u
@@ -270,11 +272,11 @@ def augw(g,w1=None,w2=None,w3=None):
270272
# v [ I | -g ]
271273

272274
# error summer: inputs are -y and r=w
273-
Ie = ss([],[],[],np.eye(ny))
275+
Ie = ss([], [], [], np.eye(ny))
274276
# control: needed to "distribute" control input
275-
Iu = ss([],[],[],np.eye(nu))
277+
Iu = ss([], [], [], np.eye(nu))
276278

277-
sysall = append(w1,w2,w3,Ie,g,Iu)
279+
sysall = append(w1, w2, w3, Ie, g, Iu)
278280

279281
niw1 = w1.inputs
280282
niw2 = w2.inputs
@@ -284,43 +286,45 @@ def augw(g,w1=None,w2=None,w3=None):
284286
now2 = w2.outputs
285287
now3 = w3.outputs
286288

287-
q = np.zeros((niw1+niw2+niw3+ny+nu,2))
288-
q[:,0] = np.arange(1,q.shape[0]+1)
289+
q = np.zeros((niw1 + niw2 + niw3 + ny + nu, 2))
290+
q[:, 0] = np.arange(1, q.shape[0] + 1)
289291

290292
# Ie -> w1
291-
q[:niw1,1] = np.arange(1+now1+now2+now3,
292-
1+now1+now2+now3+niw1)
293+
q[:niw1, 1] = np.arange(1 + now1 + now2 + now3,
294+
1 + now1 + now2 + now3 + niw1)
293295

294296
# Iu -> w2
295-
q[niw1:niw1+niw2,1] = np.arange(1+now1+now2+now3+2*ny,
296-
1+now1+now2+now3+2*ny+niw2)
297+
q[niw1:niw1 + niw2, 1] = np.arange(1 + now1 + now2 + now3 + 2 * ny,
298+
1 + now1 + now2 + now3 + 2 * ny + niw2)
297299

298300
# y -> w3
299-
q[niw1+niw2:niw1+niw2+niw3,1] = np.arange(1+now1+now2+now3+ny,
300-
1+now1+now2+now3+ny+niw3)
301+
q[niw1 + niw2:niw1 + niw2 + niw3, 1] = np.arange(1 + now1 + now2 + now3 + ny,
302+
1 + now1 + now2 + now3 + ny + niw3)
301303

302304
# -y -> Iy; note the leading -
303-
q[niw1+niw2+niw3:niw1+niw2+niw3+ny,1] = -np.arange(1+now1+now2+now3+ny,
304-
1+now1+now2+now3+2*ny)
305+
q[niw1 + niw2 + niw3:niw1 + niw2 + niw3 + ny, 1] = -np.arange(1 + now1 + now2 + now3 + ny,
306+
1 + now1 + now2 + now3 + 2 * ny)
305307

306308
# Iu -> G
307-
q[niw1+niw2+niw3+ny:niw1+niw2+niw3+ny+nu,1] = np.arange(1+now1+now2+now3+2*ny,
308-
1+now1+now2+now3+2*ny+nu)
309+
q[niw1 + niw2 + niw3 + ny:niw1 + niw2 + niw3 + ny + nu, 1] = np.arange(
310+
1 + now1 + now2 + now3 + 2 * ny,
311+
1 + now1 + now2 + now3 + 2 * ny + nu)
309312

310313
# input indices: to Ie and Iu
311-
ii = np.hstack((np.arange(1+now1+now2+now3,
312-
1+now1+now2+now3+ny),
313-
np.arange(1+now1+now2+now3+ny+nu,
314-
1+now1+now2+now3+ny+nu+nu)))
314+
ii = np.hstack((np.arange(1 + now1 + now2 + now3,
315+
1 + now1 + now2 + now3 + ny),
316+
np.arange(1 + now1 + now2 + now3 + ny + nu,
317+
1 + now1 + now2 + now3 + ny + nu + nu)))
315318

316319
# output indices
317-
oi = np.arange(1,1+now1+now2+now3+ny)
320+
oi = np.arange(1, 1 + now1 + now2 + now3 + ny)
318321

319-
p = connect(sysall,q,ii,oi)
322+
p = connect(sysall, q, ii, oi)
320323

321324
return p
322325

323-
def mixsyn(g,w1=None,w2=None,w3=None):
326+
327+
def mixsyn(g, w1=None, w2=None, w3=None):
324328
"""Mixed-sensitivity H-infinity synthesis.
325329
326330
mixsyn(g,w1,w2,w3) -> k,cl,info
@@ -356,8 +360,8 @@ def mixsyn(g,w1=None,w2=None,w3=None):
356360
"""
357361
nmeas = g.outputs
358362
ncon = g.inputs
359-
p = augw(g,w1,w2,w3)
363+
p = augw(g, w1, w2, w3)
360364

361-
k,cl,gamma,rcond=hinfsyn(p,nmeas,ncon)
362-
info = gamma,rcond
363-
return k,cl,info
365+
k, cl, gamma, rcond = hinfsyn(p, nmeas, ncon)
366+
info = gamma, rcond
367+
return k, cl, info

control/statefbk.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ def lqr(*args, **keywords):
368368

369369
return K, S, E
370370

371-
def ctrb(A,B):
371+
def ctrb(A, B):
372372
"""Controllabilty matrix
373373
374374
Parameters
@@ -391,10 +391,9 @@ def ctrb(A,B):
391391
amat = np.mat(A)
392392
bmat = np.mat(B)
393393
n = np.shape(amat)[0]
394+
394395
# Construct the controllability matrix
395-
ctrb = bmat
396-
for i in range(1, n):
397-
ctrb = np.hstack((ctrb, amat**i*bmat))
396+
ctrb = np.hstack([bmat] + [amat**i*bmat for i in range(1, n)])
398397
return ctrb
399398

400399
def obsv(A, C):
@@ -421,10 +420,8 @@ def obsv(A, C):
421420
cmat = np.mat(C)
422421
n = np.shape(amat)[0]
423422

424-
# Construct the controllability matrix
425-
obsv = cmat
426-
for i in range(1, n):
427-
obsv = np.vstack((obsv, cmat*amat**i))
423+
# Construct the observability matrix
424+
obsv = np.vstack([cmat] + [cmat*amat**i for i in range(1, n)])
428425
return obsv
429426

430427
def gram(sys,type):

0 commit comments

Comments
 (0)