From 2e872f8da254a839e3e5488770cb040f9da76b44 Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Sat, 29 Jun 2024 10:52:38 -0700 Subject: [PATCH 1/5] fix interconnect() issue #1015 --- control/nlsys.py | 57 ++++++++++++++++++++++-------- control/tests/interconnect_test.py | 16 +++++++++ 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/control/nlsys.py b/control/nlsys.py index 358c4b125..68b744759 100644 --- a/control/nlsys.py +++ b/control/nlsys.py @@ -2219,7 +2219,7 @@ def interconnect( ... inplist=['C'], outlist=['P']) A feedback system can also be constructed using the - :func:`~control.summing_block` function and the ability to + :func:`~control.summing_junction` function and the ability to automatically interconnect signals with the same names: >>> P = ct.tf(1, [1, 0], inputs='u', outputs='y') @@ -2425,15 +2425,22 @@ def interconnect( elif not found_system: raise ValueError("could not find signal %s" % sname) else: - # Regular signal specification - if not isinstance(connection, list): - dprint(f" converting item to list") - connection = [connection] - for spec in connection: - isys, indices, gain = _parse_spec(syslist, spec, 'input') + # TODO: refactor code to remove duplication + if isinstance(connection, list): + # Passed a list => create input map + dprint(f" detected input list") + new_inplist.append([]) + for spec in connection: + isys, indices, gain = _parse_spec(syslist, spec, 'input') + for isig in indices: + new_inplist[-1].append((isys, isig, gain)) + dprint(f" adding input {(isys, isig, gain)}") + else: + # Passed a single single => single input + isys, indices, gain = _parse_spec(syslist, connection, 'input') for isig in indices: - dprint(f" adding input {(isys, isig, gain)}") new_inplist.append((isys, isig, gain)) + dprint(f" adding input {(isys, isig, gain)}") inplist, inputs = new_inplist, new_inputs dprint(f" {inplist=}\n {inputs=}") @@ -2499,14 +2506,36 @@ def interconnect( elif not found_system: raise ValueError("could not find signal %s" % sname) else: - # Regular signal specification - if not isinstance(connection, list): - dprint(f" converting item to list") - connection = [connection] - for spec in connection: + # TODO: refactor code to remove duplication + if isinstance(connection, list): + # Passed a list => create input map + dprint(f" detected output list") + new_outlist.append([]) + for spec in connection: + try: + # First trying looking in the output signals + osys, indices, gain = _parse_spec( + syslist, spec, 'output') + for osig in indices: + dprint(f" adding output {(osys, osig, gain)}") + new_outlist[-1].append((osys, osig, gain)) + except ValueError: + # If not, see if we can find it in inputs + isys, indices, gain = _parse_spec( + syslist, spec, 'input or output', + dictname='input_index') + for isig in indices: + # Use string form to allow searching input list + dprint(f" adding input {(isys, isig, gain)}") + new_outlist[-1].append( + (syslist[isys].name, + syslist[isys].input_labels[isig], gain)) + else: + spec = connection try: # First trying looking in the output signals - osys, indices, gain = _parse_spec(syslist, spec, 'output') + osys, indices, gain = _parse_spec( + syslist, spec, 'output') for osig in indices: dprint(f" adding output {(osys, osig, gain)}") new_outlist.append((osys, osig, gain)) diff --git a/control/tests/interconnect_test.py b/control/tests/interconnect_test.py index f4b0c59a8..604488ca5 100644 --- a/control/tests/interconnect_test.py +++ b/control/tests/interconnect_test.py @@ -689,3 +689,19 @@ def test_interconnect_params(): timepts = np.linspace(0, 10) resp = ct.input_output_response(sys, timepts, 0, params={'a': -1}) assert resp.states[0, -1].item() < 2 * math.exp(-10) + + +# Bug identified in issue #1015 +def test_parallel_interconnect(): + sys1 = ct.rss(2, 1, 1, name='S1') + sys2 = ct.rss(2, 1, 1, name='S2') + + sys_bd = sys1 + sys2 + sys_ic = ct.interconnect( + [sys1, sys2], + inplist=[['S1.u[0]', 'S2.u[0]']], + outlist=[['S1.y[0]', 'S2.y[0]']]) + np.testing.assert_allclose(sys_bd.A, sys_ic.A) + np.testing.assert_allclose(sys_bd.B, sys_ic.B) + np.testing.assert_allclose(sys_bd.C, sys_ic.C) + np.testing.assert_allclose(sys_bd.D, sys_ic.D) From 421131ceb316a0d8c838e187714de7c88976c0aa Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Sun, 30 Jun 2024 10:11:31 -0700 Subject: [PATCH 2/5] updated documentation per comment from @bonidydy in #1015 --- control/nlsys.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/control/nlsys.py b/control/nlsys.py index 68b744759..d0ad2c661 100644 --- a/control/nlsys.py +++ b/control/nlsys.py @@ -2086,10 +2086,8 @@ def interconnect( inplist : list of input connections, optional List of connections for how the inputs for the overall system are - mapped to the subsystem inputs. The input specification is similar to - the form defined in the connection specification, except that - connections do not specify an input-spec, since these are the system - inputs. The entries for a connection are thus of the form: + mapped to the subsystem inputs. The entries for a connection are + of the form: [input-spec1, input-spec2, ...] @@ -2102,11 +2100,10 @@ def interconnect( outlist : list of output connections, optional List of connections for how the outputs from the subsystems are - mapped to overall system outputs. The output connection - description is the same as the form defined in the inplist - specification (including the optional gain term). Numbered outputs - must be chosen from the list of subsystem outputs, but named - outputs can also be contained in the list of subsystem inputs. + mapped to overall system outputs. The entris for a connection are + of the form: + + [output-spec1, output-spec2, ...] If an output connection contains more than one signal specification, then those signals are added together (multiplying by the any gain From 1964a866c5ab97c6c5b02885346e9a569783d6a1 Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Mon, 1 Jul 2024 19:37:34 -0700 Subject: [PATCH 3/5] code cleanup --- control/nlsys.py | 60 +++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/control/nlsys.py b/control/nlsys.py index d0ad2c661..a6e9043da 100644 --- a/control/nlsys.py +++ b/control/nlsys.py @@ -2422,18 +2422,18 @@ def interconnect( elif not found_system: raise ValueError("could not find signal %s" % sname) else: - # TODO: refactor code to remove duplication if isinstance(connection, list): # Passed a list => create input map dprint(f" detected input list") - new_inplist.append([]) + signal_list = [] for spec in connection: isys, indices, gain = _parse_spec(syslist, spec, 'input') for isig in indices: - new_inplist[-1].append((isys, isig, gain)) - dprint(f" adding input {(isys, isig, gain)}") + signal_list.append((isys, isig, gain)) + dprint(f" adding input {(isys, isig, gain)} to list") + new_inplist.append(signal_list) else: - # Passed a single single => single input + # Passed a single signal name => add individual input(s) isys, indices, gain = _parse_spec(syslist, connection, 'input') for isig in indices: new_inplist.append((isys, isig, gain)) @@ -2503,39 +2503,15 @@ def interconnect( elif not found_system: raise ValueError("could not find signal %s" % sname) else: - # TODO: refactor code to remove duplication - if isinstance(connection, list): - # Passed a list => create input map - dprint(f" detected output list") - new_outlist.append([]) - for spec in connection: - try: - # First trying looking in the output signals - osys, indices, gain = _parse_spec( - syslist, spec, 'output') - for osig in indices: - dprint(f" adding output {(osys, osig, gain)}") - new_outlist[-1].append((osys, osig, gain)) - except ValueError: - # If not, see if we can find it in inputs - isys, indices, gain = _parse_spec( - syslist, spec, 'input or output', - dictname='input_index') - for isig in indices: - # Use string form to allow searching input list - dprint(f" adding input {(isys, isig, gain)}") - new_outlist[-1].append( - (syslist[isys].name, - syslist[isys].input_labels[isig], gain)) - else: - spec = connection + # Utility function to find named output or input signal + def _find_output_or_input_signal(spec): + signal_list = [] try: # First trying looking in the output signals - osys, indices, gain = _parse_spec( - syslist, spec, 'output') + osys, indices, gain = _parse_spec(syslist, spec, 'output') for osig in indices: - dprint(f" adding output {(osys, osig, gain)}") - new_outlist.append((osys, osig, gain)) + dprint(f" adding output {(osys, osig, gain)}") + signal_list.append((osys, osig, gain)) except ValueError: # If not, see if we can find it in inputs isys, indices, gain = _parse_spec( @@ -2544,9 +2520,21 @@ def interconnect( for isig in indices: # Use string form to allow searching input list dprint(f" adding input {(isys, isig, gain)}") - new_outlist.append( + signal_list.append( (syslist[isys].name, syslist[isys].input_labels[isig], gain)) + return signal_list + + if isinstance(connection, list): + # Passed a list => create input map + dprint(f" detected output list") + signal_list = [] + for spec in connection: + signal_list += _find_output_or_input_signal(spec) + new_outlist.append(signal_list) + else: + new_outlist += _find_output_or_input_signal(connection) + outlist, outputs = new_outlist, new_outputs dprint(f" {outlist=}\n {outputs=}") From 9a78e33a65ff43b59694dd269b90bd025317806a Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Tue, 2 Jul 2024 07:13:06 -0700 Subject: [PATCH 4/5] fix type pointed out by @sawyerbfuller --- control/nlsys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/nlsys.py b/control/nlsys.py index a6e9043da..c9af0b826 100644 --- a/control/nlsys.py +++ b/control/nlsys.py @@ -2100,7 +2100,7 @@ def interconnect( outlist : list of output connections, optional List of connections for how the outputs from the subsystems are - mapped to overall system outputs. The entris for a connection are + mapped to overall system outputs. The entries for a connection are of the form: [output-spec1, output-spec2, ...] From 584f39d8882fce70ed203acdb2800800b80148c7 Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Sat, 6 Jul 2024 18:45:59 -0700 Subject: [PATCH 5/5] fixed small indent error --- control/nlsys.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/control/nlsys.py b/control/nlsys.py index c9af0b826..a14de1d9c 100644 --- a/control/nlsys.py +++ b/control/nlsys.py @@ -2510,8 +2510,8 @@ def _find_output_or_input_signal(spec): # First trying looking in the output signals osys, indices, gain = _parse_spec(syslist, spec, 'output') for osig in indices: - dprint(f" adding output {(osys, osig, gain)}") - signal_list.append((osys, osig, gain)) + dprint(f" adding output {(osys, osig, gain)}") + signal_list.append((osys, osig, gain)) except ValueError: # If not, see if we can find it in inputs isys, indices, gain = _parse_spec( 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