Skip to content

Commit 8c1ddec

Browse files
authored
Merge pull request #1017 from murrayrm/interconnect_bug-29Jun2024
fix parallel input or output interconnect bug (issue #1015)
2 parents f49dbcf + 584f39d commit 8c1ddec

File tree

2 files changed

+54
-24
lines changed

2 files changed

+54
-24
lines changed

control/nlsys.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,10 +2086,8 @@ def interconnect(
20862086
20872087
inplist : list of input connections, optional
20882088
List of connections for how the inputs for the overall system are
2089-
mapped to the subsystem inputs. The input specification is similar to
2090-
the form defined in the connection specification, except that
2091-
connections do not specify an input-spec, since these are the system
2092-
inputs. The entries for a connection are thus of the form:
2089+
mapped to the subsystem inputs. The entries for a connection are
2090+
of the form:
20932091
20942092
[input-spec1, input-spec2, ...]
20952093
@@ -2102,11 +2100,10 @@ def interconnect(
21022100
21032101
outlist : list of output connections, optional
21042102
List of connections for how the outputs from the subsystems are
2105-
mapped to overall system outputs. The output connection
2106-
description is the same as the form defined in the inplist
2107-
specification (including the optional gain term). Numbered outputs
2108-
must be chosen from the list of subsystem outputs, but named
2109-
outputs can also be contained in the list of subsystem inputs.
2103+
mapped to overall system outputs. The entries for a connection are
2104+
of the form:
2105+
2106+
[output-spec1, output-spec2, ...]
21102107
21112108
If an output connection contains more than one signal specification,
21122109
then those signals are added together (multiplying by the any gain
@@ -2219,7 +2216,7 @@ def interconnect(
22192216
... inplist=['C'], outlist=['P'])
22202217
22212218
A feedback system can also be constructed using the
2222-
:func:`~control.summing_block` function and the ability to
2219+
:func:`~control.summing_junction` function and the ability to
22232220
automatically interconnect signals with the same names:
22242221
22252222
>>> P = ct.tf(1, [1, 0], inputs='u', outputs='y')
@@ -2425,15 +2422,22 @@ def interconnect(
24252422
elif not found_system:
24262423
raise ValueError("could not find signal %s" % sname)
24272424
else:
2428-
# Regular signal specification
2429-
if not isinstance(connection, list):
2430-
dprint(f" converting item to list")
2431-
connection = [connection]
2432-
for spec in connection:
2433-
isys, indices, gain = _parse_spec(syslist, spec, 'input')
2425+
if isinstance(connection, list):
2426+
# Passed a list => create input map
2427+
dprint(f" detected input list")
2428+
signal_list = []
2429+
for spec in connection:
2430+
isys, indices, gain = _parse_spec(syslist, spec, 'input')
2431+
for isig in indices:
2432+
signal_list.append((isys, isig, gain))
2433+
dprint(f" adding input {(isys, isig, gain)} to list")
2434+
new_inplist.append(signal_list)
2435+
else:
2436+
# Passed a single signal name => add individual input(s)
2437+
isys, indices, gain = _parse_spec(syslist, connection, 'input')
24342438
for isig in indices:
2435-
dprint(f" adding input {(isys, isig, gain)}")
24362439
new_inplist.append((isys, isig, gain))
2440+
dprint(f" adding input {(isys, isig, gain)}")
24372441
inplist, inputs = new_inplist, new_inputs
24382442
dprint(f" {inplist=}\n {inputs=}")
24392443

@@ -2499,17 +2503,15 @@ def interconnect(
24992503
elif not found_system:
25002504
raise ValueError("could not find signal %s" % sname)
25012505
else:
2502-
# Regular signal specification
2503-
if not isinstance(connection, list):
2504-
dprint(f" converting item to list")
2505-
connection = [connection]
2506-
for spec in connection:
2506+
# Utility function to find named output or input signal
2507+
def _find_output_or_input_signal(spec):
2508+
signal_list = []
25072509
try:
25082510
# First trying looking in the output signals
25092511
osys, indices, gain = _parse_spec(syslist, spec, 'output')
25102512
for osig in indices:
25112513
dprint(f" adding output {(osys, osig, gain)}")
2512-
new_outlist.append((osys, osig, gain))
2514+
signal_list.append((osys, osig, gain))
25132515
except ValueError:
25142516
# If not, see if we can find it in inputs
25152517
isys, indices, gain = _parse_spec(
@@ -2518,9 +2520,21 @@ def interconnect(
25182520
for isig in indices:
25192521
# Use string form to allow searching input list
25202522
dprint(f" adding input {(isys, isig, gain)}")
2521-
new_outlist.append(
2523+
signal_list.append(
25222524
(syslist[isys].name,
25232525
syslist[isys].input_labels[isig], gain))
2526+
return signal_list
2527+
2528+
if isinstance(connection, list):
2529+
# Passed a list => create input map
2530+
dprint(f" detected output list")
2531+
signal_list = []
2532+
for spec in connection:
2533+
signal_list += _find_output_or_input_signal(spec)
2534+
new_outlist.append(signal_list)
2535+
else:
2536+
new_outlist += _find_output_or_input_signal(connection)
2537+
25242538
outlist, outputs = new_outlist, new_outputs
25252539
dprint(f" {outlist=}\n {outputs=}")
25262540

control/tests/interconnect_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,19 @@ def test_interconnect_params():
689689
timepts = np.linspace(0, 10)
690690
resp = ct.input_output_response(sys, timepts, 0, params={'a': -1})
691691
assert resp.states[0, -1].item() < 2 * math.exp(-10)
692+
693+
694+
# Bug identified in issue #1015
695+
def test_parallel_interconnect():
696+
sys1 = ct.rss(2, 1, 1, name='S1')
697+
sys2 = ct.rss(2, 1, 1, name='S2')
698+
699+
sys_bd = sys1 + sys2
700+
sys_ic = ct.interconnect(
701+
[sys1, sys2],
702+
inplist=[['S1.u[0]', 'S2.u[0]']],
703+
outlist=[['S1.y[0]', 'S2.y[0]']])
704+
np.testing.assert_allclose(sys_bd.A, sys_ic.A)
705+
np.testing.assert_allclose(sys_bd.B, sys_ic.B)
706+
np.testing.assert_allclose(sys_bd.C, sys_ic.C)
707+
np.testing.assert_allclose(sys_bd.D, sys_ic.D)

0 commit comments

Comments
 (0)