Skip to content

Commit 25747c7

Browse files
authored
Merge pull request #122 from murrayrm/noslycot
Allow unit tests to run without slycot
2 parents 99cc2e9 + 7de3cc8 commit 25747c7

11 files changed

+133
-64
lines changed

control/statesp.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,10 @@ def _convertToStateSpace(sys, **kw):
670670
ssout[3][:sys.outputs, :states],
671671
ssout[4], sys.dt)
672672
except ImportError:
673+
# If slycot is not available, use signal.lti (SISO only)
674+
if (sys.inputs != 1 or sys.outputs != 1):
675+
raise TypeError("No support for MIMO without slycot")
676+
673677
# TODO: do we want to squeeze first and check dimenations?
674678
# I think this will fail if num and den aren't 1-D after
675679
# the squeeze

control/tests/convert_test.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from control.statefbk import ctrb, obsv
2323
from control.freqplot import bode
2424
from control.matlab import tf
25-
25+
from control.exception import slycot_check
2626

2727
class TestConvert(unittest.TestCase):
2828
"""Test state space and transfer function conversions."""
@@ -35,7 +35,8 @@ def setUp(self):
3535
# Maximum number of states to test + 1
3636
self.maxStates = 4
3737
# Maximum number of inputs and outputs to test + 1
38-
self.maxIO = 5
38+
# If slycot is not installed, just check SISO
39+
self.maxIO = 5 if slycot_check() else 2
3940
# Set to True to print systems to the output.
4041
self.debug = False
4142
# get consistent results
@@ -161,6 +162,29 @@ def testConvert(self):
161162
np.testing.assert_array_almost_equal( \
162163
ssorig_imag, tfxfrm_imag)
163164

165+
def testConvertMIMO(self):
166+
"""Test state space to transfer function conversion."""
167+
verbose = self.debug
168+
169+
# Do a MIMO conversation and make sure that it is processed
170+
# correctly both with and without slycot
171+
#
172+
# Example from issue #120, jgoppert
173+
import control
174+
175+
# Set up a transfer function (should always work)
176+
tfcn = control.tf([[[-235, 1.146e4],
177+
[-235, 1.146E4],
178+
[-235, 1.146E4, 0]]],
179+
[[[1, 48.78, 0],
180+
[1, 48.78, 0, 0],
181+
[0.008, 1.39, 48.78]]])
182+
183+
# Convert to state space and look for an error
184+
if (not slycot_check()):
185+
self.assertRaises(TypeError, control.tf2ss, tfcn)
186+
187+
164188
def suite():
165189
return unittest.TestLoader().loadTestsFromTestCase(TestConvert)
166190

control/tests/frd_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from control.frdata import FRD, _convertToFRD
1212
from control import bdalg
1313
from control import freqplot
14+
from control.exception import slycot_check
1415
import matplotlib.pyplot as plt
1516

1617

@@ -179,6 +180,7 @@ def testNyquist(self):
179180
freqplot.nyquist(f1, f1.omega)
180181
# plt.savefig('/dev/null', format='svg')
181182

183+
@unittest.skipIf(not slycot_check(), "slycot not installed")
182184
def testMIMO(self):
183185
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
184186
[[1.0, 0.0], [0.0, 1.0]],
@@ -193,6 +195,7 @@ def testMIMO(self):
193195
sys.freqresp([0.1, 1.0, 10])[1],
194196
f1.freqresp([0.1, 1.0, 10])[1])
195197

198+
@unittest.skipIf(not slycot_check(), "slycot not installed")
196199
def testMIMOfb(self):
197200
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
198201
[[1.0, 0.0], [0.0, 1.0]],
@@ -208,6 +211,7 @@ def testMIMOfb(self):
208211
f1.freqresp([0.1, 1.0, 10])[1],
209212
f2.freqresp([0.1, 1.0, 10])[1])
210213

214+
@unittest.skipIf(not slycot_check(), "slycot not installed")
211215
def testMIMOfb2(self):
212216
sys = StateSpace(np.matrix('-2.0 0 0; 0 -1 1; 0 0 -3'),
213217
np.matrix('1.0 0; 0 0; 0 1'),
@@ -223,6 +227,7 @@ def testMIMOfb2(self):
223227
f1.freqresp([0.1, 1.0, 10])[1],
224228
f2.freqresp([0.1, 1.0, 10])[1])
225229

230+
@unittest.skipIf(not slycot_check(), "slycot not installed")
226231
def testMIMOMult(self):
227232
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
228233
[[1.0, 0.0], [0.0, 1.0]],
@@ -238,6 +243,7 @@ def testMIMOMult(self):
238243
(f1*f2).freqresp([0.1, 1.0, 10])[1],
239244
(sys*sys).freqresp([0.1, 1.0, 10])[1])
240245

246+
@unittest.skipIf(not slycot_check(), "slycot not installed")
241247
def testMIMOSmooth(self):
242248
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
243249
[[1.0, 0.0], [0.0, 1.0]],

control/tests/freqresp_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import numpy as np
1111
from control.statesp import StateSpace
1212
from control.matlab import ss, tf, bode
13+
from control.exception import slycot_check
1314
import matplotlib.pyplot as plt
1415

1516
class TestFreqresp(unittest.TestCase):
@@ -42,6 +43,7 @@ def test_doubleint(self):
4243
sys = ss(A, B, C, D);
4344
bode(sys);
4445

46+
@unittest.skipIf(not slycot_check(), "slycot not installed")
4547
def test_mimo(self):
4648
# MIMO
4749
B = np.matrix('1,0;0,1')

control/tests/matlab_test.py

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import scipy as sp
1616
from control.matlab import *
1717
from control.frdata import FRD
18+
from control.exception import slycot_check
1819
import warnings
1920

2021
# for running these through Matlab or Octave
@@ -165,12 +166,13 @@ def testStep(self):
165166
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
166167
np.testing.assert_array_almost_equal(tout, t)
167168

168-
#Test MIMO system, which contains ``siso_ss1`` twice
169-
sys = self.mimo_ss1
170-
y_00, _t = step(sys, T=t, input=0, output=0)
171-
y_11, _t = step(sys, T=t, input=1, output=1)
172-
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
173-
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
169+
if slycot_check():
170+
# Test MIMO system, which contains ``siso_ss1`` twice
171+
sys = self.mimo_ss1
172+
y_00, _t = step(sys, T=t, input=0, output=0)
173+
y_11, _t = step(sys, T=t, input=1, output=1)
174+
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
175+
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
174176

175177
def testImpulse(self):
176178
t = np.linspace(0, 1, 10)
@@ -206,12 +208,13 @@ def testImpulse(self):
206208
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
207209
np.testing.assert_array_almost_equal(tout, t)
208210

209-
#Test MIMO system, which contains ``siso_ss1`` twice
210-
sys = self.mimo_ss1
211-
y_00, _t = impulse(sys, T=t, input=0, output=0)
212-
y_11, _t = impulse(sys, T=t, input=1, output=1)
213-
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
214-
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
211+
if slycot_check():
212+
#Test MIMO system, which contains ``siso_ss1`` twice
213+
sys = self.mimo_ss1
214+
y_00, _t = impulse(sys, T=t, input=0, output=0)
215+
y_11, _t = impulse(sys, T=t, input=1, output=1)
216+
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
217+
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
215218

216219
def testInitial(self):
217220
#Test SISO system
@@ -229,13 +232,14 @@ def testInitial(self):
229232
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
230233
np.testing.assert_array_almost_equal(tout, t)
231234

232-
#Test MIMO system, which contains ``siso_ss1`` twice
233-
sys = self.mimo_ss1
234-
x0 = np.matrix(".5; 1.; .5; 1.")
235-
y_00, _t = initial(sys, T=t, X0=x0, input=0, output=0)
236-
y_11, _t = initial(sys, T=t, X0=x0, input=1, output=1)
237-
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
238-
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
235+
if slycot_check():
236+
#Test MIMO system, which contains ``siso_ss1`` twice
237+
sys = self.mimo_ss1
238+
x0 = np.matrix(".5; 1.; .5; 1.")
239+
y_00, _t = initial(sys, T=t, X0=x0, input=0, output=0)
240+
y_11, _t = initial(sys, T=t, X0=x0, input=1, output=1)
241+
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
242+
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
239243

240244
def testLsim(self):
241245
t = np.linspace(0, 1, 10)
@@ -259,18 +263,19 @@ def testLsim(self):
259263
yout, _t, _xout = lsim(self.siso_ss1, u, t, x0)
260264
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
261265

262-
#Test MIMO system, which contains ``siso_ss1`` twice
263-
#first system: initial value, second system: step response
264-
u = np.array([[0., 1.], [0, 1], [0, 1], [0, 1], [0, 1],
265-
[0, 1], [0, 1], [0, 1], [0, 1], [0, 1]])
266-
x0 = np.matrix(".5; 1; 0; 0")
267-
youttrue = np.array([[11., 9.], [8.1494, 17.6457], [5.9361, 24.7072],
268-
[4.2258, 30.4855], [2.9118, 35.2234],
269-
[1.9092, 39.1165], [1.1508, 42.3227],
270-
[0.5833, 44.9694], [0.1645, 47.1599],
271-
[-0.1391, 48.9776]])
272-
yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0)
273-
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
266+
if slycot_check():
267+
#Test MIMO system, which contains ``siso_ss1`` twice
268+
#first system: initial value, second system: step response
269+
u = np.array([[0., 1.], [0, 1], [0, 1], [0, 1], [0, 1],
270+
[0, 1], [0, 1], [0, 1], [0, 1], [0, 1]])
271+
x0 = np.matrix(".5; 1; 0; 0")
272+
youttrue = np.array([[11., 9.], [8.1494, 17.6457],
273+
[5.9361, 24.7072], [4.2258, 30.4855],
274+
[2.9118, 35.2234], [1.9092, 39.1165],
275+
[1.1508, 42.3227], [0.5833, 44.9694],
276+
[0.1645, 47.1599], [-0.1391, 48.9776]])
277+
yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0)
278+
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
274279

275280
def testMargin(self):
276281
#! TODO: check results to make sure they are OK
@@ -310,11 +315,12 @@ def testDcgain(self):
310315
gain_sim],
311316
[59, 59, 59, 59, 59])
312317

313-
# Test with MIMO system, which contains ``siso_ss1`` twice
314-
gain_mimo = dcgain(self.mimo_ss1)
315-
# print('gain_mimo: \n', gain_mimo)
316-
np.testing.assert_array_almost_equal(gain_mimo, [[59., 0 ],
317-
[0, 59.]])
318+
if slycot_check():
319+
# Test with MIMO system, which contains ``siso_ss1`` twice
320+
gain_mimo = dcgain(self.mimo_ss1)
321+
# print('gain_mimo: \n', gain_mimo)
322+
np.testing.assert_array_almost_equal(gain_mimo, [[59., 0 ],
323+
[0, 59.]])
318324

319325
def testBode(self):
320326
bode(self.siso_ss1)
@@ -370,29 +376,35 @@ def testEvalfr(self):
370376
evalfr(self.siso_tf1, w)
371377
evalfr(self.siso_tf2, w)
372378
evalfr(self.siso_tf3, w)
373-
np.testing.assert_array_almost_equal(
374-
evalfr(self.mimo_ss1, w),
375-
np.array( [[44.8-21.4j, 0.], [0., 44.8-21.4j]]))
379+
if slycot_check():
380+
np.testing.assert_array_almost_equal(
381+
evalfr(self.mimo_ss1, w),
382+
np.array( [[44.8-21.4j, 0.], [0., 44.8-21.4j]]))
376383

384+
@unittest.skipIf(not slycot_check(), "slycot not installed")
377385
def testHsvd(self):
378386
hsvd(self.siso_ss1)
379387
hsvd(self.siso_ss2)
380388
hsvd(self.siso_ss3)
381389

390+
@unittest.skipIf(not slycot_check(), "slycot not installed")
382391
def testBalred(self):
383392
balred(self.siso_ss1, 1)
384393
balred(self.siso_ss2, 2)
385394
balred(self.siso_ss3, [2, 2])
386395

396+
@unittest.skipIf(not slycot_check(), "slycot not installed")
387397
def testModred(self):
388398
modred(self.siso_ss1, [1])
389399
modred(self.siso_ss2 * self.siso_ss3, [0, 1])
390400
modred(self.siso_ss3, [1], 'matchdc')
391401
modred(self.siso_ss3, [1], 'truncate')
392402

403+
@unittest.skipIf(not slycot_check(), "slycot not installed")
393404
def testPlace(self):
394405
place(self.siso_ss1.A, self.siso_ss1.B, [-2, -2])
395406

407+
@unittest.skipIf(not slycot_check(), "slycot not installed")
396408
def testLQR(self):
397409
(K, S, E) = lqr(self.siso_ss1.A, self.siso_ss1.B, np.eye(2), np.eye(1))
398410
(K, S, E) = lqr(self.siso_ss2.A, self.siso_ss2.B, np.eye(3), \
@@ -416,6 +428,7 @@ def testObsv(self):
416428
obsv(self.siso_ss1.A, self.siso_ss1.C)
417429
obsv(self.siso_ss2.A, self.siso_ss2.C)
418430

431+
@unittest.skipIf(not slycot_check(), "slycot not installed")
419432
def testGram(self):
420433
gram(self.siso_ss1, 'c')
421434
gram(self.siso_ss2, 'c')
@@ -452,6 +465,7 @@ def testSISOssdata(self):
452465
for i in range(len(ssdata_1)):
453466
np.testing.assert_array_almost_equal(ssdata_1[i], ssdata_2[i])
454467

468+
@unittest.skipIf(not slycot_check(), "slycot not installed")
455469
def testMIMOssdata(self):
456470
m = (self.mimo_ss1.A, self.mimo_ss1.B, self.mimo_ss1.C, self.mimo_ss1.D)
457471
ssdata_1 = ssdata(self.mimo_ss1);
@@ -532,6 +546,7 @@ def testFRD(self):
532546
frd2 = frd(frd1.fresp[0,0,:], omega)
533547
assert isinstance(frd2, FRD)
534548

549+
@unittest.skipIf(not slycot_check(), "slycot not installed")
535550
def testMinreal(self, verbose=False):
536551
"""Test a minreal model reduction"""
537552
#A = [-2, 0.5, 0; 0.5, -0.3, 0; 0, 0, -0.1]

control/tests/minreal_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from control.statesp import StateSpace
1111
from control.xferfcn import TransferFunction
1212
from itertools import permutations
13+
from control.exception import slycot_check
1314

15+
@unittest.skipIf(not slycot_check(), "slycot not installed")
1416
class TestMinreal(unittest.TestCase):
1517
"""Tests for the StateSpace class."""
1618

control/tests/statefbk_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,13 @@ def check_LQR(self, K, S, poles, Q, R):
144144
np.testing.assert_array_almost_equal(poles, poles_expected)
145145

146146

147+
@unittest.skipIf(not slycot_check(), "slycot not installed")
147148
def test_LQR_integrator(self):
148149
A, B, Q, R = 0., 1., 10., 2.
149150
K, S, poles = lqr(A, B, Q, R)
150151
self.check_LQR(K, S, poles, Q, R)
151152

153+
@unittest.skipIf(not slycot_check(), "slycot not installed")
152154
def test_LQR_3args(self):
153155
sys = ss(0., 1., 1., 0.)
154156
Q, R = 10., 2.

control/tests/statesp_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from control import matlab
1111
from control.statesp import StateSpace, _convertToStateSpace
1212
from control.xferfcn import TransferFunction
13+
from control.exception import slycot_check
1314

1415
class TestStateSpace(unittest.TestCase):
1516
"""Tests for the StateSpace class."""
@@ -114,6 +115,7 @@ def testEvalFr(self):
114115

115116
np.testing.assert_almost_equal(sys.evalfr(1.), resp)
116117

118+
@unittest.skipIf(not slycot_check(), "slycot not installed")
117119
def testFreqResp(self):
118120
"""Evaluate the frequency response at multiple frequencies."""
119121

@@ -139,6 +141,7 @@ def testFreqResp(self):
139141
np.testing.assert_almost_equal(phase, truephase)
140142
np.testing.assert_equal(omega, trueomega)
141143

144+
@unittest.skipIf(not slycot_check(), "slycot not installed")
142145
def testMinreal(self):
143146
"""Test a minreal model reduction"""
144147
#A = [-2, 0.5, 0; 0.5, -0.3, 0; 0, 0, -0.1]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy