Skip to content

Commit b9cf384

Browse files
authored
Merge pull request #755 from murrayrm/timebase_bug-03Aug2022
Fix timebase bug in InterconnectedSystem (issue #754)
2 parents a73a03d + cf30479 commit b9cf384

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

control/iosys.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -871,9 +871,12 @@ def __init__(self, syslist, connections=[], inplist=[], outlist=[],
871871
if not isinstance(outlist, (list, tuple)):
872872
outlist = [outlist]
873873

874-
# Process keyword arguments
874+
# Check if dt argument was given; if not, pull from systems
875+
dt = kwargs.pop('dt', None)
876+
877+
# Process keyword arguments (except dt)
875878
defaults = {'inputs': len(inplist), 'outputs': len(outlist)}
876-
name, inputs, outputs, states, dt = _process_namedio_keywords(
879+
name, inputs, outputs, states, _ = _process_namedio_keywords(
877880
kwargs, defaults, end=True)
878881

879882
# Initialize the system list and index

control/tests/timebase_test.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import pytest
2+
import inspect
3+
import numpy as np
4+
import control as ct
5+
6+
@pytest.mark.parametrize(
7+
"dt1, dt2, dt3", [
8+
(0, 0, 0),
9+
(0, 0.1, ValueError),
10+
(0, None, 0),
11+
(0, True, ValueError),
12+
(0.1, 0, ValueError),
13+
(0.1, 0.1, 0.1),
14+
(0.1, None, 0.1),
15+
(0.1, True, 0.1),
16+
(None, 0, 0),
17+
(None, 0.1, 0.1),
18+
(None, None, None),
19+
(None, True, True),
20+
(True, 0, ValueError),
21+
(True, 0.1, 0.1),
22+
(True, None, True),
23+
(True, True, True),
24+
(0.2, None, 0.2),
25+
(0.2, 0.1, ValueError),
26+
])
27+
@pytest.mark.parametrize("op", [ct.series, ct.parallel, ct.feedback])
28+
@pytest.mark.parametrize("type", [ct.StateSpace, ct.ss, ct.tf])
29+
def test_composition(dt1, dt2, dt3, op, type):
30+
# Define the system
31+
A, B, C, D = [[1, 1], [0, 1]], [[0], [1]], [[1, 0]], 0
32+
sys1 = ct.StateSpace(A, B, C, D, dt1)
33+
sys2 = ct.StateSpace(A, B, C, D, dt2)
34+
35+
# Convert to the desired form
36+
sys1 = type(sys1)
37+
sys2 = type(sys2)
38+
39+
if inspect.isclass(dt3) and issubclass(dt3, Exception):
40+
with pytest.raises(dt3, match="incompatible timebases"):
41+
sys3 = op(sys1, sys2)
42+
else:
43+
sys3 = op(sys1, sys2)
44+
assert sys3.dt == dt3
45+
46+
47+
@pytest.mark.parametrize("dt", [None, 0, 0.1])
48+
def test_composition_override(dt):
49+
# Define the system
50+
A, B, C, D = [[1, 1], [0, 1]], [[0], [1]], [[1, 0]], 0
51+
sys1 = ct.ss(A, B, C, D, None, inputs='u1', outputs='y1')
52+
sys2 = ct.ss(A, B, C, D, None, inputs='y1', outputs='y2')
53+
54+
# Show that we can override the type
55+
sys3 = ct.interconnect([sys1, sys2], inputs='u1', outputs='y2', dt=dt)
56+
assert sys3.dt == dt
57+
58+
# Overriding the type with an inconsistent type generates an error
59+
sys1 = ct.StateSpace(A, B, C, D, 0.1, inputs='u1', outputs='y1')
60+
if dt != 0.1 and dt is not None:
61+
with pytest.raises(ValueError, match="incompatible timebases"):
62+
sys3 = ct.interconnect(
63+
[sys1, sys2], inputs='u1', outputs='y2', dt=dt)
64+
65+
sys1 = ct.StateSpace(A, B, C, D, 0, inputs='u1', outputs='y1')
66+
if dt != 0 and dt is not None:
67+
with pytest.raises(ValueError, match="incompatible timebases"):
68+
sys3 = ct.interconnect(
69+
[sys1, sys2], inputs='u1', outputs='y2', dt=dt)

0 commit comments

Comments
 (0)