@@ -616,7 +616,7 @@ class LinearIOSystem(InputOutputSystem, StateSpace):
616
616
617
617
"""
618
618
def __init__ (self , linsys , inputs = None , outputs = None , states = None ,
619
- name = None ):
619
+ name = None , ** kwargs ):
620
620
"""Create an I/O system from a state space linear system.
621
621
622
622
Converts a :class:`~control.StateSpace` system into an
@@ -662,6 +662,10 @@ def __init__(self, linsys, inputs=None, outputs=None, states=None,
662
662
if not isinstance (linsys , StateSpace ):
663
663
raise TypeError ("Linear I/O system must be a state space object" )
664
664
665
+ # Look for 'input' and 'output' parameter name variants
666
+ inputs = _parse_signal_parameter (inputs , 'input' , kwargs )
667
+ outputs = _parse_signal_parameter (outputs , 'output' , kwargs , end = True )
668
+
665
669
# Create the I/O system object
666
670
super (LinearIOSystem , self ).__init__ (
667
671
inputs = linsys .ninputs , outputs = linsys .noutputs ,
@@ -711,8 +715,7 @@ class NonlinearIOSystem(InputOutputSystem):
711
715
712
716
"""
713
717
def __init__ (self , updfcn , outfcn = None , inputs = None , outputs = None ,
714
- states = None , params = {},
715
- name = None , ** kwargs ):
718
+ states = None , params = {}, name = None , ** kwargs ):
716
719
"""Create a nonlinear I/O system given update and output functions.
717
720
718
721
Creates an :class:`~control.InputOutputSystem` for a nonlinear system
@@ -779,17 +782,25 @@ def __init__(self, updfcn, outfcn=None, inputs=None, outputs=None,
779
782
Nonlinear system represented as an input/output system.
780
783
781
784
"""
785
+ # Look for 'input' and 'output' parameter name variants
786
+ inputs = _parse_signal_parameter (inputs , 'input' , kwargs )
787
+ outputs = _parse_signal_parameter (outputs , 'output' , kwargs )
788
+
782
789
# Store the update and output functions
783
790
self .updfcn = updfcn
784
791
self .outfcn = outfcn
785
792
786
793
# Initialize the rest of the structure
787
- dt = kwargs .get ('dt' , config .defaults ['control.default_dt' ])
794
+ dt = kwargs .pop ('dt' , config .defaults ['control.default_dt' ])
788
795
super (NonlinearIOSystem , self ).__init__ (
789
796
inputs = inputs , outputs = outputs , states = states ,
790
797
params = params , dt = dt , name = name
791
798
)
792
799
800
+ # Make sure all input arguments got parsed
801
+ if kwargs :
802
+ raise TypeError ("unknown parameters %s" % kwargs )
803
+
793
804
# Check to make sure arguments are consistent
794
805
if updfcn is None :
795
806
if self .nstates is None :
@@ -874,7 +885,7 @@ class InterconnectedSystem(InputOutputSystem):
874
885
"""
875
886
def __init__ (self , syslist , connections = [], inplist = [], outlist = [],
876
887
inputs = None , outputs = None , states = None ,
877
- params = {}, dt = None , name = None ):
888
+ params = {}, dt = None , name = None , ** kwargs ):
878
889
"""Create an I/O system from a list of systems + connection info.
879
890
880
891
The InterconnectedSystem class is used to represent an input/output
@@ -886,6 +897,10 @@ def __init__(self, syslist, connections=[], inplist=[], outlist=[],
886
897
See :func:`~control.interconnect` for a list of parameters.
887
898
888
899
"""
900
+ # Look for 'input' and 'output' parameter name variants
901
+ inputs = _parse_signal_parameter (inputs , 'input' , kwargs )
902
+ outputs = _parse_signal_parameter (outputs , 'output' , kwargs , end = True )
903
+
889
904
# Convert input and output names to lists if they aren't already
890
905
if not isinstance (inplist , (list , tuple )):
891
906
inplist = [inplist ]
@@ -1850,6 +1865,15 @@ def linearize(sys, xeq, ueq=[], t=0, params={}, **kw):
1850
1865
return sys .linearize (xeq , ueq , t = t , params = params , ** kw )
1851
1866
1852
1867
1868
+ # Utility function to parse a signal parameter
1869
+ def _parse_signal_parameter (value , name , kwargs , end = False ):
1870
+ if value is None and name in kwargs :
1871
+ value = list (kwargs .pop (name ))
1872
+ if end and kwargs :
1873
+ raise TypeError ("unknown parameters %s" % kwargs )
1874
+ return value
1875
+
1876
+
1853
1877
def _find_size (sysval , vecval ):
1854
1878
"""Utility function to find the size of a system parameter
1855
1879
@@ -1889,7 +1913,7 @@ def tf2io(*args, **kwargs):
1889
1913
# Function to create an interconnected system
1890
1914
def interconnect (syslist , connections = None , inplist = [], outlist = [],
1891
1915
inputs = None , outputs = None , states = None ,
1892
- params = {}, dt = None , name = None ):
1916
+ params = {}, dt = None , name = None , ** kwargs ):
1893
1917
"""Interconnect a set of input/output systems.
1894
1918
1895
1919
This function creates a new system that is an interconnection of a set of
@@ -2035,7 +2059,7 @@ def interconnect(syslist, connections=None, inplist=[], outlist=[],
2035
2059
>>> P = control.tf2io(control.tf(1, [1, 0]), inputs='u', outputs='y')
2036
2060
>>> C = control.tf2io(control.tf(10, [1, 1]), inputs='e', outputs='u')
2037
2061
>>> sumblk = control.summing_junction(inputs=['r', '-y'], output='e')
2038
- >>> T = control.interconnect([P, C, sumblk], inplist ='r', outlist ='y')
2062
+ >>> T = control.interconnect([P, C, sumblk], input ='r', output ='y')
2039
2063
2040
2064
Notes
2041
2065
-----
@@ -2060,7 +2084,14 @@ def interconnect(syslist, connections=None, inplist=[], outlist=[],
2060
2084
treated as both a :class:`~control.StateSpace` system as well as an
2061
2085
:class:`~control.InputOutputSystem`.
2062
2086
2087
+ The `input` and `output` keywords can be used instead of `inputs` and
2088
+ `outputs`, for more natural naming of SISO systems.
2089
+
2063
2090
"""
2091
+ # Look for 'input' and 'output' parameter name variants
2092
+ inputs = _parse_signal_parameter (inputs , 'input' , kwargs )
2093
+ outputs = _parse_signal_parameter (outputs , 'output' , kwargs , end = True )
2094
+
2064
2095
# If connections was not specified, set up default connection list
2065
2096
if connections is None :
2066
2097
# For each system input, look for outputs with the same name
@@ -2077,30 +2108,36 @@ def interconnect(syslist, connections=None, inplist=[], outlist=[],
2077
2108
# Use an empty connections list
2078
2109
connections = []
2079
2110
2111
+ # If inplist/outlist is not present, try using inputs/outputs instead
2112
+ if not inplist and inputs is not None :
2113
+ inplist = list (inputs )
2114
+ if not outlist and outputs is not None :
2115
+ outlist = list (outputs )
2116
+
2080
2117
# Process input list
2081
2118
if not isinstance (inplist , (list , tuple )):
2082
2119
inplist = [inplist ]
2083
2120
new_inplist = []
2084
2121
for signal in inplist :
2122
+ # Create an empty connection and append to inplist
2123
+ connection = []
2124
+
2085
2125
# Check for signal names without a system name
2086
2126
if isinstance (signal , str ) and len (signal .split ('.' )) == 1 :
2087
2127
# Get the signal name
2088
2128
name = signal [1 :] if signal [0 ] == '-' else signal
2089
2129
sign = '-' if signal [0 ] == '-' else ""
2090
2130
2091
2131
# Look for the signal name as a system input
2092
- new_name = None
2093
2132
for sys in syslist :
2094
2133
if name in sys .input_index .keys ():
2095
- if new_name is not None :
2096
- raise ValueError ("signal %s is not unique" % name )
2097
- new_name = sign + sys .name + "." + name
2134
+ connection .append (sign + sys .name + "." + name )
2098
2135
2099
2136
# Make sure we found the name
2100
- if new_name is None :
2137
+ if len ( connection ) == 0 :
2101
2138
raise ValueError ("could not find signal %s" % name )
2102
2139
else :
2103
- new_inplist .append (new_name )
2140
+ new_inplist .append (connection )
2104
2141
else :
2105
2142
new_inplist .append (signal )
2106
2143
inplist = new_inplist
@@ -2110,25 +2147,25 @@ def interconnect(syslist, connections=None, inplist=[], outlist=[],
2110
2147
outlist = [outlist ]
2111
2148
new_outlist = []
2112
2149
for signal in outlist :
2150
+ # Create an empty connection and append to inplist
2151
+ connection = []
2152
+
2113
2153
# Check for signal names without a system name
2114
2154
if isinstance (signal , str ) and len (signal .split ('.' )) == 1 :
2115
2155
# Get the signal name
2116
2156
name = signal [1 :] if signal [0 ] == '-' else signal
2117
2157
sign = '-' if signal [0 ] == '-' else ""
2118
2158
2119
2159
# Look for the signal name as a system output
2120
- new_name = None
2121
2160
for sys in syslist :
2122
2161
if name in sys .output_index .keys ():
2123
- if new_name is not None :
2124
- raise ValueError ("signal %s is not unique" % name )
2125
- new_name = sign + sys .name + "." + name
2162
+ connection .append (sign + sys .name + "." + name )
2126
2163
2127
2164
# Make sure we found the name
2128
- if new_name is None :
2165
+ if len ( connection ) == 0 :
2129
2166
raise ValueError ("could not find signal %s" % name )
2130
2167
else :
2131
- new_outlist .append (new_name )
2168
+ new_outlist .append (connection )
2132
2169
else :
2133
2170
new_outlist .append (signal )
2134
2171
outlist = new_outlist
@@ -2146,7 +2183,9 @@ def interconnect(syslist, connections=None, inplist=[], outlist=[],
2146
2183
2147
2184
2148
2185
# Summing junction
2149
- def summing_junction (inputs , output = 'y' , dimension = None , name = None , prefix = 'u' ):
2186
+ def summing_junction (
2187
+ inputs = None , output = None , dimension = None , name = None ,
2188
+ prefix = 'u' , ** kwargs ):
2150
2189
"""Create a summing junction as an input/output system.
2151
2190
2152
2191
This function creates a static input/output system that outputs the sum of
@@ -2185,10 +2224,10 @@ def summing_junction(inputs, output='y', dimension=None, name=None, prefix='u'):
2185
2224
2186
2225
Example
2187
2226
-------
2188
- >>> P = control.tf2io(ct.tf(1, [1, 0]), inputs ='u', outputs ='y')
2189
- >>> C = control.tf2io(ct.tf(10, [1, 1]), inputs ='e', outputs ='u')
2227
+ >>> P = control.tf2io(ct.tf(1, [1, 0]), input ='u', output ='y')
2228
+ >>> C = control.tf2io(ct.tf(10, [1, 1]), input ='e', output ='u')
2190
2229
>>> sumblk = control.summing_junction(inputs=['r', '-y'], output='e')
2191
- >>> T = control.interconnect((P, C, sumblk), inplist ='r', outlist ='y')
2230
+ >>> T = control.interconnect((P, C, sumblk), input ='r', output ='y')
2192
2231
2193
2232
"""
2194
2233
# Utility function to parse input and output signal lists
@@ -2221,6 +2260,16 @@ def _parse_list(signals, signame='input', prefix='u'):
2221
2260
# Return the parsed list
2222
2261
return nsignals , names , gains
2223
2262
2263
+ # Look for 'input' and 'output' parameter name variants
2264
+ inputs = _parse_signal_parameter (inputs , 'input' , kwargs )
2265
+ output = _parse_signal_parameter (output , 'outputs' , kwargs , end = True )
2266
+
2267
+ # Default values for inputs and output
2268
+ if inputs is None :
2269
+ raise TypeError ("input specification is required" )
2270
+ if output is None :
2271
+ output = 'y'
2272
+
2224
2273
# Read the input list
2225
2274
ninputs , input_names , input_gains = _parse_list (
2226
2275
inputs , signame = "input" , prefix = prefix )
0 commit comments