61
61
import scipy as sp
62
62
from scipy .signal import lti , cont2discrete
63
63
from warnings import warn
64
- from .lti import LTI , timebase , timebaseEqual , isdtime
64
+ from .lti import LTI , common_timebase , isdtime
65
65
from . import config
66
66
from copy import deepcopy
67
67
@@ -174,7 +174,10 @@ def __init__(self, *args, **kw):
174
174
if len (args ) == 4 :
175
175
# The user provided A, B, C, and D matrices.
176
176
(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' ]
178
181
elif len (args ) == 5 :
179
182
# Discrete time system
180
183
(A , B , C , D , dt ) = args
@@ -190,9 +193,12 @@ def __init__(self, *args, **kw):
190
193
try :
191
194
dt = args [0 ].dt
192
195
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' ]
194
200
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 ))
196
202
197
203
# Process keyword arguments
198
204
remove_useless = kw .get ('remove_useless' , config .defaults ['statesp.remove_useless_states' ])
@@ -316,14 +322,7 @@ def __add__(self, other):
316
322
(self .outputs != other .outputs )):
317
323
raise ValueError ("Systems have different shapes." )
318
324
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 )
327
326
328
327
# Concatenate the various arrays
329
328
A = concatenate ((
@@ -372,16 +371,8 @@ def __mul__(self, other):
372
371
# Check to make sure the dimensions are OK
373
372
if self .inputs != other .outputs :
374
373
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 )
385
376
386
377
# Concatenate the various arrays
387
378
A = concatenate (
@@ -453,9 +444,8 @@ def _evalfr(self, omega):
453
444
"""Evaluate a SS system's transfer function at a single frequency"""
454
445
# Figure out the point to evaluate the transfer function
455
446
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 :
459
449
warn ("_evalfr: frequency evaluation above Nyquist frequency" )
460
450
else :
461
451
s = omega * 1.j
@@ -512,9 +502,8 @@ def freqresp(self, omega):
512
502
# axis (continuous time) or unit circle (discrete time).
513
503
omega .sort ()
514
504
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 :
518
507
warn ("freqresp: frequency evaluation above Nyquist frequency" )
519
508
else :
520
509
cmplx_freqs = omega * 1.j
@@ -617,14 +606,7 @@ def feedback(self, other=1, sign=-1):
617
606
if (self .inputs != other .outputs ) or (self .outputs != other .inputs ):
618
607
raise ValueError ("State space systems don't have compatible inputs/outputs for "
619
608
"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 )
628
610
629
611
A1 = self .A
630
612
B1 = self .B
@@ -694,14 +676,7 @@ def lft(self, other, nu=-1, ny=-1):
694
676
# dimension check
695
677
# TODO
696
678
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 )
705
680
706
681
# submatrices
707
682
A = self .A
@@ -815,8 +790,7 @@ def append(self, other):
815
790
if not isinstance (other , StateSpace ):
816
791
other = _convertToStateSpace (other )
817
792
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 )
820
794
821
795
n = self .states + other .states
822
796
m = self .inputs + other .inputs
@@ -1246,6 +1220,11 @@ def _mimo2simo(sys, input, warn_conversion=False):
1246
1220
1247
1221
return sys
1248
1222
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 ))
1249
1228
1250
1229
def ss (* args ):
1251
1230
"""ss(A, B, C, D[, dt])
0 commit comments