Skip to content

Commit ecdf1e7

Browse files
committed
add frequency_reponse() + FRD properties mag, phase, freq
1 parent 6c3c630 commit ecdf1e7

3 files changed

Lines changed: 57 additions & 17 deletions

File tree

control/frdata.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,29 @@ def __init__(self, *args, **kwargs):
233233
self.ifunc = None
234234
super().__init__(self.fresp.shape[1], self.fresp.shape[0])
235235

236+
#
237+
# Frequency response properties
238+
#
239+
# Different properties of the frequency response that can be used for
240+
# analysis and characterization.
241+
#
242+
243+
@property
244+
def magnitude(self):
245+
return np.abs(self.fresp)
246+
247+
@property
248+
def phase(self):
249+
return np.angle(self.fresp)
250+
251+
@property
252+
def frequency(self):
253+
return self.omega
254+
255+
@property
256+
def response(self):
257+
return self.fresp
258+
236259
def __str__(self):
237260
"""String representation of the transfer function."""
238261

control/lti.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
__all__ = ['issiso', 'timebase', 'common_timebase', 'timebaseEqual',
2121
'isdtime', 'isctime', 'pole', 'zero', 'damp', 'evalfr',
22-
'freqresp', 'dcgain']
22+
'frequency_response', 'freqresp', 'dcgain']
2323

2424
class LTI:
2525
"""LTI is a parent class to linear time-invariant (LTI) system objects.
@@ -172,16 +172,16 @@ def frequency_response(self, omega, squeeze=None):
172172
173173
Reports the frequency response of the system,
174174
175-
G(j*omega) = mag*exp(j*phase)
175+
G(j*omega) = mag * exp(j*phase)
176176
177-
for continuous time systems. For discrete time systems, the response is
178-
evaluated around the unit circle such that
177+
for continuous time systems. For discrete time systems, the response
178+
is evaluated around the unit circle such that
179179
180-
G(exp(j*omega*dt)) = mag*exp(j*phase).
180+
G(exp(j*omega*dt)) = mag * exp(j*phase).
181181
182182
In general the system may be multiple input, multiple output (MIMO),
183-
where `m = self.ninputs` number of inputs and `p = self.noutputs` number
184-
of outputs.
183+
where `m = self.ninputs` number of inputs and `p = self.noutputs`
184+
number of outputs.
185185
186186
Parameters
187187
----------
@@ -203,15 +203,15 @@ def frequency_response(self, omega, squeeze=None):
203203
204204
mag, phase, omega = response
205205
206-
where ``mag`` is the magnitude (absolute value, not dB or log10)
207-
of the system frequency response, ``phase`` is the wrapped phase
208-
in radians of the system frequency response, and ``omega`` is the
209-
(sorted) frequencies at which the response was evaluated. If the
210-
system is SISO and squeeze is not True, ``mag`` and ``phase`` are
211-
1D, indexed by frequency. If the system is not SISO or squeeze is
212-
False, the array is 3D, indexed by the output, input, and
213-
frequency. If ``squeeze`` is True then single-dimensional axes
214-
are removed.
206+
where ``mag`` is the magnitude (absolute value, not dB or
207+
log10) of the system frequency response, ``phase`` is the wrapped
208+
phase in radians of the system frequency response, and ``omega``
209+
is the (sorted) frequencies at which the response was evaluated.
210+
If the system is SISO and squeeze is not True, ``magnitude`` and
211+
``phase`` are 1D, indexed by frequency. If the system is not SISO
212+
or squeeze is False, the array is 3D, indexed by the output,
213+
input, and frequency. If ``squeeze`` is True then
214+
single-dimensional axes are removed.
215215
216216
"""
217217
omega = np.sort(np.array(omega, ndmin=1))
@@ -597,7 +597,7 @@ def evalfr(sys, x, squeeze=None):
597597
"""
598598
return sys.__call__(x, squeeze=squeeze)
599599

600-
def freqresp(sys, omega, squeeze=None):
600+
def frequency_response(sys, omega, squeeze=None):
601601
"""Frequency response of an LTI system at multiple angular frequencies.
602602
603603
In general the system may be multiple input, multiple output (MIMO), where
@@ -671,6 +671,10 @@ def freqresp(sys, omega, squeeze=None):
671671
return sys.frequency_response(omega, squeeze=squeeze)
672672

673673

674+
# Alternative name (legacy)
675+
freqresp = frequency_response
676+
677+
674678
def dcgain(sys):
675679
"""Return the zero-frequency (or DC) gain of the given system
676680

control/tests/frd_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,16 @@ def test_to_pandas():
519519
# Check to make sure the data make senses
520520
np.testing.assert_equal(df['omega'], resp.omega)
521521
np.testing.assert_equal(df['H_{y[0], u[0]}'], resp.fresp[0, 0])
522+
523+
524+
def test_frequency_response():
525+
# Create an SISO frequence response
526+
sys = ct.rss(2, 2, 2)
527+
omega = np.logspace(-2, 2, 20)
528+
resp = ct.frequency_response(sys, omega)
529+
eval = sys(omega*1j)
530+
531+
# Make sure we get the right answers in various ways
532+
np.testing.assert_equal(resp.magnitude, np.abs(eval))
533+
np.testing.assert_equal(resp.phase, np.angle(eval))
534+
np.testing.assert_equal(resp.omega, omega)

0 commit comments

Comments
 (0)