3838
3939from .statesp import StateSpace , tf2ss
4040from .timeresp import _check_convert_array
41- from .lti import isctime , isdtime , _find_timebase
41+ from .lti import isctime , isdtime , common_timebase
42+ from . import config
4243
4344__all__ = ['InputOutputSystem' , 'LinearIOSystem' , 'NonlinearIOSystem' ,
4445 'InterconnectedSystem' , 'input_output_response' , 'find_eqpt' ,
4546 'linearize' , 'ss2io' , 'tf2io' ]
4647
48+ # Define module default parameter values
49+ _iosys_defaults = {}
4750
4851class InputOutputSystem (object ):
4952 """A class for representing input/output systems.
@@ -69,9 +72,11 @@ class for a set of subclasses that are used to implement specific
6972 states : int, list of str, or None
7073 Description of the system states. Same format as `inputs`.
7174 dt : None, True or float, optional
72- System timebase. None (default) indicates continuous time, True
73- indicates discrete time with undefined sampling time, positive number
74- is discrete time with specified sampling time.
75+ System timebase. 0 (default) indicates continuous
76+ time, True indicates discrete time with unspecified sampling
77+ time, positive number is discrete time with specified
78+ sampling time, None indicates unspecified timebase (either
79+ continuous or discrete time).
7580 params : dict, optional
7681 Parameter values for the systems. Passed to the evaluation functions
7782 for the system as default values, overriding internal defaults.
@@ -87,9 +92,11 @@ class for a set of subclasses that are used to implement specific
8792 Dictionary of signal names for the inputs, outputs and states and the
8893 index of the corresponding array
8994 dt : None, True or float
90- System timebase. None (default) indicates continuous time, True
91- indicates discrete time with undefined sampling time, positive number
92- is discrete time with specified sampling time.
95+ System timebase. 0 (default) indicates continuous
96+ time, True indicates discrete time with unspecified sampling
97+ time, positive number is discrete time with specified
98+ sampling time, None indicates unspecified timebase (either
99+ continuous or discrete time).
93100 params : dict, optional
94101 Parameter values for the systems. Passed to the evaluation functions
95102 for the system as default values, overriding internal defaults.
@@ -118,7 +125,7 @@ def name_or_default(self, name=None):
118125 return name
119126
120127 def __init__ (self , inputs = None , outputs = None , states = None , params = {},
121- dt = None , name = None ):
128+ name = None , ** kwargs ):
122129 """Create an input/output system.
123130
124131 The InputOutputSystem contructor is used to create an input/output
@@ -143,10 +150,11 @@ def __init__(self, inputs=None, outputs=None, states=None, params={},
143150 states : int, list of str, or None
144151 Description of the system states. Same format as `inputs`.
145152 dt : None, True or float, optional
146- System timebase. None (default) indicates continuous
147- time, True indicates discrete time with undefined sampling
153+ System timebase. 0 (default) indicates continuous
154+ time, True indicates discrete time with unspecified sampling
148155 time, positive number is discrete time with specified
149- sampling time.
156+ sampling time, None indicates unspecified timebase (either
157+ continuous or discrete time).
150158 params : dict, optional
151159 Parameter values for the systems. Passed to the evaluation
152160 functions for the system as default values, overriding internal
@@ -162,9 +170,13 @@ def __init__(self, inputs=None, outputs=None, states=None, params={},
162170
163171 """
164172 # Store the input arguments
165- self .params = params .copy () # default parameters
166- self .dt = dt # timebase
167- self .name = self .name_or_default (name ) # system name
173+
174+ # default parameters
175+ self .params = params .copy ()
176+ # timebase
177+ self .dt = kwargs .get ('dt' , config .defaults ['control.default_dt' ])
178+ # system name
179+ self .name = self .name_or_default (name )
168180
169181 # Parse and store the number of inputs, outputs, and states
170182 self .set_inputs (inputs )
@@ -210,9 +222,7 @@ def __mul__(sys2, sys1):
210222 "inputs and outputs" )
211223
212224 # Make sure timebase are compatible
213- dt = _find_timebase (sys1 , sys2 )
214- if dt is False :
215- raise ValueError ("System timebases are not compabile" )
225+ dt = common_timebase (sys1 .dt , sys2 .dt )
216226
217227 inplist = [(0 ,i ) for i in range (sys1 .ninputs )]
218228 outlist = [(1 ,i ) for i in range (sys2 .noutputs )]
@@ -464,12 +474,11 @@ def feedback(self, other=1, sign=-1, params={}):
464474 "inputs and outputs" )
465475
466476 # Make sure timebases are compatible
467- dt = _find_timebase (self , other )
468- if dt is False :
469- raise ValueError ("System timebases are not compabile" )
477+ dt = common_timebase (self .dt , other .dt )
470478
471479 inplist = [(0 ,i ) for i in range (self .ninputs )]
472480 outlist = [(0 ,i ) for i in range (self .noutputs )]
481+
473482 # Return the series interconnection between the systems
474483 newsys = InterconnectedSystem ((self , other ), inplist = inplist , outlist = outlist ,
475484 params = params , dt = dt )
@@ -580,10 +589,11 @@ def __init__(self, linsys, inputs=None, outputs=None, states=None,
580589 states : int, list of str, or None, optional
581590 Description of the system states. Same format as `inputs`.
582591 dt : None, True or float, optional
583- System timebase. None (default) indicates continuous
584- time, True indicates discrete time with undefined sampling
592+ System timebase. 0 (default) indicates continuous
593+ time, True indicates discrete time with unspecified sampling
585594 time, positive number is discrete time with specified
586- sampling time.
595+ sampling time, None indicates unspecified timebase (either
596+ continuous or discrete time).
587597 params : dict, optional
588598 Parameter values for the systems. Passed to the evaluation
589599 functions for the system as default values, overriding internal
@@ -650,7 +660,8 @@ class NonlinearIOSystem(InputOutputSystem):
650660
651661 """
652662 def __init__ (self , updfcn , outfcn = None , inputs = None , outputs = None ,
653- states = None , params = {}, dt = None , name = None ):
663+ states = None , params = {},
664+ name = None , ** kwargs ):
654665 """Create a nonlinear I/O system given update and output functions.
655666
656667 Creates an `InputOutputSystem` for a nonlinear system by specifying a
@@ -702,10 +713,10 @@ def __init__(self, updfcn, outfcn=None, inputs=None, outputs=None,
702713 operating in continuous or discrete time. It can have the
703714 following values:
704715
705- * dt = None No timebase specified
706- * dt = 0 Continuous time system
707- * dt > 0 Discrete time system with sampling time dt
708- * dt = True Discrete time with unspecified sampling time
716+ * dt = 0: continuous time system (default)
717+ * dt > 0: discrete time system with sampling period 'dt'
718+ * dt = True: discrete time with unspecified sampling period
719+ * dt = None: no timebase specified
709720
710721 name : string, optional
711722 System name (used for specifying signals). If unspecified, a generic
@@ -722,6 +733,7 @@ def __init__(self, updfcn, outfcn=None, inputs=None, outputs=None,
722733 self .outfcn = outfcn
723734
724735 # Initialize the rest of the structure
736+ dt = kwargs .get ('dt' , config .defaults ['control.default_dt' ])
725737 super (NonlinearIOSystem , self ).__init__ (
726738 inputs = inputs , outputs = outputs , states = states ,
727739 params = params , dt = dt , name = name
@@ -871,10 +883,10 @@ def __init__(self, syslist, connections=[], inplist=[], outlist=[],
871883 operating in continuous or discrete time. It can have the
872884 following values:
873885
874- * dt = None No timebase specified
875- * dt = 0 Continuous time system
876- * dt > 0 Discrete time system with sampling time dt
877- * dt = True Discrete time with unspecified sampling time
886+ * dt = 0: continuous time system (default)
887+ * dt > 0: discrete time system with sampling period 'dt'
888+ * dt = True: discrete time with unspecified sampling period
889+ * dt = None: no timebase specified
878890
879891 name : string, optional
880892 System name (used for specifying signals). If unspecified, a generic
@@ -888,20 +900,14 @@ def __init__(self, syslist, connections=[], inplist=[], outlist=[],
888900 # Check to make sure all systems are consistent
889901 self .syslist = syslist
890902 self .syslist_index = {}
891- dt = None
892903 nstates = 0 ; self .state_offset = []
893904 ninputs = 0 ; self .input_offset = []
894905 noutputs = 0 ; self .output_offset = []
895906 sysobj_name_dct = {}
896907 sysname_count_dct = {}
897908 for sysidx , sys in enumerate (syslist ):
898909 # Make sure time bases are consistent
899- # TODO: Use lti._find_timebase() instead?
900- if dt is None and sys .dt is not None :
901- # Timebase was not specified; set to match this system
902- dt = sys .dt
903- elif dt != sys .dt :
904- raise TypeError ("System timebases are not compatible" )
910+ dt = common_timebase (dt , sys .dt )
905911
906912 # Make sure number of inputs, outputs, states is given
907913 if sys .ninputs is None or sys .noutputs is None or \
0 commit comments