@@ -77,13 +77,35 @@ class FrequencyResponseData(LTI):
7777 above, i.e. the rows represent the outputs and the columns
7878 represent the inputs.
7979
80+ A frequency response data object is callable and returns the value of the
81+ transfer function evaluated at a point in the complex plane (must be on
82+ the imaginary access). See :meth:`~control.FrequencyResponseData.__call__`
83+ for a more detailed description.
84+
8085 """
8186
8287 # Allow NDarray * StateSpace to give StateSpace._rmul_() priority
8388 # https://docs.scipy.org/doc/numpy/reference/arrays.classes.html
8489 __array_priority__ = 11 # override ndarray and matrix types
8590
86- epsw = 1e-8
91+ #
92+ # Class attributes
93+ #
94+ # These attributes are defined as class attributes so that they are
95+ # documented properly. They are "overwritten" in __init__.
96+ #
97+
98+ #: Number of system inputs.
99+ #:
100+ #: :meta hide-value:
101+ ninputs = 1
102+
103+ #: Number of system outputs.
104+ #:
105+ #: :meta hide-value:
106+ noutputs = 1
107+
108+ _epsw = 1e-8 #: Bound for exact frequency match
87109
88110 def __init__ (self , * args , ** kwargs ):
89111 """Construct an FRD object.
@@ -141,7 +163,8 @@ def __init__(self, *args, **kwargs):
141163 self .omega = args [0 ].omega
142164 self .fresp = args [0 ].fresp
143165 else :
144- raise ValueError ("Needs 1 or 2 arguments; received %i." % len (args ))
166+ raise ValueError (
167+ "Needs 1 or 2 arguments; received %i." % len (args ))
145168
146169 # create interpolation functions
147170 if smooth :
@@ -378,7 +401,7 @@ def eval(self, omega, squeeze=None):
378401 then single-dimensional axes are removed.
379402
380403 """
381- omega_array = np .array (omega , ndmin = 1 ) # array-like version of omega
404+ omega_array = np .array (omega , ndmin = 1 ) # array-like version of omega
382405
383406 # Make sure that we are operating on a simple list
384407 if len (omega_array .shape ) > 1 :
@@ -389,7 +412,7 @@ def eval(self, omega, squeeze=None):
389412 raise ValueError ("FRD.eval can only accept real-valued omega" )
390413
391414 if self .ifunc is None :
392- elements = np .isin (self .omega , omega ) # binary array
415+ elements = np .isin (self .omega , omega ) # binary array
393416 if sum (elements ) < len (omega_array ):
394417 raise ValueError (
395418 "not all frequencies omega are in frequency list of FRD "
@@ -398,7 +421,7 @@ def eval(self, omega, squeeze=None):
398421 out = self .fresp [:, :, elements ]
399422 else :
400423 out = empty ((self .noutputs , self .ninputs , len (omega_array )),
401- dtype = complex )
424+ dtype = complex )
402425 for i in range (self .noutputs ):
403426 for j in range (self .ninputs ):
404427 for k , w in enumerate (omega_array ):
@@ -417,6 +440,9 @@ def __call__(self, s, squeeze=None):
417440 To evaluate at a frequency omega in radians per second, enter
418441 ``s = omega * 1j`` or use ``sys.eval(omega)``
419442
443+ For a frequency response data object, the argument must be an
444+ imaginary number (since only the frequency response is defined).
445+
420446 Parameters
421447 ----------
422448 s : complex scalar or 1D array_like
@@ -444,14 +470,15 @@ def __call__(self, s, squeeze=None):
444470 If `s` is not purely imaginary, because
445471 :class:`FrequencyDomainData` systems are only defined at imaginary
446472 frequency values.
473+
447474 """
448475 # Make sure that we are operating on a simple list
449476 if len (np .atleast_1d (s ).shape ) > 1 :
450477 raise ValueError ("input list must be 1D" )
451478
452479 if any (abs (np .atleast_1d (s ).real ) > 0 ):
453480 raise ValueError ("__call__: FRD systems can only accept "
454- "purely imaginary frequencies" )
481+ "purely imaginary frequencies" )
455482
456483 # need to preserve array or scalar status
457484 if hasattr (s , '__len__' ):
@@ -510,6 +537,7 @@ def feedback(self, other=1, sign=-1):
510537# fixes this problem.
511538#
512539
540+
513541FRD = FrequencyResponseData
514542
515543
@@ -534,7 +562,7 @@ def _convert_to_FRD(sys, omega, inputs=1, outputs=1):
534562 if isinstance (sys , FRD ):
535563 omega .sort ()
536564 if len (omega ) == len (sys .omega ) and \
537- (abs (omega - sys .omega ) < FRD .epsw ).all ():
565+ (abs (omega - sys .omega ) < FRD ._epsw ).all ():
538566 # frequencies match, and system was already frd; simply use
539567 return sys
540568
0 commit comments