8000 Handle integrator, all-pass filters · python-control/python-control@0c81cb2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0c81cb2

Browse files
committed
Handle integrator, all-pass filters
1 parent 70e912f commit 0c81cb2

File tree

2 files changed

+46
-31
lines changed

2 files changed

+46
-31
lines changed

control/lti.py

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -215,37 +215,31 @@ def _bandwidth(self, dbdrop=-3):
215215
if not(np.isscalar(dbdrop)) or dbdrop >= 0:
216216
raise ValueError("expecting dbdrop be a negative scalar in dB")
217217

218-
# # # this will probabily fail if there is a resonant frequency larger than the bandwidth, the initial guess can be around that peak
219-
# G1 = ct.tf(0.1, [1, 0.1])
220-
# wn2 = 0.9
221-
# zeta2 = 0.001
222-
# G2 = ct.tf(wn2**2, [1, 2*zeta2*wn2, wn2**2])
223-
# ct.bandwidth(G1*G2)
224-
# import scipy
225-
# result = scipy.optimize.root(lambda w: np.abs(self(w*1j)) - np.abs(self.dcgain())*10**(dbdrop/20), x0=1)
226-
227-
# if result.success:
228-
# return np.abs(result.x)[0]
229-
230-
# use bodeplot to identify the 0-crossing bracket
218+
dcgain = self.dcgain()
219+
if np.isinf(dcgain):
220+
return np.nan
221+
222+
# use frequency range to identify the 0-crossing (dbdrop) bracket
231223
from control.freqplot import _default_frequency_range
232224
omega = _default_frequency_range(self)
233225
mag, phase, omega = self.frequency_response(omega)
226+
idx_dropped = np.nonzero(mag - dcgain*10**(dbdrop/20) < 0)[0]
234227

235-
dcgain = self.dcgain()
236-
idx_dropped = np.nonzero(mag - dcgain*10**(dbdrop/20) < 0)[0][0]
237-
238-
# solve for the bandwidth, use scipy.optimize.root_scalar() to solve using bisection
239-
import scipy
240-
result = scipy.optimize.root_scalar(lambda w: np.abs(self(w*1j)) - np.abs(dcgain)*10**(dbdrop/20),
241-
bracket=[omega[idx_dropped-1], omega[idx_dropped]],
242-
method='bisect')
243-
244-
# check solution
245-
if result.converged:
246-
return np.abs(result.root)
228+
if idx_dropped.shape[0] == 0:
229+
# no frequency response is dbdrop below the dc gain.
230+
return np.inf
247231
else:
248-
raise Exception(result.message)
232+
# solve for the bandwidth, use scipy.optimize.root_scalar() to solve using bisection
233+
import scipy
234+
result = scipy.optimize.root_scalar(lambda w: np.abs(self(w*1j)) - np.abs(dcgain)*10**(dbdrop/20),
235+
bracket=[omega[idx_dropped[0] - 1], omega[idx_dropped[0]]],
236+
method='bisect')
237+
238+
# check solution
239+
if result.converged:
240+
return np.abs(result.root)
241+
else:
242+
raise Exception(result.message)
249243

250244
def ispassive(self):
251245
# importing here prevents circular dependancy
@@ -557,10 +551,17 @@ def bandwidth(sys, dbdrop=-3):
557551
558552
Returns
559553
-------
560-
bandwidth : #TODO data-type
561-
The first frequency where the gain drops below dbdrop of the dc gain
562-
of the system.
563-
554+
bandwidth : ndarray
555+
The first frequency (rad/time-unit) where the gain drops below dbdrop of the dc gain
556+
of the system, or nan if the system has infinite dc gain, inf if the gain does not drop for all frequency
557+
558+
Raises
559+
------
560+
TypeError
561+
if 'sys' is not an SISO LTI instance
562+
ValueError
563+
if 'dbdrop' is not a negative scalar
564+
564565
Example
565566
-------
566567
>>> G = ct.tf([1], [1, 1])
@@ -575,6 +576,9 @@ def bandwidth(sys, dbdrop=-3):
575576
0.1018
576577
577578
"""
579+
if not isinstance(sys, LTI):
580+
raise TypeError("sys must be a LTI instance.")
581+
578582
return sys.bandwidth(dbdrop)
579583

580584

control/tests/lti_test.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,18 @@ def test_bandwidth(self):
117117
np.testing.assert_allclose(sys2.bandwidth(), 0.101848388240241)
118118
np.testing.assert_allclose(bandwidth(sys2), 0.101848388240241)
119119

120-
# test if raise exception given other than SISO system
120+
# test constant gain, bandwidth should be infinity
121+
sysAP = tf(1,1)
122+
np.testing.assert_allclose(bandwidth(sysAP), np.inf)
123+
124+
# test integrator, bandwidth should return np.nan
125+
sysInt = tf(1, [1, 0])
126+
np.testing.assert_allclose(bandwidth(sysInt), np.nan)
127+
128+
# test exception for system other than LTI
129+
np.testing.assert_raises(TypeError, bandwidth, 1)
130+
131+
# test exception for system other than SISO system
121132
sysMIMO = tf([[[-1, 41], [1]], [[1, 2], [3, 4]]],
122133
[[[1, 10], [1, 20]], [[1, 30], [1, 40]]])
123134
np.testing.assert_raises(TypeError, bandwidth, sysMIMO)

0 commit comments

Comments
 (0)
0