Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions control/statesp.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,10 @@ def _convertToStateSpace(sys, **kw):
ssout[3][:sys.outputs, :states],
ssout[4], sys.dt)
except ImportError:
# If slycot is not available, use signal.lti (SISO only)
if (sys.inputs != 1 or sys.outputs != 1):
raise TypeError("No support for MIMO without slycot")

# TODO: do we want to squeeze first and check dimenations?
# I think this will fail if num and den aren't 1-D after
# the squeeze
Expand Down
28 changes: 26 additions & 2 deletions control/tests/convert_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from control.statefbk import ctrb, obsv
from control.freqplot import bode
from control.matlab import tf

from control.exception import slycot_check

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

def testConvertMIMO(self):
"""Test state space to transfer function conversion."""
verbose = self.debug

# Do a MIMO conversation and make sure that it is processed
# correctly both with and without slycot
#
# Example from issue #120, jgoppert
import control

# Set up a transfer function (should always work)
tfcn = control.tf([[[-235, 1.146e4],
[-235, 1.146E4],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation here and on the next 4 lines seems to be slightly off. I recommend

        tfcn = control.tf([[[-235, 1.146e4],
                            [-235, 1.146E4],
                            [-235, 1.146E4, 0]]],
                          [[[1, 48.78, 0],
                            [1, 48.78, 0, 0],
                            [0.008, 1.39, 48.78]]])

[-235, 1.146E4, 0]]],
[[[1, 48.78, 0],
[1, 48.78, 0, 0],
[0.008, 1.39, 48.78]]])

# Convert to state space and look for an error
if (not slycot_check()):
self.assertRaises(TypeError, control.tf2ss, tfcn)


def suite():
return unittest.TestLoader().loadTestsFromTestCase(TestConvert)

Expand Down
6 changes: 6 additions & 0 deletions control/tests/frd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from control.frdata import FRD, _convertToFRD
from control import bdalg
from control import freqplot
from control.exception import slycot_check
import matplotlib.pyplot as plt


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

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testMIMO(self):
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
[[1.0, 0.0], [0.0, 1.0]],
Expand All @@ -193,6 +195,7 @@ def testMIMO(self):
sys.freqresp([0.1, 1.0, 10])[1],
f1.freqresp([0.1, 1.0, 10])[1])

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

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

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

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testMIMOSmooth(self):
sys = StateSpace([[-0.5, 0.0], [0.0, -1.0]],
[[1.0, 0.0], [0.0, 1.0]],
Expand Down
2 changes: 2 additions & 0 deletions control/tests/freqresp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import numpy as np
from control.statesp import StateSpace
from control.matlab import ss, tf, bode
from control.exception import slycot_check
import matplotlib.pyplot as plt

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

@unittest.skipIf(not slycot_check(), "slycot not installed")
def test_mimo(self):
# MIMO
B = np.matrix('1,0;0,1')
Expand Down
93 changes: 54 additions & 39 deletions control/tests/matlab_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import scipy as sp
from control.matlab import *
from control.frdata import FRD
from control.exception import slycot_check
import warnings

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

#Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
y_00, _t = step(sys, T=t, input=0, output=0)
y_11, _t = step(sys, T=t, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
if slycot_check():
# Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
y_00, _t = step(sys, T=t, input=0, output=0)
y_11, _t = step(sys, T=t, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)

def testImpulse(self):
t = np.linspace(0, 1, 10)
Expand Down Expand Up @@ -206,12 +208,13 @@ def testImpulse(self):
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
np.testing.assert_array_almost_equal(tout, t)

#Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
y_00, _t = impulse(sys, T=t, input=0, output=0)
y_11, _t = impulse(sys, T=t, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
if slycot_check():
#Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
y_00, _t = impulse(sys, T=t, input=0, output=0)
y_11, _t = impulse(sys, T=t, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)

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

#Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
x0 = np.matrix(".5; 1.; .5; 1.")
y_00, _t = initial(sys, T=t, X0=x0, input=0, output=0)
y_11, _t = initial(sys, T=t, X0=x0, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)
if slycot_check():
#Test MIMO system, which contains ``siso_ss1`` twice
sys = self.mimo_ss1
x0 = np.matrix(".5; 1.; .5; 1.")
y_00, _t = initial(sys, T=t, X0=x0, input=0, output=0)
y_11, _t = initial(sys, T=t, X0=x0, input=1, output=1)
np.testing.assert_array_almost_equal(y_00, youttrue, decimal=4)
np.testing.assert_array_almost_equal(y_11, youttrue, decimal=4)

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

#Test MIMO system, which contains ``siso_ss1`` twice
#first system: initial value, second system: step response
u = np.array([[0., 1.], [0, 1], [0, 1], [0, 1], [0, 1],
[0, 1], [0, 1], [0, 1], [0, 1], [0, 1]])
x0 = np.matrix(".5; 1; 0; 0")
youttrue = np.array([[11., 9.], [8.1494, 17.6457], [5.9361, 24.7072],
[4.2258, 30.4855], [2.9118, 35.2234],
[1.9092, 39.1165], [1.1508, 42.3227],
[0.5833, 44.9694], [0.1645, 47.1599],
[-0.1391, 48.9776]])
yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0)
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)
if slycot_check():
#Test MIMO system, which contains ``siso_ss1`` twice
#first system: initial value, second system: step response
u = np.array([[0., 1.], [0, 1], [0, 1], [0, 1], [0, 1],
[0, 1], [0, 1], [0, 1], [0, 1], [0, 1]])
x0 = np.matrix(".5; 1; 0; 0")
youttrue = np.array([[11., 9.], [8.1494, 17.6457],
[5.9361, 24.7072], [4.2258, 30.4855],
[2.9118, 35.2234], [1.9092, 39.1165],
[1.1508, 42.3227], [0.5833, 44.9694],
[0.1645, 47.1599], [-0.1391, 48.9776]])
yout, _t, _xout = lsim(self.mimo_ss1, u, t, x0)
np.testing.assert_array_almost_equal(yout, youttrue, decimal=4)

def testMargin(self):
#! TODO: check results to make sure they are OK
Expand Down Expand Up @@ -310,11 +315,12 @@ def testDcgain(self):
gain_sim],
[59, 59, 59, 59, 59])

# Test with MIMO system, which contains ``siso_ss1`` twice
gain_mimo = dcgain(self.mimo_ss1)
# print('gain_mimo: \n', gain_mimo)
np.testing.assert_array_almost_equal(gain_mimo, [[59., 0 ],
[0, 59.]])
if slycot_check():
# Test with MIMO system, which contains ``siso_ss1`` twice
gain_mimo = dcgain(self.mimo_ss1)
# print('gain_mimo: \n', gain_mimo)
np.testing.assert_array_almost_equal(gain_mimo, [[59., 0 ],
[0, 59.]])

def testBode(self):
bode(self.siso_ss1)
Expand Down Expand Up @@ -370,29 +376,35 @@ def testEvalfr(self):
evalfr(self.siso_tf1, w)
evalfr(self.siso_tf2, w)
evalfr(self.siso_tf3, w)
np.testing.assert_array_almost_equal(
evalfr(self.mimo_ss1, w),
np.array( [[44.8-21.4j, 0.], [0., 44.8-21.4j]]))
if slycot_check():
np.testing.assert_array_almost_equal(
evalfr(self.mimo_ss1, w),
np.array( [[44.8-21.4j, 0.], [0., 44.8-21.4j]]))

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testHsvd(self):
hsvd(self.siso_ss1)
hsvd(self.siso_ss2)
hsvd(self.siso_ss3)

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testBalred(self):
balred(self.siso_ss1, 1)
balred(self.siso_ss2, 2)
balred(self.siso_ss3, [2, 2])

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testModred(self):
modred(self.siso_ss1, [1])
modred(self.siso_ss2 * self.siso_ss3, [1, 2])
modred(self.siso_ss3, [1], 'matchdc')
modred(self.siso_ss3, [1], 'truncate')

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

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

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

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

@unittest.skipIf(not slycot_check(), "slycot not installed")
def testMinreal(self, verbose=False):
"""Test a minreal model reduction"""
#A = [-2, 0.5, 0; 0.5, -0.3, 0; 0, 0, -0.1]
Expand Down
2 changes: 2 additions & 0 deletions control/tests/minreal_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
from control.statesp import StateSpace
from control.xferfcn import TransferFunction
from itertools import permutations
from control.exception import slycot_check

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

Expand Down
2 changes: 2 additions & 0 deletions control/tests/statefbk_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,13 @@ def check_LQR(self, K, S, poles, Q, R):
np.testing.assert_array_almost_equal(poles, poles_expected)


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

@unittest.skipIf(not slycot_check(), "slycot not installed")
def test_LQR_3args(self):
sys = ss(0., 1., 1., 0.)
Q, R = 10., 2.
Expand Down
3 changes: 3 additions & 0 deletions control/tests/statesp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from control import matlab
from control.statesp import StateSpace, _convertToStateSpace
from control.xferfcn import TransferFunction
from control.exception import slycot_check

class TestStateSpace(unittest.TestCase):
"""Tests for the StateSpace class."""
Expand Down Expand Up @@ -113,6 +114,7 @@ def testEvalFr(self):

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

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

Expand All @@ -138,6 +140,7 @@ def testFreqResp(self):
np.testing.assert_almost_equal(phase, truephase)
np.testing.assert_equal(omega, trueomega)

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