1- # Copyright (c) 2010 by California Institute of Technology
2- # Copyright (c) 2012 by Delft University of Technology
3- # All rights reserved.
4- #
5- # Redistribution and use in source and binary forms, with or without
6- # modification, are permitted provided that the following conditions
7- # are met:
8- #
9- # 1. Redistributions of source code must retain the above copyright
10- # notice, this list of conditions and the following disclaimer.
11- #
12- # 2. Redistributions in binary form must reproduce the above copyright
13- # notice, this list of conditions and the following disclaimer in the
14- # documentation and/or other materials provided with the distribution.
15- #
16- # 3. Neither the names of the California Institute of Technology nor
17- # the Delft University of Technology nor
18- # the names of its contributors may be used to endorse or promote
19- # products derived from this software without specific prior
20- # written permission.
21- #
22- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25- # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALTECH
26- # OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29- # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30- # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32- # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33- # SUCH DAMAGE.
1+ # frdata.py - frequency response data representation and functions
342#
353# Author: M.M. (Rene) van Paassen (using xferfcn.py as basis)
364# Date: 02 Oct 12
375
38-
396"""
407Frequency response data representation and functions.
418
429This module contains the FRD class and also functions that operate on
4310FRD data.
4411"""
4512
46- # External function declarations
4713from copy import copy
4814from warnings import warn
4915
5016import numpy as np
51- from numpy import angle , array , empty , ones , \
52- real , imag , absolute , eye , linalg , where , sort
53- from scipy .interpolate import splprep , splev
17+ from numpy import absolute , angle , array , empty , eye , imag , linalg , ones , \
18+ real , sort , where
19+ from scipy .interpolate import splev , splprep
5420
55- from .lti import LTI , _process_frequency_response
21+ from . import config
5622from .exception import pandas_check
5723from .iosys import InputOutputSystem , _process_iosys_keywords , common_timebase
58- from . import config
24+ from .lti import LTI , _process_frequency_response
5925
6026__all__ = ['FrequencyResponseData' , 'FRD' , 'frd' ]
6127
@@ -100,6 +66,10 @@ class constructor, using the :func:~~control.frd` factory function
10066 dt : float, True, or None
10167 System timebase.
10268
69+ See Also
70+ --------
71+ frd
72+
10373 Notes
10474 -----
10575 The main data members are 'omega' and 'fresp', where 'omega' is a 1D array
@@ -120,7 +90,6 @@ class constructor, using the :func:~~control.frd` factory function
12090 for a more detailed description.
12191
12292 """
123-
12493 #
12594 # Class attributes
12695 #
@@ -206,11 +175,12 @@ def __init__(self, *args, **kwargs):
206175 "Needs 1 or 2 arguments; received %i." % len (args ))
207176
208177 #
209- # Process key word arguments
178+ # Process keyword arguments
210179 #
211180
212- # If data was generated by a system, keep track of that
213- self .sysname = kwargs .pop ('sysname' , None )
181+ # If data was generated by a system, keep track of that (used when
182+ # plotting data). Otherwise, use the system name, if given.
183+ self .sysname = kwargs .pop ('sysname' , kwargs .get ('name' , None ))
214184
215185 # Keep track of default properties for plotting
216186 self .plot_phase = kwargs .pop ('plot_phase' , None )
@@ -280,7 +250,7 @@ def __str__(self):
280250 """String representation of the transfer function."""
281251
282252 mimo = self .ninputs > 1 or self .noutputs > 1
283- outstr = ['Frequency response data' ]
253+ outstr = [f" { InputOutputSystem . __str__ ( self ) } " ]
284254
285255 for i in range (self .ninputs ):
286256 for j in range (self .noutputs ):
@@ -322,7 +292,7 @@ def __add__(self, other):
322292
323293 # Convert the second argument to a frequency response function.
324294 # or re-base the frd to the current omega (if needed)
325- other = _convert_to_FRD (other , omega = self .omega )
295+ other = _convert_to_frd (other , omega = self .omega )
326296
327297 # Check that the input-output sizes are consistent.
328298 if self .ninputs != other .ninputs :
@@ -359,7 +329,7 @@ def __mul__(self, other):
359329 return FRD (self .fresp * other , self .omega ,
360330 smooth = (self .ifunc is not None ))
361331 else :
362- other = _convert_to_FRD (other , omega = self .omega )
332+ other = _convert_to_frd (other , omega = self .omega )
363333
364334 # Check that the input-output sizes are consistent.
365335 if self .ninputs != other .noutputs :
@@ -386,7 +356,7 @@ def __rmul__(self, other):
386356 return FRD (self .fresp * other , self .omega ,
387357 smooth = (self .ifunc is not None ))
388358 else :
389- other = _convert_to_FRD (other , omega = self .omega )
359+ other = _convert_to_frd (other , omega = self .omega )
390360
391361 # Check that the input-output sizes are consistent.
392362 if self .noutputs != other .ninputs :
@@ -414,7 +384,7 @@ def __truediv__(self, other):
414384 return FRD (self .fresp * (1 / other ), self .omega ,
415385 smooth = (self .ifunc is not None ))
416386 else :
417- other = _convert_to_FRD (other , omega = self .omega )
387+ other = _convert_to_frd (other , omega = self .omega )
418388
419389 if (self .ninputs > 1 or self .noutputs > 1 or
420390 other .ninputs > 1 or other .noutputs > 1 ):
@@ -433,7 +403,7 @@ def __rtruediv__(self, other):
433403 return FRD (other / self .fresp , self .omega ,
434404 smooth = (self .ifunc is not None ))
435405 else :
436- other = _convert_to_FRD (other , omega = self .omega )
406+ other = _convert_to_frd (other , omega = self .omega )
437407
438408 if (self .ninputs > 1 or self .noutputs > 1 or
439409 other .ninputs > 1 or other .noutputs > 1 ):
@@ -572,8 +542,8 @@ def __call__(self, s=None, squeeze=None, return_magphase=None):
572542 ------
573543 ValueError
574544 If `s` is not purely imaginary, because
575- :class:`FrequencyDomainData ` systems are only defined at imaginary
576- frequency values.
545+ :class:`FrequencyResponseData ` systems are only defined at
546+ imaginary values (corresponding to real frequencies) .
577547
578548 """
579549 if s is None :
@@ -638,7 +608,7 @@ def freqresp(self, omega):
638608 def feedback (self , other = 1 , sign = - 1 ):
639609 """Feedback interconnection between two FRD objects."""
640610
641- other = _convert_to_FRD (other , omega = self .omega )
611+ other = _convert_to_frd (other , omega = self .omega )
642612
643613 if (self .noutputs != other .ninputs or self .ninputs != other .noutputs ):
644614 raise ValueError (
@@ -710,7 +680,7 @@ def to_pandas(self):
710680FRD = FrequencyResponseData
711681
712682
713- def _convert_to_FRD (sys , omega , inputs = 1 , outputs = 1 ):
683+ def _convert_to_frd (sys , omega , inputs = 1 , outputs = 1 ):
714684 """Convert a system to frequency response data form (if needed).
715685
716686 If sys is already an frd, and its frequency range matches or
@@ -721,14 +691,14 @@ def _convert_to_FRD(sys, omega, inputs=1, outputs=1):
721691 manually, as in:
722692
723693 >>> import numpy as np
724- >>> from control.frdata import _convert_to_FRD
694+ >>> from control.frdata import _convert_to_frd
725695
726696 >>> omega = np.logspace(-1, 1)
727- >>> frd = _convert_to_FRD (3., omega) # Assumes inputs = outputs = 1
697+ >>> frd = _convert_to_frd (3., omega) # Assumes inputs = outputs = 1
728698 >>> frd.ninputs, frd.noutputs
729699 (1, 1)
730700
731- >>> frd = _convert_to_FRD (1., omega, inputs=3, outputs=2)
701+ >>> frd = _convert_to_frd (1., omega, inputs=3, outputs=2)
732702 >>> frd.ninputs, frd.noutputs
733703 (3, 2)
734704
@@ -777,51 +747,67 @@ def _convert_to_FRD(sys, omega, inputs=1, outputs=1):
777747 sys .__class__ )
778748
779749
780- def frd (* args ):
781- """frd(d, w)
782-
783- Construct a frequency response data model.
750+ def frd (* args , ** kwargs ):
751+ """frd(response, omega[, dt])
784752
785- frd models store the (measured) frequency response of a system .
753+ Construct a frequency response data (FRD) model .
786754
787- This function can be called in different ways:
755+ A frequency response data model stores the (measured) frequency response
756+ of a system. This factory function can be called in different ways:
788757
789- ``frd(response, freqs )``
758+ ``frd(response, omega )``
790759 Create an frd model with the given response data, in the form of
791- complex response vector, at matching frequency freqs [in rad/s]
760+ complex response vector, at matching frequencies ``omega`` [in rad/s].
792761
793- ``frd(sys, freqs )``
762+ ``frd(sys, omega )``
794763 Convert an LTI system into an frd model with data at frequencies
795- freqs .
764+ ``omega`` .
796765
797766 Parameters
798767 ----------
799- response: array_like, or list
800- complex vector with the system response
801- freq: array_lik or lis
802- vector with frequencies
803- sys: LTI (StateSpace or TransferFunction)
804- A linear system
768+ response : array_like or LTI system
769+ Complex vector with the system response or an LTI system that can
770+ be used to copmute the frequency response at a list of frequencies.
771+ omega : array_like
772+ Vector of frequencies at which the response is evaluated.
773+ dt : float, True, or None
774+ System timebase.
775+ smooth : bool, optional
776+ If ``True``, create an interpolation function that allows the
777+ frequency response to be computed at any frequency within the range
778+ of frequencies give in ``omega``. If ``False`` (default),
779+ frequency response can only be obtained at the frequencies
780+ specified in ``omega``.
805781
806782 Returns
807783 -------
808- sys: FRD
809- New frequency response system
784+ sys : :class:`FrequencyResponseData`
785+ New frequency response data system.
786+
787+ Other Parameters
788+ ----------------
789+ inputs, outputs : str, or list of str, optional
790+ List of strings that name the individual signals of the transformed
791+ system. If not given, the inputs and outputs are the same as the
792+ original system.
793+ name : string, optional
794+ System name. If unspecified, a generic name <sys[id]> is generated
795+ with a unique integer id.
810796
811797 See Also
812798 --------
813- FRD , ss, tf
799+ FrequencyResponseData, frequency_response , ss, tf
814800
815801 Examples
816802 --------
817803 >>> # Create from measurements
818804 >>> response = [1.0, 1.0, 0.5]
819- >>> freqs = [1, 10, 100]
820- >>> F = ct.frd(response, freqs )
805+ >>> omega = [1, 10, 100]
806+ >>> F = ct.frd(response, omega )
821807
822808 >>> G = ct.tf([1], [1, 1])
823- >>> freqs = [1, 10, 100]
824- >>> F = ct.frd(G, freqs )
809+ >>> omega = [1, 10, 100]
810+ >>> F = ct.frd(G, omega )
825811
826812 """
827- return FRD (* args )
813+ return FrequencyResponseData (* args , ** kwargs )
0 commit comments