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
34
2
#
35
3
# Author: M.M. (Rene) van Paassen (using xferfcn.py as basis)
36
4
# Date: 02 Oct 12
37
5
38
-
39
6
"""
40
7
Frequency response data representation and functions.
41
8
42
9
This module contains the FRD class and also functions that operate on
43
10
FRD data.
44
11
"""
45
12
46
- # External function declarations
47
13
from copy import copy
48
14
from warnings import warn
49
15
50
16
import 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
54
20
55
- from .lti import LTI , _process_frequency_response
21
+ from . import config
56
22
from .exception import pandas_check
57
23
from .iosys import InputOutputSystem , _process_iosys_keywords , common_timebase
58
- from . import config
24
+ from .lti import LTI , _process_frequency_response
59
25
60
26
__all__ = ['FrequencyResponseData' , 'FRD' , 'frd' ]
61
27
@@ -100,6 +66,10 @@ class constructor, using the :func:~~control.frd` factory function
100
66
dt : float, True, or None
101
67
System timebase.
102
68
69
+ See Also
70
+ --------
71
+ frd
72
+
103
73
Notes
104
74
-----
105
75
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
120
90
for a more detailed description.
121
91
122
92
"""
123
-
124
93
#
125
94
# Class attributes
126
95
#
@@ -206,11 +175,12 @@ def __init__(self, *args, **kwargs):
206
175
"Needs 1 or 2 arguments; received %i." % len (args ))
207
176
208
177
#
209
- # Process key word arguments
178
+ # Process keyword arguments
210
179
#
211
180
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 ))
214
184
215
185
# Keep track of default properties for plotting
216
186
self .plot_phase = kwargs .pop ('plot_phase' , None )
@@ -280,7 +250,7 @@ def __str__(self):
280
250
"""String representation of the transfer function."""
281
251
282
252
mimo = self .ninputs > 1 or self .noutputs > 1
283
- outstr = ['Frequency response data' ]
253
+ outstr = [f" { InputOutputSystem . __str__ ( self ) } " ]
284
254
285
255
for i in range (self .ninputs ):
286
256
for j in range (self .noutputs ):
@@ -322,7 +292,7 @@ def __add__(self, other):
322
292
323
293
# Convert the second argument to a frequency response function.
324
294
# 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 )
326
296
327
297
# Check that the input-output sizes are consistent.
328
298
if self .ninputs != other .ninputs :
@@ -359,7 +329,7 @@ def __mul__(self, other):
359
329
return FRD (self .fresp * other , self .omega ,
360
330
smooth = (self .ifunc is not None ))
361
331
else :
362
- other = _convert_to_FRD (other , omega = self .omega )
332
+ other = _convert_to_frd (other , omega = self .omega )
363
333
364
334
# Check that the input-output sizes are consistent.
365
335
if self .ninputs != other .noutputs :
@@ -386,7 +356,7 @@ def __rmul__(self, other):
386
356
return FRD (self .fresp * other , self .omega ,
387
357
smooth = (self .ifunc is not None ))
388
358
else :
389
- other = _convert_to_FRD (other , omega = self .omega )
359
+ other = _convert_to_frd (other , omega = self .omega )
390
360
391
361
# Check that the input-output sizes are consistent.
392
362
if self .noutputs != other .ninputs :
@@ -414,7 +384,7 @@ def __truediv__(self, other):
414
384
return FRD (self .fresp * (1 / other ), self .omega ,
415
385
smooth = (self .ifunc is not None ))
416
386
else :
417
- other = _convert_to_FRD (other , omega = self .omega )
387
+ other = _convert_to_frd (other , omega = self .omega )
418
388
419
389
if (self .ninputs > 1 or self .noutputs > 1 or
420
390
other .ninputs > 1 or other .noutputs > 1 ):
@@ -433,7 +403,7 @@ def __rtruediv__(self, other):
433
403
return FRD (other / self .fresp , self .omega ,
434
404
smooth = (self .ifunc is not None ))
435
405
else :
436
- other = _convert_to_FRD (other , omega = self .omega )
406
+ other = _convert_to_frd (other , omega = self .omega )
437
407
438
408
if (self .ninputs > 1 or self .noutputs > 1 or
439
409
other .ninputs > 1 or other .noutputs > 1 ):
@@ -572,8 +542,8 @@ def __call__(self, s=None, squeeze=None, return_magphase=None):
572
542
------
573
543
ValueError
574
544
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) .
577
547
578
548
"""
579
549
if s is None :
@@ -638,7 +608,7 @@ def freqresp(self, omega):
638
608
def feedback (self , other = 1 , sign = - 1 ):
639
609
"""Feedback interconnection between two FRD objects."""
640
610
641
- other = _convert_to_FRD (other , omega = self .omega )
611
+ other = _convert_to_frd (other , omega = self .omega )
642
612
643
613
if (self .noutputs != other .ninputs or self .ninputs != other .noutputs ):
644
614
raise ValueError (
@@ -710,7 +680,7 @@ def to_pandas(self):
710
680
FRD = FrequencyResponseData
711
681
712
682
713
- def _convert_to_FRD (sys , omega , inputs = 1 , outputs = 1 ):
683
+ def _convert_to_frd (sys , omega , inputs = 1 , outputs = 1 ):
714
684
"""Convert a system to frequency response data form (if needed).
715
685
716
686
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):
721
691
manually, as in:
722
692
723
693
>>> import numpy as np
724
- >>> from control.frdata import _convert_to_FRD
694
+ >>> from control.frdata import _convert_to_frd
725
695
726
696
>>> 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
728
698
>>> frd.ninputs, frd.noutputs
729
699
(1, 1)
730
700
731
- >>> frd = _convert_to_FRD (1., omega, inputs=3, outputs=2)
701
+ >>> frd = _convert_to_frd (1., omega, inputs=3, outputs=2)
732
702
>>> frd.ninputs, frd.noutputs
733
703
(3, 2)
734
704
@@ -777,51 +747,67 @@ def _convert_to_FRD(sys, omega, inputs=1, outputs=1):
777
747
sys .__class__ )
778
748
779
749
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])
784
752
785
- frd models store the (measured) frequency response of a system .
753
+ Construct a frequency response data (FRD) model .
786
754
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:
788
757
789
- ``frd(response, freqs )``
758
+ ``frd(response, omega )``
790
759
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].
792
761
793
- ``frd(sys, freqs )``
762
+ ``frd(sys, omega )``
794
763
Convert an LTI system into an frd model with data at frequencies
795
- freqs .
764
+ ``omega`` .
796
765
797
766
Parameters
798
767
----------
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``.
805
781
806
782
Returns
807
783
-------
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.
810
796
811
797
See Also
812
798
--------
813
- FRD , ss, tf
799
+ FrequencyResponseData, frequency_response , ss, tf
814
800
815
801
Examples
816
802
--------
817
803
>>> # Create from measurements
818
804
>>> 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 )
821
807
822
808
>>> 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 )
825
811
826
812
"""
827
- return FRD (* args )
813
+ return FrequencyResponseData (* args , ** kwargs )
0 commit comments