Skip to content

Commit eafec5b

Browse files
committed
Fix signal/system naming in indexed systems
1 parent ca5e3ea commit eafec5b

File tree

6 files changed

+69
-25
lines changed

6 files changed

+69
-25
lines changed

control/namedio.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
'namedio.linearized_system_name_suffix': '$linearized',
2424
'namedio.sampled_system_name_prefix': '',
2525
'namedio.sampled_system_name_suffix': '$sampled',
26+
'namedio.indexed_system_name_prefix': '',
27+
'namedio.indexed_system_name_suffix': '$indexed',
2628
'namedio.converted_system_name_prefix': '',
2729
'namedio.converted_system_name_suffix': '$converted',
2830
}

control/statesp.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,10 +1294,15 @@ def __getitem__(self, indices):
12941294
"""Array style access"""
12951295
if len(indices) != 2:
12961296
raise IOError('must provide indices of length 2 for state space')
1297-
i = indices[0]
1298-
j = indices[1]
1299-
return StateSpace(self.A, self.B[:, j], self.C[i, :],
1300-
self.D[i, j], self.dt)
1297+
outdx = indices[0] if isinstance(indices[0], list) else [indices[0]]
1298+
inpdx = indices[1] if isinstance(indices[1], list) else [indices[1]]
1299+
sysname = config.defaults['namedio.indexed_system_name_prefix'] + \
1300+
self.name + config.defaults['namedio.indexed_system_name_suffix']
1301+
return StateSpace(
1302+
self.A, self.B[:, inpdx], self.C[outdx, :], self.D[outdx, inpdx],
1303+
self.dt, name=sysname,
1304+
inputs=[self.input_labels[i] for i in list(inpdx)],
1305+
outputs=[self.output_labels[i] for i in list(outdx)])
13011306

13021307
def sample(self, Ts, method='zoh', alpha=None, prewarp_frequency=None,
13031308
name=None, copy_names=True, **kwargs):

control/tests/config_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,18 @@ def test_get_param_last(self):
301301

302302
assert ct.config._get_param(
303303
'config', 'second', kwargs, pop=True, last=True) == 2
304+
305+
def test_system_indexing(self):
306+
# Default renaming
307+
sys = ct.TransferFunction(
308+
[ [ [1], [2], [3]], [ [3], [4], [5]] ],
309+
[ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ], 0.5)
310+
sys1 = sys[1:, 1:]
311+
assert sys1.name == sys.name + '$indexed'
312+
313+
# Reset the format
314+
ct.config.set_defaults(
315+
'namedio', indexed_system_name_prefix='PRE',
316+
indexed_system_name_suffix='POST')
317+
sys2 = sys[1:, 1:]
318+
assert sys2.name == 'PRE' + sys.name + 'POST'

control/tests/statesp_test.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -479,22 +479,27 @@ def test_append_tf(self):
479479

480480
def test_array_access_ss(self):
481481

482-
sys1 = StateSpace([[1., 2.], [3., 4.]],
483-
[[5., 6.], [6., 8.]],
484-
[[9., 10.], [11., 12.]],
485-
[[13., 14.], [15., 16.]], 1)
486-
487-
sys1_11 = sys1[0, 1]
488-
np.testing.assert_array_almost_equal(sys1_11.A,
482+
sys1 = StateSpace(
483+
[[1., 2.], [3., 4.]],
484+
[[5., 6.], [6., 8.]],
485+
[[9., 10.], [11., 12.]],
486+
[[13., 14.], [15., 16.]], 1,
487+
inputs=['u0', 'u1'], outputs=['y0', 'y1'])
488+
489+
sys1_01 = sys1[0, 1]
490+
np.testing.assert_array_almost_equal(sys1_01.A,
489491
sys1.A)
490-
np.testing.assert_array_almost_equal(sys1_11.B,
492+
np.testing.assert_array_almost_equal(sys1_01.B,
491493
sys1.B[:, 1:2])
492-
np.testing.assert_array_almost_equal(sys1_11.C,
494+
np.testing.assert_array_almost_equal(sys1_01.C,
493495
sys1.C[0:1, :])
494-
np.testing.assert_array_almost_equal(sys1_11.D,
496+
np.testing.assert_array_almost_equal(sys1_01.D,
495497
sys1.D[0, 1])
496498

497-
assert sys1.dt == sys1_11.dt
499+
assert sys1.dt == sys1_01.dt
500+
assert sys1_01.input_labels == ['u1']
501+
assert sys1_01.output_labels == ['y0']
502+
assert sys1_01.name == sys1.name + "$indexed"
498503

499504
def test_dc_gain_cont(self):
500505
"""Test DC gain for continuous-time state-space systems."""
@@ -831,7 +836,7 @@ def test_error_u_dynamics_mimo(self, u, sys222):
831836
sys222.dynamics(0, (1, 1), u)
832837
with pytest.raises(ValueError):
833838
sys222.output(0, (1, 1), u)
834-
839+
835840
def test_sample_named_signals(self):
836841
sysc = ct.StateSpace(1.1, 1, 1, 1, inputs='u', outputs='y', states='a')
837842

@@ -859,14 +864,14 @@ def test_sample_named_signals(self):
859864
assert sysd_newnames.find_output('x') == 0
860865
assert sysd_newnames.find_output('y') is None
861866
assert sysd_newnames.find_state('b') == 0
862-
assert sysd_newnames.find_state('a') is None
867+
assert sysd_newnames.find_state('a') is None
863868
# test just one name
864869
sysd_newnames = sysc.sample(0.1, inputs='v')
865870
assert sysd_newnames.find_input('v') == 0
866871
assert sysd_newnames.find_input('u') is None
867872
assert sysd_newnames.find_output('y') == 0
868873
assert sysd_newnames.find_output('x') is None
869-
874+
870875
class TestRss:
871876
"""These are tests for the proper functionality of statesp.rss."""
872877

control/tests/xferfcn_test.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,19 +392,30 @@ def test_pow(self):
392392
def test_slice(self):
393393
sys = TransferFunction(
394394
[ [ [1], [2], [3]], [ [3], [4], [5]] ],
395-
[ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ])
395+
[ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ],
396+
inputs=['u0', 'u1', 'u2'], outputs=['y0', 'y1'], name='sys')
397+
396398
sys1 = sys[1:, 1:]
397399
assert (sys1.ninputs, sys1.noutputs) == (2, 1)
400+
assert sys1.input_labels == ['u1', 'u2']
401+
assert sys1.output_labels == ['y1']
402+
assert sys1.name == 'sys$indexed'
398403

399404
sys2 = sys[:2, :2]
400405
assert (sys2.ninputs, sys2.noutputs) == (2, 2)
406+
assert sys2.input_labels == ['u0', 'u1']
407+
assert sys2.output_labels == ['y0', 'y1']
408+
assert sys2.name == 'sys$indexed'
401409

402410
sys = TransferFunction(
403411
[ [ [1], [2], [3]], [ [3], [4], [5]] ],
404412
[ [[1, 2], [1, 3], [1, 4]], [[1, 4], [1, 5], [1, 6]] ], 0.5)
405413
sys1 = sys[1:, 1:]
406414
assert (sys1.ninputs, sys1.noutputs) == (2, 1)
407415
assert sys1.dt == 0.5
416+
assert sys1.input_labels == ['u[1]', 'u[2]']
417+
assert sys1.output_labels == ['y[1]']
418+
assert sys1.name == sys.name + '$indexed'
408419

409420
def test__isstatic(self):
410421
numstatic = 1.1

control/xferfcn.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -791,8 +791,7 @@ def __getitem__(self, key):
791791
if stop2 is None:
792792
stop2 = len(self.num[0])
793793

794-
num = []
795-
den = []
794+
num, den = [], []
796795
for i in range(start1, stop1, step1):
797796
num_i = []
798797
den_i = []
@@ -801,10 +800,17 @@ def __getitem__(self, key):
801800
den_i.append(self.den[i][j])
802801
num.append(num_i)
803802
den.append(den_i)
804-
if self.isctime():
805-
return TransferFunction(num, den)
806-
else:
807-
return TransferFunction(num, den, self.dt)
803+
804+
# Save the label names
805+
outputs = [self.output_labels[i] for i in range(start1, stop1, step1)]
806+
inputs = [self.input_labels[j] for j in range(start2, stop2, step2)]
807+
808+
# Create the system name
809+
sysname = config.defaults['namedio.indexed_system_name_prefix'] + \
810+
self.name + config.defaults['namedio.indexed_system_name_suffix']
811+
812+
return TransferFunction(
813+
num, den, self.dt, inputs=inputs, outputs=outputs, name=sysname)
808814

809815
def freqresp(self, omega):
810816
"""(deprecated) Evaluate transfer function at complex frequencies.

0 commit comments

Comments
 (0)