6262from scipy .signal import cont2discrete
6363from scipy .signal import StateSpace as signalStateSpace
6464from warnings import warn
65- from .lti import LTI , timebase , timebaseEqual , isdtime
65+ from .lti import LTI , common_timebase , isdtime
6666from . import config
6767from copy import deepcopy
6868
@@ -180,7 +180,10 @@ def __init__(self, *args, **kw):
180180 if len (args ) == 4 :
181181 # The user provided A, B, C, and D matrices.
182182 (A , B , C , D ) = args
183- dt = config .defaults ['statesp.default_dt' ]
183+ if _isstaticgain (A , B , C , D ):
184+ dt = None
185+ else :
186+ dt = config .defaults ['statesp.default_dt' ]
184187 elif len (args ) == 5 :
185188 # Discrete time system
186189 (A , B , C , D , dt ) = args
@@ -196,9 +199,12 @@ def __init__(self, *args, **kw):
196199 try :
197200 dt = args [0 ].dt
198201 except NameError :
199- dt = config .defaults ['statesp.default_dt' ]
202+ if _isstaticgain (A , B , C , D ):
203+ dt = None
204+ else :
205+ dt = config .defaults ['statesp.default_dt' ]
200206 else :
201- raise ValueError ("Needs 1 or 4 arguments; received %i." % len (args ))
207+ raise ValueError ("Expected 1, 4, or 5 arguments; received %i." % len (args ))
202208
203209 # Process keyword arguments
204210 remove_useless = kw .get ('remove_useless' ,
@@ -330,14 +336,7 @@ def __add__(self, other):
330336 (self .outputs != other .outputs )):
331337 raise ValueError ("Systems have different shapes." )
332338
333- # Figure out the sampling time to use
334- if self .dt is None and other .dt is not None :
335- dt = other .dt # use dt from second argument
336- elif (other .dt is None and self .dt is not None ) or \
337- (timebaseEqual (self , other )):
338- dt = self .dt # use dt from first argument
339- else :
340- raise ValueError ("Systems have different sampling times" )
339+ dt = common_timebase (self .dt , other .dt )
341340
342341 # Concatenate the various arrays
343342 A = concatenate ((
@@ -386,16 +385,8 @@ def __mul__(self, other):
386385 # Check to make sure the dimensions are OK
387386 if self .inputs != other .outputs :
388387 raise ValueError ("C = A * B: A has %i column(s) (input(s)), \
389- but B has %i row(s)\n (output(s))." % (self .inputs , other .outputs ))
390-
391- # Figure out the sampling time to use
392- if (self .dt == None and other .dt != None ):
393- dt = other .dt # use dt from second argument
394- elif (other .dt == None and self .dt != None ) or \
395- (timebaseEqual (self , other )):
396- dt = self .dt # use dt from first argument
397- else :
398- raise ValueError ("Systems have different sampling times" )
388+ but B has %i row(s)\n (output(s))." % (self .inputs , other .outputs ))
389+ dt = common_timebase (self .dt , other .dt )
399390
400391 # Concatenate the various arrays
401392 A = concatenate (
@@ -467,9 +458,8 @@ def _evalfr(self, omega):
467458 """Evaluate a SS system's transfer function at a single frequency"""
468459 # Figure out the point to evaluate the transfer function
469460 if isdtime (self , strict = True ):
470- dt = timebase (self )
471- s = exp (1.j * omega * dt )
472- if omega * dt > math .pi :
461+ s = exp (1.j * omega * self .dt )
462+ if omega * self .dt > math .pi :
473463 warn ("_evalfr: frequency evaluation above Nyquist frequency" )
474464 else :
475465 s = omega * 1.j
@@ -526,9 +516,8 @@ def freqresp(self, omega):
526516 # axis (continuous time) or unit circle (discrete time).
527517 omega .sort ()
528518 if isdtime (self , strict = True ):
529- dt = timebase (self )
530- cmplx_freqs = exp (1.j * omega * dt )
531- if max (np .abs (omega )) * dt > math .pi :
519+ cmplx_freqs = exp (1.j * omega * self .dt )
520+ if max (np .abs (omega )) * self .dt > math .pi :
532521 warn ("freqresp: frequency evaluation above Nyquist frequency" )
533522 else :
534523 cmplx_freqs = omega * 1.j
@@ -631,14 +620,7 @@ def feedback(self, other=1, sign=-1):
631620 if (self .inputs != other .outputs ) or (self .outputs != other .inputs ):
632621 raise ValueError ("State space systems don't have compatible inputs/outputs for "
633622 "feedback." )
634-
635- # Figure out the sampling time to use
636- if self .dt is None and other .dt is not None :
637- dt = other .dt # use dt from second argument
638- elif other .dt is None and self .dt is not None or timebaseEqual (self , other ):
639- dt = self .dt # use dt from first argument
640- else :
641- raise ValueError ("Systems have different sampling times" )
623+ dt = common_timebase (self .dt , other .dt )
642624
643625 A1 = self .A
644626 B1 = self .B
@@ -708,14 +690,7 @@ def lft(self, other, nu=-1, ny=-1):
708690 # dimension check
709691 # TODO
710692
711- # Figure out the sampling time to use
712- if (self .dt == None and other .dt != None ):
713- dt = other .dt # use dt from second argument
714- elif (other .dt == None and self .dt != None ) or \
715- timebaseEqual (self , other ):
716- dt = self .dt # use dt from first argument
717- else :
718- raise ValueError ("Systems have different time bases" )
693+ dt = common_timebase (self .dt , other .dt )
719694
720695 # submatrices
721696 A = self .A
@@ -858,8 +833,7 @@ def append(self, other):
858833 if not isinstance (other , StateSpace ):
859834 other = _convertToStateSpace (other )
860835
861- if self .dt != other .dt :
862- raise ValueError ("Systems must have the same time step" )
836+ self .dt = common_timebase (self .dt , other .dt )
863837
864838 n = self .states + other .states
865839 m = self .inputs + other .inputs
@@ -1293,6 +1267,11 @@ def _mimo2simo(sys, input, warn_conversion=False):
12931267
12941268 return sys
12951269
1270+ def _isstaticgain (A , B , C , D ):
1271+ """returns True if and only if the system has no dynamics, that is,
1272+ if A and B are zero. """
1273+ return not np .any (np .matrix (A , dtype = float )) \
1274+ and not np .any (np .matrix (B , dtype = float ))
12961275
12971276def ss (* args ):
12981277 """ss(A, B, C, D[, dt])
0 commit comments