@@ -668,7 +668,7 @@ def __rdiv__(self, other):
668
668
raise NotImplementedError (
669
669
"StateSpace.__rdiv__ is not implemented yet." )
670
670
671
- def __call__ (self , x , squeeze = None ):
671
+ def __call__ (self , x , squeeze = None , warn_infinite = True ):
672
672
"""Evaluate system's transfer function at complex frequency.
673
673
674
674
Returns the complex frequency response `sys(x)` where `x` is `s` for
@@ -689,6 +689,8 @@ def __call__(self, x, squeeze=None):
689
689
keep all indices (output, input and, if omega is array_like,
690
690
frequency) even if the system is SISO. The default value can be
691
691
set using config.defaults['control.squeeze_frequency_response'].
692
+ warn_infinite : bool, optional
693
+ If set to `False`, don't warn if frequency response is infinite.
692
694
693
695
Returns
694
696
-------
@@ -702,7 +704,7 @@ def __call__(self, x, squeeze=None):
702
704
703
705
"""
704
706
# Use Slycot if available
705
- out = self .horner (x )
707
+ out = self .horner (x , warn_infinite = warn_infinite )
706
708
return _process_frequency_response (self , x , out , squeeze = squeeze )
707
709
708
710
def slycot_laub (self , x ):
@@ -758,7 +760,7 @@ def slycot_laub(self, x):
758
760
out [:, :, kk + 1 ] = result [0 ] + self .D
759
761
return out
760
762
761
- def horner (self , x ):
763
+ def horner (self , x , warn_infinite = True ):
762
764
"""Evaluate system's transfer function at complex frequency
763
765
using Laub's or Horner's method.
764
766
@@ -795,14 +797,22 @@ def horner(self, x):
795
797
raise ValueError ("input list must be 1D" )
796
798
797
799
# Preallocate
798
- out = empty ((self .noutputs , self .ninputs , len (x_arr )), dtype = complex )
800
+ out = empty ((self .noutputs , self .ninputs , len (x_arr )),
801
+ dtype = complex )
799
802
800
803
#TODO: can this be vectorized?
801
804
for idx , x_idx in enumerate (x_arr ):
802
- out [:,:,idx ] = \
803
- np .dot (self .C ,
805
+ try :
806
+ out [:,:,idx ] = np .dot (
807
+ self .C ,
804
808
solve (x_idx * eye (self .nstates ) - self .A , self .B )) \
805
- + self .D
809
+ + self .D
810
+ except LinAlgError :
811
+ if warn_infinite :
812
+ warn ("frequency response is not finite" ,
813
+ RuntimeWarning )
814
+ # TODO: check for nan cases
815
+ out [:,:,idx ] = np .inf
806
816
return out
807
817
808
818
def freqresp (self , omega ):
@@ -1200,7 +1210,7 @@ def dcgain(self):
1200
1210
gain : ndarray
1201
1211
An array of shape (outputs,inputs); the array will either
1202
1212
be the zero-frequency (or DC) gain, or, if the frequency
1203
- response is singular, the array will be filled with np.nan .
1213
+ response is singular, the array will be filled with np.inf .
1204
1214
"""
1205
1215
try :
1206
1216
if self .isctime ():
@@ -1210,7 +1220,7 @@ def dcgain(self):
1210
1220
gain = np .squeeze (self .horner (1 ))
1211
1221
except LinAlgError :
1212
1222
# eigenvalue at DC
1213
- gain = np .tile (np .nan , (self .noutputs , self .ninputs ))
1223
+ gain = np .tile (np .inf , (self .noutputs , self .ninputs ))
1214
1224
return np .squeeze (gain )
1215
1225
1216
1226
def _isstatic (self ):
0 commit comments