Skip to content

Commit c65263f

Browse files
authored
update FRD class name to fix MacOS sphinx build problems (#326)
1 parent 4d718af commit c65263f

3 files changed

Lines changed: 107 additions & 94 deletions

File tree

control/frdata.py

Lines changed: 104 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,49 @@
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.
34+
#
35+
# Author: M.M. (Rene) van Paassen (using xferfcn.py as basis)
36+
# Date: 02 Oct 12
37+
138
from __future__ import division
39+
240
"""
341
Frequency response data representation and functions.
442
543
This module contains the FRD class and also functions that operate on
644
FRD data.
745
"""
846

9-
"""Copyright (c) 2010 by California Institute of Technology
10-
Copyright (c) 2012 by Delft University of Technology
11-
All rights reserved.
12-
13-
Redistribution and use in source and binary forms, with or without
14-
modification, are permitted provided that the following conditions
15-
are met:
16-
17-
1. Redistributions of source code must retain the above copyright
18-
notice, this list of conditions and the following disclaimer.
19-
20-
2. Redistributions in binary form must reproduce the above copyright
21-
notice, this list of conditions and the following disclaimer in the
22-
documentation and/or other materials provided with the distribution.
23-
24-
3. Neither the names of the California Institute of Technology nor
25-
the Delft University of Technology nor
26-
the names of its contributors may be used to endorse or promote
27-
products derived from this software without specific prior
28-
written permission.
29-
30-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31-
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32-
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33-
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALTECH
34-
OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35-
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36-
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
37-
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38-
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
39-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
40-
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41-
SUCH DAMAGE.
42-
43-
Author: M.M. (Rene) van Paassen (using xferfcn.py as basis)
44-
Date: 02 Oct 12
45-
Revised:
46-
47-
$Id: frd.py 185 2012-08-30 05:44:32Z murrayrm $
48-
49-
"""
50-
5147
# External function declarations
5248
from warnings import warn
5349
import numpy as np
@@ -56,21 +52,22 @@
5652
from scipy.interpolate import splprep, splev
5753
from .lti import LTI
5854

59-
__all__ = ['FRD', 'frd']
55+
__all__ = ['FrequencyResponseData', 'FRD', 'frd']
56+
6057

61-
class FRD(LTI):
62-
"""FRD(d, w)
58+
class FrequencyResponseData(LTI):
59+
"""FrequencyResponseData(d, w)
6360
6461
A class for models defined by frequency response data (FRD)
6562
66-
The FRD class is used to represent systems in frequency response data form.
63+
The FrequencyResponseData (FRD) class is used to represent systems in
64+
frequency response data form.
6765
68-
The main data members are 'omega' and 'fresp', where `omega` is a 1D
69-
array with the frequency points of the response, and `fresp` is a 3D array,
70-
with the first dimension corresponding to the output index of the FRD,
71-
the second dimension corresponding to the input index, and the 3rd dimension
72-
corresponding to the frequency points in omega.
73-
For example,
66+
The main data members are 'omega' and 'fresp', where `omega` is a 1D array
67+
with the frequency points of the response, and `fresp` is a 3D array, with
68+
the first dimension corresponding to the output index of the FRD, the
69+
second dimension corresponding to the input index, and the 3rd dimension
70+
corresponding to the frequency points in omega. For example,
7471
7572
>>> frdata[2,5,:] = numpy.array([1., 0.8-0.2j, 0.2-0.8j])
7673
@@ -88,9 +85,7 @@ class FRD(LTI):
8885
epsw = 1e-8
8986

9087
def __init__(self, *args, **kwargs):
91-
"""FRD(d, w)
92-
93-
Construct an FRD object
88+
"""Construct an FRD object.
9489
9590
The default constructor is FRD(d, w), where w is an iterable of
9691
frequency points, and d is the matching frequency data.
@@ -154,10 +149,10 @@ def __init__(self, *args, **kwargs):
154149
dtype=tuple)
155150
for i in range(self.fresp.shape[0]):
156151
for j in range(self.fresp.shape[1]):
157-
self.ifunc[i,j],u = splprep(
152+
self.ifunc[i, j], u = splprep(
158153
u=self.omega, x=[real(self.fresp[i, j, :]),
159154
imag(self.fresp[i, j, :])],
160-
w=1.0/(absolute(self.fresp[i, j, :])+0.001), s=0.0)
155+
w=1.0/(absolute(self.fresp[i, j, :]) + 0.001), s=0.0)
161156
else:
162157
self.ifunc = None
163158
LTI.__init__(self, self.fresp.shape[1], self.fresp.shape[0])
@@ -166,7 +161,7 @@ def __str__(self):
166161
"""String representation of the transfer function."""
167162

168163
mimo = self.inputs > 1 or self.outputs > 1
169-
outstr = [ 'frequency response data ' ]
164+
outstr = ['frequency response data ']
170165

171166
mt, pt, wt = self.freqresp(self.omega)
172167
for i in range(self.inputs):
@@ -176,9 +171,9 @@ def __str__(self):
176171
outstr.append('Freq [rad/s] Response ')
177172
outstr.append('------------ ---------------------')
178173
outstr.extend(
179-
[ '%12.3f %10.4g%+10.4gj' % (w, m, p)
180-
for m, p, w in zip(real(self.fresp[j,i,:]), imag(self.fresp[j,i,:]), wt) ])
181-
174+
['%12.3f %10.4g%+10.4gj' % (w, m, p)
175+
for m, p, w in zip(real(self.fresp[j, i, :]),
176+
imag(self.fresp[j, i, :]), wt)])
182177

183178
return '\n'.join(outstr)
184179

@@ -194,8 +189,8 @@ def __add__(self, other):
194189
# verify that the frequencies match
195190
if len(other.omega) != len(self.omega) or \
196191
(other.omega != self.omega).any():
197-
warn("Frequency points do not match; expect"
198-
" truncation and interpolation.")
192+
warn("Frequency points do not match; expect "
193+
"truncation and interpolation.")
199194

200195
# Convert the second argument to a frequency response function.
201196
# or re-base the frd to the current omega (if needed)
@@ -214,7 +209,7 @@ def __add__(self, other):
214209
def __radd__(self, other):
215210
"""Right add two LTI objects (parallel connection)."""
216211

217-
return self + other;
212+
return self + other
218213

219214
def __sub__(self, other):
220215
"""Subtract two LTI objects."""
@@ -238,16 +233,17 @@ def __mul__(self, other):
238233

239234
# Check that the input-output sizes are consistent.
240235
if self.inputs != other.outputs:
241-
raise ValueError("H = G1*G2: input-output size mismatch"
242-
" G1 has %i input(s), G2 has %i output(s)." %
236+
raise ValueError(
237+
"H = G1*G2: input-output size mismatch: "
238+
"G1 has %i input(s), G2 has %i output(s)." %
243239
(self.inputs, other.outputs))
244240

245241
inputs = other.inputs
246242
outputs = self.outputs
247243
fresp = empty((outputs, inputs, len(self.omega)),
248244
dtype=self.fresp.dtype)
249245
for i in range(len(self.omega)):
250-
fresp[:,:,i] = dot(self.fresp[:,:,i], other.fresp[:,:,i])
246+
fresp[:, :, i] = dot(self.fresp[:, :, i], other.fresp[:, :, i])
251247
return FRD(fresp, self.omega,
252248
smooth=(self.ifunc is not None) and
253249
(other.ifunc is not None))
@@ -264,8 +260,9 @@ def __rmul__(self, other):
264260

265261
# Check that the input-output sizes are consistent.
266262
if self.outputs != other.inputs:
267-
raise ValueError("H = G1*G2: input-output size mismatch"
268-
" G1 has %i input(s), G2 has %i output(s)." %
263+
raise ValueError(
264+
"H = G1*G2: input-output size mismatch: "
265+
"G1 has %i input(s), G2 has %i output(s)." %
269266
(other.inputs, self.outputs))
270267

271268
inputs = self.inputs
@@ -274,7 +271,7 @@ def __rmul__(self, other):
274271
fresp = empty((outputs, inputs, len(self.omega)),
275272
dtype=self.fresp.dtype)
276273
for i in range(len(self.omega)):
277-
fresp[:,:,i] = dot(other.fresp[:,:,i], self.fresp[:,:,i])
274+
fresp[:, :, i] = dot(other.fresp[:, :, i], self.fresp[:, :, i])
278275
return FRD(fresp, self.omega,
279276
smooth=(self.ifunc is not None) and
280277
(other.ifunc is not None))
@@ -289,11 +286,11 @@ def __truediv__(self, other):
289286
else:
290287
other = _convertToFRD(other, omega=self.omega)
291288

292-
293289
if (self.inputs > 1 or self.outputs > 1 or
294290
other.inputs > 1 or other.outputs > 1):
295291
raise NotImplementedError(
296-
"FRD.__truediv__ is currently implemented only for SISO systems.")
292+
"FRD.__truediv__ is currently only implemented for SISO "
293+
"systems.")
297294

298295
return FRD(self.fresp/other.fresp, self.omega,
299296
smooth=(self.ifunc is not None) and
@@ -315,20 +312,21 @@ def __rtruediv__(self, other):
315312
if (self.inputs > 1 or self.outputs > 1 or
316313
other.inputs > 1 or other.outputs > 1):
317314
raise NotImplementedError(
318-
"FRD.__rtruediv__ is currently implemented only for SISO systems.")
315+
"FRD.__rtruediv__ is currently only implemented for "
316+
"SISO systems.")
319317

320318
return other / self
321319

322320
# TODO: Remove when transition to python3 complete
323321
def __rdiv__(self, other):
324322
return self.__rtruediv__(other)
325323

326-
def __pow__(self,other):
324+
def __pow__(self, other):
327325
if not type(other) == int:
328326
raise ValueError("Exponent must be an integer")
329327
if other == 0:
330-
return FRD(ones(self.fresp.shape),self.omega,
331-
smooth=(self.ifunc is not None)) #unity
328+
return FRD(ones(self.fresp.shape), self.omega,
329+
smooth=(self.ifunc is not None)) # unity
332330
if other > 0:
333331
return self * (self**(other-1))
334332
if other < 0:
@@ -347,7 +345,7 @@ def evalfr(self, omega):
347345
348346
"""
349347
warn("FRD.evalfr(omega) will be deprecated in a future release "
350-
"of python-control; use sys.eval(omega) instead",
348+
"of python-control; use sys.eval(omega) instead",
351349
PendingDeprecationWarning) # pragma: no coverage
352350
return self._evalfr(omega)
353351

@@ -381,22 +379,22 @@ def _evalfr(self, omega):
381379
if self.ifunc is None:
382380
try:
383381
out = self.fresp[:, :, where(self.omega == omega)[0][0]]
384-
except:
382+
except Exception:
385383
raise ValueError(
386384
"Frequency %f not in frequency list, try an interpolating"
387385
" FRD if you want additional points" % omega)
388386
else:
389387
if getattr(omega, '__iter__', False):
390388
for i in range(self.outputs):
391389
for j in range(self.inputs):
392-
for k,w in enumerate(omega):
393-
frraw = splev(w, self.ifunc[i,j], der=0)
394-
out[i,j,k] = frraw[0] + 1.0j*frraw[1]
390+
for k, w in enumerate(omega):
391+
frraw = splev(w, self.ifunc[i, j], der=0)
392+
out[i, j, k] = frraw[0] + 1.0j * frraw[1]
395393
else:
396394
for i in range(self.outputs):
397395
for j in range(self.inputs):
398-
frraw = splev(omega, self.ifunc[i,j], der=0)
399-
out[i,j] = frraw[0] + 1.0j*frraw[1]
396+
frraw = splev(omega, self.ifunc[i, j], der=0)
397+
out[i, j] = frraw[0] + 1.0j * frraw[1]
400398

401399
return out
402400

@@ -406,9 +404,10 @@ def freqresp(self, omega):
406404
407405
mag, phase, omega = self.freqresp(omega)
408406
409-
reports the value of the magnitude, phase, and angular frequency of the
410-
transfer function matrix evaluated at s = i * omega, where omega is a
411-
list of angular frequencies, and is a sorted version of the input omega.
407+
reports the value of the magnitude, phase, and angular frequency of
408+
the transfer function matrix evaluated at s = i * omega, where omega
409+
is a list of angular frequencies, and is a sorted version of the input
410+
omega.
412411
413412
"""
414413

@@ -431,8 +430,7 @@ def feedback(self, other=1, sign=-1):
431430

432431
other = _convertToFRD(other, omega=self.omega)
433432

434-
if (self.outputs != other.inputs or
435-
self.inputs != other.outputs):
433+
if (self.outputs != other.inputs or self.inputs != other.outputs):
436434
raise ValueError(
437435
"FRD.feedback, inputs/outputs mismatch")
438436
fresp = empty((self.outputs, self.inputs, len(other.omega)),
@@ -452,6 +450,20 @@ def feedback(self, other=1, sign=-1):
452450

453451
return FRD(fresp, other.omega, smooth=(self.ifunc is not None))
454452

453+
#
454+
# Allow FRD as an alias for the FrequencyResponseData class
455+
#
456+
# Note: This class was initially given the name "FRD", but this caused
457+
# problems with documentation on MacOS platforms, since files were generated
458+
# for control.frd and control.FRD, which are not differentiated on most MacOS
459+
# filesystems, which are case insensitive. Renaming the FRD class to be
460+
# FrequenceResponseData and then assigning FRD to point to the same object
461+
# fixes this problem.
462+
#
463+
464+
FRD = FrequencyResponseData
465+
466+
455467
def _convertToFRD(sys, omega, inputs=1, outputs=1):
456468
"""Convert a system to frequency response data form (if needed).
457469
@@ -495,18 +507,19 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
495507
# try converting constant matrices
496508
try:
497509
sys = array(sys)
498-
outputs,inputs = sys.shape
510+
outputs, inputs = sys.shape
499511
fresp = empty((outputs, inputs, len(omega)), dtype=float)
500512
for i in range(outputs):
501513
for j in range(inputs):
502-
fresp[i,j,:] = sys[i,j]
514+
fresp[i, j, :] = sys[i, j]
503515
return FRD(fresp, omega, smooth=True)
504-
except:
516+
except Exception:
505517
pass
506518

507519
raise TypeError('''Can't convert given type "%s" to FRD system.''' %
508520
sys.__class__)
509521

522+
510523
def frd(*args):
511524
"""frd(d, w)
512525

doc/classes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ these directly.
1515

1616
TransferFunction
1717
StateSpace
18-
FRD
18+
FrequencyResponseData
1919
InputOutputSystem
2020

2121
Input/Output system subclasses

doc/conventions.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ function. A full list of functions can be found in :ref:`function-ref`.
6262

6363
FRD (frequency response data) systems
6464
-------------------------------------
65-
The :class:`FRD` class is used to represent systems in frequency response
66-
data form.
65+
The :class:`FrequencyResponseData` (FRD) class is used to represent systems in
66+
frequency response data form.
6767

6868
The main data members are `omega` and `fresp`, where `omega` is a 1D array
6969
with the frequency points of the response, and `fresp` is a 3D array, with

0 commit comments

Comments
 (0)