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)
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