Skip to content

Commit 7076fac

Browse files
committed
2 parents 4c79cb2 + 8356044 commit 7076fac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2651
-1511
lines changed

.github/workflows/python-package-conda.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
strategy:
1111
max-parallel: 5
1212
matrix:
13-
python-version: [3.6, 3.9]
13+
python-version: [3.7, 3.9]
1414
slycot: ["", "conda"]
1515
array-and-matrix: [0]
1616
include:

.travis.yml

Lines changed: 0 additions & 112 deletions
This file was deleted.

control/bdalg.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@
6262

6363

6464
def series(sys1, *sysn):
65-
"""Return the series connection (sysn \\* ... \\*) sys2 \\* sys1
65+
r"""series(sys1, sys2, [..., sysn])
66+
67+
Return the series connection (`sysn` \* ...\ \*) `sys2` \* `sys1`.
6668
6769
Parameters
6870
----------
@@ -107,8 +109,9 @@ def series(sys1, *sysn):
107109

108110

109111
def parallel(sys1, *sysn):
110-
"""
111-
Return the parallel connection sys1 + sys2 (+ ... + sysn)
112+
r"""parallel(sys1, sys2, [..., sysn])
113+
114+
Return the parallel connection `sys1` + `sys2` (+ ...\ + `sysn`).
112115
113116
Parameters
114117
----------
@@ -252,9 +255,9 @@ def feedback(sys1, sys2=1, sign=-1):
252255
return sys1.feedback(sys2, sign)
253256

254257
def append(*sys):
255-
"""append(sys1, sys2, ..., sysn)
258+
"""append(sys1, sys2, [..., sysn])
256259
257-
Group models by appending their inputs and outputs
260+
Group models by appending their inputs and outputs.
258261
259262
Forms an augmented system model, and appends the inputs and
260263
outputs together. The system type will be the type of the first

control/canonical.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import numpy as np
1010

11-
from numpy import zeros, zeros_like, shape, poly, iscomplex, vstack, hstack, dot, \
11+
from numpy import zeros, zeros_like, shape, poly, iscomplex, vstack, hstack, \
1212
transpose, empty, finfo, float64
1313
from numpy.linalg import solve, matrix_rank, eig
1414

@@ -149,7 +149,7 @@ def observable_form(xsys):
149149
raise ValueError("Transformation matrix singular to working precision.")
150150

151151
# Finally, compute the output matrix
152-
zsys.B = Tzx.dot(xsys.B)
152+
zsys.B = Tzx @ xsys.B
153153

154154
return zsys, Tzx
155155

@@ -189,13 +189,13 @@ def rsolve(M, y):
189189

190190
# Update the system matrices
191191
if not inverse:
192-
zsys.A = rsolve(T, dot(T, zsys.A)) / timescale
193-
zsys.B = dot(T, zsys.B) / timescale
192+
zsys.A = rsolve(T, T @ zsys.A) / timescale
193+
zsys.B = T @ zsys.B / timescale
194194
zsys.C = rsolve(T, zsys.C)
195195
else:
196-
zsys.A = solve(T, zsys.A).dot(T) / timescale
196+
zsys.A = solve(T, zsys.A) @ T / timescale
197197
zsys.B = solve(T, zsys.B) / timescale
198-
zsys.C = zsys.C.dot(T)
198+
zsys.C = zsys.C @ T
199199

200200
return zsys
201201

@@ -405,8 +405,8 @@ def bdschur(a, condmax=None, sort=None):
405405
permidx = np.hstack([blkidxs[i] for i in sortidx])
406406
rperm = np.eye(amodal.shape[0])[permidx]
407407

408-
tmodal = tmodal.dot(rperm)
409-
amodal = rperm.dot(amodal).dot(rperm.T)
408+
tmodal = tmodal @ rperm
409+
amodal = rperm @ amodal @ rperm.T
410410
blksizes = blksizes[sortidx]
411411

412412
elif sort is None:

control/delay.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
#
4343
# $Id$
4444

45-
from __future__ import division
4645

4746
__all__ = ['pade']
4847

control/exception.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@ class ControlNotImplemented(NotImplementedError):
6161
pass
6262

6363
# Utility function to see if slycot is installed
64+
slycot_installed = None
6465
def slycot_check():
65-
try:
66-
import slycot
67-
except:
68-
return False
69-
else:
70-
return True
66+
global slycot_installed
67+
if slycot_installed is None:
68+
try:
69+
import slycot
70+
slycot_installed = True
71+
except:
72+
slycot_installed = False
73+
return slycot_installed

control/flatsys/flatsys.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,7 @@ def traj_const(null_coeffs):
462462
for type, fun, lb, ub in traj_constraints:
463463
if type == sp.optimize.LinearConstraint:
464464
# `fun` is A matrix associated with polytope...
465-
values.append(
466-
np.dot(fun, np.hstack([states, inputs])))
465+
values.append(fun @ np.hstack([states, inputs]))
467466
elif type == sp.optimize.NonlinearConstraint:
468467
values.append(fun(states, inputs))
469468
else:

control/flatsys/linflat.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def __init__(self, linsys, inputs=None, outputs=None, states=None,
110110

111111
# Compute the flat output variable z = C x
112112
Cfz = np.zeros(np.shape(linsys.C)); Cfz[0, 0] = 1
113-
self.Cf = np.dot(Cfz, Tr)
113+
self.Cf = Cfz @ Tr
114114

115115
# Compute the flat flag from the state (and input)
116116
def forward(self, x, u):
@@ -122,11 +122,11 @@ def forward(self, x, u):
122122
x = np.reshape(x, (-1, 1))
123123
u = np.reshape(u, (1, -1))
124124
zflag = [np.zeros(self.nstates + 1)]
125-
zflag[0][0] = np.dot(self.Cf, x)
125+
zflag[0][0] = self.Cf @ x
126126
H = self.Cf # initial state transformation
127127
for i in range(1, self.nstates + 1):
128-
zflag[0][i] = np.dot(H, np.dot(self.A, x) + np.dot(self.B, u))
129-
H = np.dot(H, self.A) # derivative for next iteration
128+
zflag[0][i] = H @ (self.A @ x + self.B @ u)
129+
H = H @ self.A # derivative for next iteration
130130
return zflag
131131

132132
# Compute state and input from flat flag
@@ -137,6 +137,6 @@ def reverse(self, zflag):
137137
138138
"""
139139
z = zflag[0][0:-1]
140-
x = np.dot(self.Tinv, z)
141-
u = zflag[0][-1] - np.dot(self.F, z)
140+
x = self.Tinv @ z
141+
u = zflag[0][-1] - self.F @ z
142142
return np.reshape(x, self.nstates), np.reshape(u, self.ninputs)

control/frdata.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
# Author: M.M. (Rene) van Paassen (using xferfcn.py as basis)
3636
# Date: 02 Oct 12
3737

38-
from __future__ import division
3938

4039
"""
4140
Frequency response data representation and functions.
@@ -48,7 +47,7 @@
4847
from warnings import warn
4948
import numpy as np
5049
from numpy import angle, array, empty, ones, \
51-
real, imag, absolute, eye, linalg, where, dot, sort
50+
real, imag, absolute, eye, linalg, where, sort
5251
from scipy.interpolate import splprep, splev
5352
from .lti import LTI, _process_frequency_response
5453
from . import config
@@ -302,7 +301,7 @@ def __mul__(self, other):
302301
fresp = empty((outputs, inputs, len(self.omega)),
303302
dtype=self.fresp.dtype)
304303
for i in range(len(self.omega)):
305-
fresp[:, :, i] = dot(self.fresp[:, :, i], other.fresp[:, :, i])
304+
fresp[:, :, i] = self.fresp[:, :, i] @ other.fresp[:, :, i]
306305
return FRD(fresp, self.omega,
307306
smooth=(self.ifunc is not None) and
308307
(other.ifunc is not None))
@@ -330,7 +329,7 @@ def __rmul__(self, other):
330329
fresp = empty((outputs, inputs, len(self.omega)),
331330
dtype=self.fresp.dtype)
332331
for i in range(len(self.omega)):
333-
fresp[:, :, i] = dot(other.fresp[:, :, i], self.fresp[:, :, i])
332+
fresp[:, :, i] = other.fresp[:, :, i] @ self.fresp[:, :, i]
334333
return FRD(fresp, self.omega,
335334
smooth=(self.ifunc is not None) and
336335
(other.ifunc is not None))
@@ -536,20 +535,15 @@ def feedback(self, other=1, sign=-1):
536535
if (self.noutputs != other.ninputs or self.ninputs != other.noutputs):
537536
raise ValueError(
538537
"FRD.feedback, inputs/outputs mismatch")
539-
fresp = empty((self.noutputs, self.ninputs, len(other.omega)),
540-
dtype=complex)
541-
# TODO: vectorize this
538+
542539
# TODO: handle omega re-mapping
543-
# TODO: is there a reason to use linalg.solve instead of linalg.inv?
544-
# https://github.com/python-control/python-control/pull/314#discussion_r294075154
545-
for k, w in enumerate(other.omega):
546-
fresp[:, :, k] = np.dot(
547-
self.fresp[:, :, k],
548-
linalg.solve(
549-
eye(self.ninputs)
550-
+ np.dot(other.fresp[:, :, k], self.fresp[:, :, k]),
551-
eye(self.ninputs))
552-
)
540+
541+
# reorder array axes in order to leverage numpy broadcasting
542+
myfresp = np.moveaxis(self.fresp, 2, 0)
543+
otherfresp = np.moveaxis(other.fresp, 2, 0)
544+
I_AB = eye(self.ninputs)[np.newaxis, :, :] + otherfresp @ myfresp
545+
resfresp = (myfresp @ linalg.inv(I_AB))
546+
fresp = np.moveaxis(resfresp, 0, 2)
553547

554548
return FRD(fresp, other.omega, smooth=(self.ifunc is not None))
555549

0 commit comments

Comments
 (0)