6161import scipy as sp
6262from scipy .signal import lti , cont2discrete
6363from warnings import warn
64- from .lti import LTI , timebase , timebaseEqual , isdtime
64+ from .lti import LTI , common_timebase , isdtime
6565from . import config
6666from copy import deepcopy
6767
@@ -174,7 +174,10 @@ def __init__(self, *args, **kw):
174174 if len (args ) == 4 :
175175 # The user provided A, B, C, and D matrices.
176176 (A , B , C , D ) = args
177- dt = config .defaults ['statesp.default_dt' ]
177+ if _isstaticgain (A , B , C , D ):
178+ dt = None
179+ else :
180+ dt = config .defaults ['statesp.default_dt' ]
178181 elif len (args ) == 5 :
179182 # Discrete time system
180183 (A , B , C , D , dt ) = args
@@ -190,9 +193,12 @@ def __init__(self, *args, **kw):
190193 try :
191194 dt = args [0 ].dt
192195 except NameError :
193- dt = config .defaults ['statesp.default_dt' ]
196+ if _isstaticgain (A , B , C , D ):
197+ dt = None
198+ else :
199+ dt = config .defaults ['statesp.default_dt' ]
194200 else :
195- raise ValueError ("Needs 1 or 4 arguments; received %i." % len (args ))
201+ raise ValueError ("Expected 1, 4, or 5 arguments; received %i." % len (args ))
196202
197203 # Process keyword arguments
198204 remove_useless = kw .get ('remove_useless' , config .defaults ['statesp.remove_useless_states' ])
@@ -316,14 +322,7 @@ def __add__(self, other):
316322 (self .outputs != other .outputs )):
317323 raise ValueError ("Systems have different shapes." )
318324
319- # Figure out the sampling time to use
320- if self .dt is None and other .dt is not None :
321- dt = other .dt # use dt from second argument
322- elif (other .dt is None and self .dt is not None ) or \
323- (timebaseEqual (self , other )):
324- dt = self .dt # use dt from first argument
325- else :
326- raise ValueError ("Systems have different sampling times" )
325+ dt = common_timebase (self .dt , other .dt )
327326
328327 # Concatenate the various arrays
329328 A = concatenate ((
@@ -372,16 +371,8 @@ def __mul__(self, other):
372371 # Check to make sure the dimensions are OK
373372 if self .inputs != other .outputs :
374373 raise ValueError ("C = A * B: A has %i column(s) (input(s)), \
375- but B has %i row(s)\n (output(s))." % (self .inputs , other .outputs ))
376-
377- # Figure out the sampling time to use
378- if (self .dt == None and other .dt != None ):
379- dt = other .dt # use dt from second argument
380- elif (other .dt == None and self .dt != None ) or \
381- (timebaseEqual (self , other )):
382- dt = self .dt # use dt from first argument
383- else :
384- raise ValueError ("Systems have different sampling times" )
374+ but B has %i row(s)\n (output(s))." % (self .inputs , other .outputs ))
375+ dt = common_timebase (self .dt , other .dt )
385376
386377 # Concatenate the various arrays
387378 A = concatenate (
@@ -453,9 +444,8 @@ def _evalfr(self, omega):
453444 """Evaluate a SS system's transfer function at a single frequency"""
454445 # Figure out the point to evaluate the transfer function
455446 if isdtime (self , strict = True ):
456- dt = timebase (self )
457- s = exp (1.j * omega * dt )
458- if omega * dt > math .pi :
447+ s = exp (1.j * omega * self .dt )
448+ if omega * self .dt > math .pi :
459449 warn ("_evalfr: frequency evaluation above Nyquist frequency" )
460450 else :
461451 s = omega * 1.j
@@ -512,9 +502,8 @@ def freqresp(self, omega):
512502 # axis (continuous time) or unit circle (discrete time).
513503 omega .sort ()
514504 if isdtime (self , strict = True ):
515- dt = timebase (self )
516- cmplx_freqs = exp (1.j * omega * dt )
517- if max (np .abs (omega )) * dt > math .pi :
505+ cmplx_freqs = exp (1.j * omega * self .dt )
506+ if max (np .abs (omega )) * self .dt > math .pi :
518507 warn ("freqresp: frequency evaluation above Nyquist frequency" )
519508 else :
520509 cmplx_freqs = omega * 1.j
@@ -617,14 +606,7 @@ def feedback(self, other=1, sign=-1):
617606 if (self .inputs != other .outputs ) or (self .outputs != other .inputs ):
618607 raise ValueError ("State space systems don't have compatible inputs/outputs for "
619608 "feedback." )
620-
621- # Figure out the sampling time to use
622- if self .dt is None and other .dt is not None :
623- dt = other .dt # use dt from second argument
624- elif other .dt is None and self .dt is not None or timebaseEqual (self , other ):
625- dt = self .dt # use dt from first argument
626- else :
627- raise ValueError ("Systems have different sampling times" )
609+ dt = common_timebase (self .dt , other .dt )
628610
629611 A1 = self .A
630612 B1 = self .B
@@ -694,14 +676,7 @@ def lft(self, other, nu=-1, ny=-1):
694676 # dimension check
695677 # TODO
696678
697- # Figure out the sampling time to use
698- if (self .dt == None and other .dt != None ):
699- dt = other .dt # use dt from second argument
700- elif (other .dt == None and self .dt != None ) or \
701- timebaseEqual (self , other ):
702- dt = self .dt # use dt from first argument
703- else :
704- raise ValueError ("Systems have different time bases" )
679+ dt = common_timebase (self .dt , other .dt )
705680
706681 # submatrices
707682 A = self .A
@@ -815,8 +790,7 @@ def append(self, other):
815790 if not isinstance (other , StateSpace ):
816791 other = _convertToStateSpace (other )
817792
818- if self .dt != other .dt :
819- raise ValueError ("Systems must have the same time step" )
793+ self .dt = common_timebase (self .dt , other .dt )
820794
821795 n = self .states + other .states
822796 m = self .inputs + other .inputs
@@ -1246,6 +1220,11 @@ def _mimo2simo(sys, input, warn_conversion=False):
12461220
12471221 return sys
12481222
1223+ def _isstaticgain (A , B , C , D ):
1224+ """returns True if and only if the system has no dynamics, that is,
1225+ if A and B are zero. """
1226+ return not np .any (np .matrix (A , dtype = float )) \
1227+ and not np .any (np .matrix (B , dtype = float ))
12491228
12501229def ss (* args ):
12511230 """ss(A, B, C, D[, dt])
0 commit comments