Skip to content

Commit 92bd703

Browse files
authored
Merge pull request #1108 from murrayrm/mimo_ss2tf_scipy-12Jan2025
scipy-based implementation of ss2tf
2 parents ebff125 + e539c72 commit 92bd703

File tree

7 files changed

+16
-44
lines changed

7 files changed

+16
-44
lines changed

control/tests/frd_test.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@ def testNyquist(self, frd_fcn):
258258
freqplot.nyquist(f1)
259259
# plt.savefig('/dev/null', format='svg')
260260

261-
@slycotonly
262261
@pytest.mark.parametrize(
263262
"frd_fcn", [ct.frd, ct.FRD, ct.FrequencyResponseData])
264263
def testMIMO(self, frd_fcn):
@@ -276,7 +275,6 @@ def testMIMO(self, frd_fcn):
276275
sys.frequency_response(chkpts)[1],
277276
f1.frequency_response(chkpts)[1])
278277

279-
@slycotonly
280278
@pytest.mark.parametrize(
281279
"frd_fcn", [ct.frd, ct.FRD, ct.FrequencyResponseData])
282280
def testMIMOfb(self, frd_fcn):
@@ -295,7 +293,6 @@ def testMIMOfb(self, frd_fcn):
295293
f1.frequency_response(chkpts)[1],
296294
f2.frequency_response(chkpts)[1])
297295

298-
@slycotonly
299296
@pytest.mark.parametrize(
300297
"frd_fcn", [ct.frd, ct.FRD, ct.FrequencyResponseData])
301298
def testMIMOfb2(self, frd_fcn):
@@ -316,7 +313,6 @@ def testMIMOfb2(self, frd_fcn):
316313
f1.frequency_response(chkpts)[1],
317314
f2.frequency_response(chkpts)[1])
318315

319-
@slycotonly
320316
@pytest.mark.parametrize(
321317
"frd_fcn", [ct.frd, ct.FRD, ct.FrequencyResponseData])
322318
def testMIMOMult(self, frd_fcn):
@@ -335,7 +331,6 @@ def testMIMOMult(self, frd_fcn):
335331
(f1*f2).frequency_response(chkpts)[1],
336332
(sys*sys).frequency_response(chkpts)[1])
337333

338-
@slycotonly
339334
@pytest.mark.parametrize(
340335
"frd_fcn", [ct.frd, ct.FRD, ct.FrequencyResponseData])
341336
def testMIMOSmooth(self, frd_fcn):

control/tests/iosys_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2288,7 +2288,6 @@ def test_signal_indexing():
22882288
resp.outputs['y[0]', 'u[0]']
22892289

22902290

2291-
@slycotonly
22922291
@pytest.mark.parametrize("fcn, spec, expected, missing", [
22932292
(ct.ss, {}, "states=4, outputs=3, inputs=2", r"dt|name"),
22942293
(ct.tf, {}, "outputs=3, inputs=2", r"dt|states|name"),

control/tests/lti_test.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ def test_squeeze_exceptions(self, fcn):
309309
evalfr(sys, [[0.1j, 1j], [1j, 10j]])
310310

311311

312-
@slycotonly
313312
@pytest.mark.parametrize(
314313
"outdx, inpdx, key",
315314
[('y[0]', 'u[1]', (0, 1)),
@@ -356,7 +355,6 @@ def test_subsys_indexing(fcn, outdx, inpdx, key):
356355
subsys_chk.frequency_response(omega).response)
357356

358357

359-
@slycotonly
360358
@pytest.mark.parametrize("op", [
361359
'__mul__', '__rmul__', '__add__', '__radd__', '__sub__', '__rsub__'])
362360
@pytest.mark.parametrize("fcn", [ct.ss, ct.tf, ct.frd])

control/tests/matlab2_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ def MIMO_mats(self):
4949
D = zeros((2, 2))
5050
return A, B, C, D
5151

52-
@slycotonly
5352
def test_dcgain_mimo(self, MIMO_mats):
5453
"""Test function dcgain with MIMO systems"""
5554
#Test MIMO systems

control/tests/statesp_test.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,13 @@ def test_zero_siso(self, sys222):
248248

249249
np.testing.assert_almost_equal(true_z, z)
250250

251-
@slycotonly
252251
def test_zero_mimo_sys322_square(self, sys322):
253252
"""Evaluate the zeros of a square MIMO system."""
254253

255254
z = np.sort(sys322.zeros())
256255
true_z = np.sort([44.41465, -0.490252, -5.924398])
257256
np.testing.assert_array_almost_equal(z, true_z)
258257

259-
@slycotonly
260258
def test_zero_mimo_sys222_square(self, sys222):
261259
"""Evaluate the zeros of a square MIMO system."""
262260

@@ -320,7 +318,6 @@ def test_multiply_ss(self, sys222, sys322):
320318
np.testing.assert_array_almost_equal(sys.C, C)
321319
np.testing.assert_array_almost_equal(sys.D, D)
322320

323-
@slycotonly
324321
def test_add_sub_mimo_siso(self):
325322
# Test SS with SS
326323
ss_siso = StateSpace(
@@ -702,8 +699,6 @@ def test_call(self, dt, omega, resp):
702699
with pytest.raises(AttributeError):
703700
sys.evalfr(omega)
704701

705-
706-
@slycotonly
707702
def test_freq_resp(self):
708703
"""Evaluate the frequency response at multiple frequencies."""
709704

control/tests/xferfcn_test.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
import pytest
1111

1212
import control as ct
13-
from control import (StateSpace, TransferFunction, defaults, evalfr, isctime,
14-
isdtime, reset_defaults, rss, sample_system, set_defaults,
15-
ss, ss2tf, tf, tf2ss, zpk)
13+
from control import StateSpace, TransferFunction, defaults, evalfr, isctime, \
14+
isdtime, reset_defaults, rss, sample_system, set_defaults, ss, ss2tf, tf, \
15+
tf2ss, zpk
1616
from control.statesp import _convert_to_statespace
1717
from control.tests.conftest import slycotonly
1818
from control.xferfcn import _convert_to_transfer_function, _tf_close_coeff
@@ -186,7 +186,6 @@ def test_reverse_sign_siso(self):
186186
np.testing.assert_allclose(sys2.num, [[[-1., -3., -5.]]])
187187
np.testing.assert_allclose(sys2.den, [[[1., 6., 2., -1.]]])
188188

189-
@slycotonly
190189
def test_reverse_sign_mimo(self):
191190
"""Negate a MIMO system."""
192191
num1 = [[[1., 2.], [0., 3.], [2., -1.]],
@@ -228,7 +227,6 @@ def test_add_siso(self):
228227
np.testing.assert_allclose(sys3.num, [[[20., 4., -8]]])
229228
np.testing.assert_allclose(sys3.den, [[[1., 6., 1., -7., -2., 1.]]])
230229

231-
@slycotonly
232230
def test_add_mimo(self):
233231
"""Add two MIMO systems."""
234232
num1 = [[[1., 2.], [0., 3.], [2., -1.]],
@@ -276,7 +274,6 @@ def test_subtract_siso(self):
276274
np.testing.assert_allclose(sys4.num, [[[-2., -6., 12., 10., 2.]]])
277275
np.testing.assert_allclose(sys4.den, [[[1., 6., 1., -7., -2., 1.]]])
278276

279-
@slycotonly
280277
def test_subtract_mimo(self):
281278
"""Subtract two MIMO systems."""
282279
num1 = [[[1., 2.], [0., 3.], [2., -1.]],
@@ -327,7 +324,6 @@ def test_multiply_siso(self):
327324
np.testing.assert_allclose(sys3.num, sys4.num)
328325
np.testing.assert_allclose(sys3.den, sys4.den)
329326

330-
@slycotonly
331327
def test_multiply_mimo(self):
332328
"""Multiply two MIMO systems."""
333329
num1 = [[[1., 2.], [0., 3.], [2., -1.]],
@@ -714,7 +710,6 @@ def test_call_dtime(self):
714710
sys = TransferFunction([1., 3., 5], [1., 6., 2., -1], 0.1)
715711
np.testing.assert_array_almost_equal(sys(1j), -0.5 - 0.5j)
716712

717-
@slycotonly
718713
def test_call_mimo(self):
719714
"""Evaluate the frequency response of a MIMO system at one frequency."""
720715

@@ -755,7 +750,6 @@ def test_frequency_response_siso(self):
755750
np.testing.assert_array_almost_equal(phase, truephase)
756751
np.testing.assert_array_almost_equal(omega, trueomega)
757752

758-
@slycotonly
759753
def test_freqresp_mimo(self):
760754
"""Evaluate the MIMO magnitude and phase at multiple frequencies."""
761755
num = [[[1., 2.], [0., 3.], [2., -1.]],
@@ -852,7 +846,6 @@ def test_common_den_nonproper(self):
852846
_, den2, _ = tf2._common_den(allow_nonproper=True)
853847
np.testing.assert_array_almost_equal(den2, common_den_ref)
854848

855-
@slycotonly
856849
def test_pole_mimo(self):
857850
"""Test for correct MIMO poles."""
858851
sys = TransferFunction(
@@ -936,7 +929,6 @@ def test_append(self):
936929
tf_appended_2 = tf1.append(tf2).append(tf3)
937930
assert _tf_close_coeff(tf_exp_2, tf_appended_2)
938931

939-
@slycotonly
940932
def test_convert_to_transfer_function(self):
941933
"""Test for correct state space to transfer function conversion."""
942934
A = [[1., -2.], [-3., 4.]]
@@ -1023,7 +1015,6 @@ def test_state_space_conversion_mimo(self):
10231015
np.testing.assert_array_almost_equal(H.num[1][0], H2.num[1][0])
10241016
np.testing.assert_array_almost_equal(H.den[1][0], H2.den[1][0])
10251017

1026-
@slycotonly
10271018
def test_indexing(self):
10281019
"""Test TF scalar indexing and slice"""
10291020
tm = ss2tf(rss(5, 3, 3))
@@ -1213,7 +1204,6 @@ def test_printing_polynomial(self, args, outputfmt, var, dt, dtstring):
12131204
assert len(polystr[0].split('\n')) == 4
12141205
assert polystr[2] == outputfmt.format(var=var)
12151206

1216-
@slycotonly
12171207
def test_printing_mimo(self):
12181208
"""Print MIMO, continuous time"""
12191209
sys = ss2tf(rss(4, 2, 3))
@@ -1332,7 +1322,6 @@ def test_printing_zpk_mimo(self, num, den, output):
13321322
res = str(G)
13331323
assert res.partition('\n\n')[2] == output
13341324

1335-
@slycotonly
13361325
def test_size_mismatch(self):
13371326
"""Test size mismacht"""
13381327
sys1 = ss2tf(rss(2, 2, 2))

control/xferfcn.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,12 @@ def _convert_to_transfer_function(
15161516
den = [[[1.] for j in range(sys.ninputs)]
15171517
for i in range(sys.noutputs)]
15181518
else:
1519+
# Preallocate numerator and denominator arrays
1520+
num = [[[] for j in range(sys.ninputs)]
1521+
for i in range(sys.noutputs)]
1522+
den = [[[] for j in range(sys.ninputs)]
1523+
for i in range(sys.noutputs)]
1524+
15191525
try:
15201526
# Use Slycot to make the transformation
15211527
# Make sure to convert system matrices to numpy arrays
@@ -1524,12 +1530,6 @@ def _convert_to_transfer_function(
15241530
sys.nstates, sys.ninputs, sys.noutputs, array(sys.A),
15251531
array(sys.B), array(sys.C), array(sys.D), tol1=0.0)
15261532

1527-
# Preallocate outputs.
1528-
num = [[[] for j in range(sys.ninputs)]
1529-
for i in range(sys.noutputs)]
1530-
den = [[[] for j in range(sys.ninputs)]
1531-
for i in range(sys.noutputs)]
1532-
15331533
for i in range(sys.noutputs):
15341534
for j in range(sys.ninputs):
15351535
num[i][j] = list(tfout[6][i, j, :])
@@ -1538,16 +1538,13 @@ def _convert_to_transfer_function(
15381538
den[i][j] = list(tfout[5][i, :])
15391539

15401540
except ImportError:
1541-
# If slycot is not available, use signal.lti (SISO only)
1542-
if sys.ninputs != 1 or sys.noutputs != 1:
1543-
raise ControlMIMONotImplemented("Not implemented for " +
1544-
"MIMO systems without slycot.")
1545-
1546-
# Do the conversion using sp.signal.ss2tf
1547-
# Note that this returns a 2D array for the numerator
1548-
num, den = sp.signal.ss2tf(sys.A, sys.B, sys.C, sys.D)
1549-
num = squeeze(num) # Convert to 1D array
1550-
den = squeeze(den) # Probably not needed
1541+
# If slycot not available, do conversion using sp.signal.ss2tf
1542+
for j in range(sys.ninputs):
1543+
num_j, den_j = sp.signal.ss2tf(
1544+
sys.A, sys.B, sys.C, sys.D, input=j)
1545+
for i in range(sys.noutputs):
1546+
num[i][j] = num_j[i]
1547+
den[i][j] = den_j
15511548

15521549
newsys = TransferFunction(num, den, sys.dt)
15531550
if use_prefix_suffix:

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