Skip to content

Commit 1d1c289

Browse files
committed
fix up rounding errors and matrix/array
1 parent 07cedd8 commit 1d1c289

2 files changed

Lines changed: 37 additions & 28 deletions

File tree

control/canonical.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
__all__ = ['canonical_form', 'reachable_form', 'observable_form', 'modal_form',
1818
'similarity_transform', 'bdschur']
1919

20+
2021
def canonical_form(xsys, form='reachable'):
2122
"""Convert a system into canonical form
2223
@@ -41,16 +42,16 @@ def canonical_form(xsys, form='reachable'):
4142
--------
4243
>>> Gs = ct.tf2ss([1], [1, 3, 2])
4344
>>> Gc, T = ct.canonical_form(Gs) # default reachable
44-
>>> Gc.B
45+
>>> Gc.B.round()
4546
array([[1.],
4647
[0.]])
4748
4849
>>> Gc, T = ct.canonical_form(Gs, 'observable')
49-
>>> Gc.C
50+
>>> Gc.C.round()
5051
array([[1., 0.]])
5152
5253
>>> Gc, T = ct.canonical_form(Gs, 'modal')
53-
>>> Gc.A
54+
>>> Gc.A.round() # doctest: +SKIP
5455
array([[-2., 0.],
5556
[ 0., -1.]])
5657
@@ -88,9 +89,9 @@ def reachable_form(xsys):
8889
--------
8990
>>> Gs = ct.tf2ss([1], [1, 3, 2])
9091
>>> Gc, T = ct.reachable_form(Gs) # default reachable
91-
>>> Gc.B # doctest: +SKIP
92-
matrix([[1.],
93-
[0.]])
92+
>>> Gc.B.round()
93+
array([[1.],
94+
[0.]])
9495
9596
"""
9697
# Check to make sure we have a SISO system
@@ -151,8 +152,8 @@ def observable_form(xsys):
151152
--------
152153
>>> Gs = ct.tf2ss([1], [1, 3, 2])
153154
>>> Gc, T = ct.observable_form(Gs)
154-
>>> Gc.C # doctest: +SKIP
155-
matrix([[1., 0.]])
155+
>>> Gc.C.round()
156+
array([[1., 0.]])
156157
157158
"""
158159
# Check to make sure we have a SISO system
@@ -216,15 +217,15 @@ def similarity_transform(xsys, T, timescale=1, inverse=False):
216217
Examples
217218
--------
218219
>>> Gs = ct.tf2ss([1], [1, 3, 2])
219-
>>> Gs.A # doctest: +SKIP
220-
matrix([[-3., -2.],
221-
[ 1., 0.]])
220+
>>> Gs.A.round()
221+
array([[-3., -2.],
222+
[ 1., 0.]])
222223
223-
>>> T = np.array([[0,1],[1,0]])
224+
>>> T = np.array([[0, 1], [1, 0]])
224225
>>> Gt = ct.similarity_transform(Gs, T)
225-
>>> Gt.A # doctest: +SKIP
226-
matrix([[ 0., 1.],
227-
[-2., -3.]])
226+
>>> Gt.A.round()
227+
array([[ 0., 1.],
228+
[-2., -3.]])
228229
229230
"""
230231
# Create a new system, starting with a copy of the old one
@@ -293,7 +294,8 @@ def _bdschur_condmax_search(aschur, tschur, condmax):
293294
294295
Iterates mb03rd with different pmax values until:
295296
- result is non-defective;
296-
- or condition number of similarity transform is unchanging despite large pmax;
297+
- or condition number of similarity transform is unchanging
298+
despite large pmax;
297299
- or condition number of similarity transform is close to condmax.
298300
299301
Parameters
@@ -332,22 +334,25 @@ def _bdschur_condmax_search(aschur, tschur, condmax):
332334

333335
# get lower bound; try condmax ** 0.5 first
334336
pmaxlower = condmax ** 0.5
335-
amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0], aschur, tschur, pmax=pmaxlower)
337+
amodal, tmodal, blksizes, eigvals = mb03rd(
338+
aschur.shape[0], aschur, tschur, pmax=pmaxlower)
336339
if np.linalg.cond(tmodal) <= condmax:
337340
reslower = amodal, tmodal, blksizes, eigvals
338341
else:
339342
pmaxlower = 1.0
340-
amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0], aschur, tschur, pmax=pmaxlower)
343+
amodal, tmodal, blksizes, eigvals = mb03rd(
344+
aschur.shape[0], aschur, tschur, pmax=pmaxlower)
341345
cond = np.linalg.cond(tmodal)
342346
if cond > condmax:
343-
msg = 'minimum cond={} > condmax={}; try increasing condmax'.format(cond, condmax)
347+
msg = f"minimum {cond=} > {condmax=}; try increasing condmax"
344348
raise RuntimeError(msg)
345349

346350
pmax = pmaxlower
347351

348352
# phase 1: search for upper bound on pmax
349353
for i in range(50):
350-
amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0], aschur, tschur, pmax=pmax)
354+
amodal, tmodal, blksizes, eigvals = mb03rd(
355+
aschur.shape[0], aschur, tschur, pmax=pmax)
351356
cond = np.linalg.cond(tmodal)
352357
if cond < condmax:
353358
pmaxlower = pmax
@@ -368,7 +373,8 @@ def _bdschur_condmax_search(aschur, tschur, condmax):
368373
# phase 2: bisection search
369374
for i in range(50):
370375
pmax = (pmaxlower * pmaxupper) ** 0.5
371-
amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0], aschur, tschur, pmax=pmax)
376+
amodal, tmodal, blksizes, eigvals = mb03rd(
377+
aschur.shape[0], aschur, tschur, pmax=pmax)
372378
cond = np.linalg.cond(tmodal)
373379

374380
if cond < condmax:
@@ -440,7 +446,8 @@ def bdschur(a, condmax=None, sort=None):
440446
return a.copy(), np.eye(a.shape[1], a.shape[0]), np.array([])
441447

442448
aschur, tschur = schur(a)
443-
amodal, tmodal, blksizes, eigvals = _bdschur_condmax_search(aschur, tschur, condmax)
449+
amodal, tmodal, blksizes, eigvals = _bdschur_condmax_search(
450+
aschur, tschur, condmax)
444451

445452
if sort in ('continuous', 'discrete'):
446453

@@ -484,9 +491,11 @@ def modal_form(xsys, condmax=None, sort=False):
484491
xsys : StateSpace object
485492
System to be transformed, with state `x`
486493
condmax : None or float, optional
487-
An upper bound on individual transformations. If None, use `bdschur` default.
494+
An upper bound on individual transformations. If None, use
495+
`bdschur` default.
488496
sort : bool, optional
489-
If False (default), Schur blocks will not be sorted. See `bdschur` for sort order.
497+
If False (default), Schur blocks will not be sorted. See `bdschur`
498+
for sort order.
490499
491500
Returns
492501
-------
@@ -499,9 +508,9 @@ def modal_form(xsys, condmax=None, sort=False):
499508
--------
500509
>>> Gs = ct.tf2ss([1], [1, 3, 2])
501510
>>> Gc, T = ct.modal_form(Gs) # default reachable
502-
>>> Gc.A # doctest: +SKIP
503-
matrix([[-2., 0.],
504-
[ 0., -1.]])
511+
>>> Gc.A.round() # doctest: +SKIP
512+
array([[-2., 0.],
513+
[ 0., -1.]])
505514
506515
"""
507516

control/descfcn.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def describing_function_plot(
249249
>>> H_simple = ct.tf([8], [1, 2, 2, 1])
250250
>>> F_saturation = ct.saturation_nonlinearity(1)
251251
>>> amp = np.linspace(1, 4, 10)
252-
>>> ct.describing_function_plot(H_simple, F_saturation, amp)
252+
>>> ct.describing_function_plot(H_simple, F_saturation, amp) # doctest: +SKIP
253253
[(3.343844998258643, 1.4142293090899216)]
254254
255255
"""

0 commit comments

Comments
 (0)