@@ -676,6 +676,12 @@ def __init__(self, linsys, **kwargs):
676676 StateSpace .__init__ (
677677 self , linsys , remove_useless_states = False , init_namedio = False )
678678
679+ # When sampling a LinearIO system, return a LinearIOSystem
680+ def sample (self , * args , ** kwargs ):
681+ return LinearIOSystem (StateSpace .sample (self , * args , ** kwargs ))
682+
683+ sample .__doc__ = StateSpace .sample .__doc__
684+
679685 # The following text needs to be replicated from StateSpace in order for
680686 # this entry to show up properly in sphinx doccumentation (not sure why,
681687 # but it was the only way to get it to work).
@@ -1373,13 +1379,11 @@ def unused_signals(self):
13731379 -------
13741380
13751381 unused_inputs : dict
1376-
13771382 A mapping from tuple of indices (isys, isig) to string
13781383 '{sys}.{sig}', for all unused subsystem inputs.
13791384
13801385 unused_outputs : dict
1381-
1382- A mapping from tuple of indices (isys, isig) to string
1386+ A mapping from tuple of indices (osys, osig) to string
13831387 '{sys}.{sig}', for all unused subsystem outputs.
13841388
13851389 """
@@ -1433,10 +1437,13 @@ def _find_outputs_by_basename(self, basename):
14331437 for sig , isig in sys .output_index .items ()
14341438 if sig == (basename )}
14351439
1436- def check_unused_signals (self , ignore_inputs = None , ignore_outputs = None ):
1440+ def check_unused_signals (
1441+ self , ignore_inputs = None , ignore_outputs = None , warning = True ):
14371442 """Check for unused subsystem inputs and outputs
14381443
1439- If any unused inputs or outputs are found, emit a warning.
1444+ Check to see if there are any unused signals and return a list of
1445+ unused input and output signal descriptions. If `warning` is True
1446+ and any unused inputs or outputs are found, emit a warning.
14401447
14411448 Parameters
14421449 ----------
@@ -1454,6 +1461,16 @@ def check_unused_signals(self, ignore_inputs=None, ignore_outputs=None):
14541461 If the 'sig' form is used, all subsystem outputs with that
14551462 name are considered ignored.
14561463
1464+ Returns
1465+ -------
1466+ dropped_inputs: list of tuples
1467+ A list of the dropped input signals, with each element of the
1468+ list in the form of (isys, isig).
1469+
1470+ dropped_outputs: list of tuples
1471+ A list of the dropped output signals, with each element of the
1472+ list in the form of (osys, osig).
1473+
14571474 """
14581475
14591476 if ignore_inputs is None :
@@ -1477,7 +1494,7 @@ def check_unused_signals(self, ignore_inputs=None, ignore_outputs=None):
14771494 ignore_input_map [self ._parse_signal (
14781495 ignore_input , 'input' )[:2 ]] = ignore_input
14791496
1480- # (isys, isig ) -> signal-spec
1497+ # (osys, osig ) -> signal-spec
14811498 ignore_output_map = {}
14821499 for ignore_output in ignore_outputs :
14831500 if isinstance (ignore_output , str ) and '.' not in ignore_output :
@@ -1496,30 +1513,32 @@ def check_unused_signals(self, ignore_inputs=None, ignore_outputs=None):
14961513 used_ignored_inputs = set (ignore_input_map ) - set (unused_inputs )
14971514 used_ignored_outputs = set (ignore_output_map ) - set (unused_outputs )
14981515
1499- if dropped_inputs :
1516+ if warning and dropped_inputs :
15001517 msg = ('Unused input(s) in InterconnectedSystem: '
15011518 + '; ' .join (f'{ inp } ={ unused_inputs [inp ]} '
15021519 for inp in dropped_inputs ))
15031520 warn (msg )
15041521
1505- if dropped_outputs :
1522+ if warning and dropped_outputs :
15061523 msg = ('Unused output(s) in InterconnectedSystem: '
15071524 + '; ' .join (f'{ out } : { unused_outputs [out ]} '
15081525 for out in dropped_outputs ))
15091526 warn (msg )
15101527
1511- if used_ignored_inputs :
1528+ if warning and used_ignored_inputs :
15121529 msg = ('Input(s) specified as ignored is (are) used: '
15131530 + '; ' .join (f'{ inp } : { ignore_input_map [inp ]} '
15141531 for inp in used_ignored_inputs ))
15151532 warn (msg )
15161533
1517- if used_ignored_outputs :
1534+ if warning and used_ignored_outputs :
15181535 msg = ('Output(s) specified as ignored is (are) used: '
15191536 + '; ' .join (f'{ out } ={ ignore_output_map [out ]} '
15201537 for out in used_ignored_outputs ))
15211538 warn (msg )
15221539
1540+ return dropped_inputs , dropped_outputs
1541+
15231542
15241543class LinearICSystem (InterconnectedSystem , LinearIOSystem ):
15251544
@@ -2580,9 +2599,10 @@ def tf2io(*args, **kwargs):
25802599
25812600
25822601# Function to create an interconnected system
2583- def interconnect (syslist , connections = None , inplist = None , outlist = None ,
2584- params = None , check_unused = True , ignore_inputs = None ,
2585- ignore_outputs = None , warn_duplicate = None , ** kwargs ):
2602+ def interconnect (
2603+ syslist , connections = None , inplist = None , outlist = None , params = None ,
2604+ check_unused = True , add_unused = False , ignore_inputs = None ,
2605+ ignore_outputs = None , warn_duplicate = None , ** kwargs ):
25862606 """Interconnect a set of input/output systems.
25872607
25882608 This function creates a new system that is an interconnection of a set of
@@ -2653,8 +2673,8 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None,
26532673 the system input connects to only one subsystem input, a single input
26542674 specification can be given (without the inner list).
26552675
2656- If omitted, the input map can be specified using the
2657- :func:`~control.InterconnectedSystem.set_input_map` method .
2676+ If omitted the ` input` parameter will be used to identify the list
2677+ of input signals to the overall system .
26582678
26592679 outlist : list of output connections, optional
26602680 List of connections for how the outputs from the subsystems are mapped
@@ -2707,12 +2727,16 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None,
27072727 System name (used for specifying signals). If unspecified, a generic
27082728 name <sys[id]> is generated with a unique integer id.
27092729
2710- check_unused : bool
2730+ check_unused : bool, optional
27112731 If True, check for unused sub-system signals. This check is
27122732 not done if connections is False, and neither input nor output
27132733 mappings are specified.
27142734
2715- ignore_inputs : list of input-spec
2735+ add_unused : bool, optional
2736+ If True, subsystem signals that are not connected to other components
2737+ are added as inputs and outputs of the interconnected system.
2738+
2739+ ignore_inputs : list of input-spec, optional
27162740 A list of sub-system inputs known not to be connected. This is
27172741 *only* used in checking for unused signals, and does not
27182742 disable use of the input.
@@ -2722,7 +2746,7 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None,
27222746 signals from all sub-systems with that base name are
27232747 considered ignored.
27242748
2725- ignore_outputs : list of output-spec
2749+ ignore_outputs : list of output-spec, optional
27262750 A list of sub-system outputs known not to be connected. This
27272751 is *only* used in checking for unused signals, and does not
27282752 disable use of the output.
@@ -2732,7 +2756,7 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None,
27322756 outputs from all sub-systems with that base name are
27332757 considered ignored.
27342758
2735- warn_duplicate : None, True, or False
2759+ warn_duplicate : None, True, or False, optional
27362760 Control how warnings are generated if duplicate objects or names are
27372761 detected. In `None` (default), then warnings are generated for
27382762 systems that have non-generic names. If `False`, warnings are not
@@ -2886,10 +2910,30 @@ def interconnect(syslist, connections=None, inplist=None, outlist=None,
28862910 outlist = new_outlist
28872911
28882912 newsys = InterconnectedSystem (
2889- syslist , connections = connections , inplist = inplist , outlist = outlist ,
2890- inputs = inputs , outputs = outputs , states = states ,
2913+ syslist , connections = connections , inplist = inplist ,
2914+ outlist = outlist , inputs = inputs , outputs = outputs , states = states ,
28912915 params = params , dt = dt , name = name , warn_duplicate = warn_duplicate )
28922916
2917+ # See if we should add any signals
2918+ if add_unused :
2919+ # Get all unused signals
2920+ dropped_inputs , dropped_outputs = newsys .check_unused_signals (
2921+ ignore_inputs , ignore_outputs , warning = False )
2922+
2923+ # Add on any unused signals that we aren't ignoring
2924+ for isys , isig in dropped_inputs :
2925+ inplist .append ((isys , isig ))
2926+ inputs .append (newsys .syslist [isys ].input_labels [isig ])
2927+ for osys , osig in dropped_outputs :
2928+ outlist .append ((osys , osig ))
2929+ outputs .append (newsys .syslist [osys ].output_labels [osig ])
2930+
2931+ # Rebuild the system with new inputs/outputs
2932+ newsys = InterconnectedSystem (
2933+ syslist , connections = connections , inplist = inplist ,
2934+ outlist = outlist , inputs = inputs , outputs = outputs , states = states ,
2935+ params = params , dt = dt , name = name , warn_duplicate = warn_duplicate )
2936+
28932937 # check for implicitly dropped signals
28942938 if check_unused :
28952939 newsys .check_unused_signals (ignore_inputs , ignore_outputs )
0 commit comments