Skip to content

Commit 2500199

Browse files
authored
Merge pull request #575 from bnavigator/add-frd-margin-test
Ease cutoff between poly and frd method for stability margins
2 parents b41574f + 52d8fc3 commit 2500199

File tree

2 files changed

+30
-29
lines changed

2 files changed

+30
-29
lines changed

control/margins.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def _likely_numerical_inaccuracy(sys):
218218
# * z**(-p_q)
219219
x = [1] + [0] * (-p_q)
220220
p1 = np.polymul(p1, x)
221-
return np.linalg.norm(p1) < 1e-3 * np.linalg.norm(p2)
221+
return np.linalg.norm(p1) < 1e-4 * np.linalg.norm(p2)
222222

223223
# Took the framework for the old function by
224224
# Sawyer B. Fuller <minster@uw.edu>, removed a lot of the innards
@@ -337,7 +337,8 @@ def stability_margins(sysdata, returnall=False, epsw=0.0, method='best'):
337337
if isinstance(sys, xferfcn.TransferFunction) and not sys.isctime():
338338
if _likely_numerical_inaccuracy(sys):
339339
warn("stability_margins: Falling back to 'frd' method "
340-
"because of chance of numerical inaccuracy in 'poly' method.")
340+
"because of chance of numerical inaccuracy in 'poly' method.",
341+
stacklevel=2)
341342
omega_sys = freqplot._default_frequency_range(sys)
342343
omega_sys = omega_sys[omega_sys < np.pi / sys.dt]
343344
sys = frdata.FRD(sys, omega_sys, smooth=True)

control/tests/margin_test.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -336,41 +336,41 @@ def test_zmore_stability_margins(tsys_zmore):
336336
@pytest.mark.parametrize(
337337
'cnum, cden, dt,'
338338
'ref,'
339-
'rtol',
339+
'rtol, poly_is_inaccurate',
340340
[( # gh-465
341341
[2], [1, 3, 2, 0], 1e-2,
342-
[2.9558, 32.390, 0.43584, 1.4037, 0.74951, 0.97079],
343-
2e-3), # the gradient of the function reduces numerical precision
342+
[ 2.955761, 32.398492, 0.429535, 1.403725, 0.749367, 0.923898],
343+
1e-5, True),
344344
( # 2/(s+1)**3
345345
[2], [1, 3, 3, 1], .1,
346346
[3.4927, 65.4212, 0.5763, 1.6283, 0.76625, 1.2019],
347-
1e-4),
348-
( # gh-523
347+
1e-4, True),
348+
( # gh-523 a
349349
[1.1 * 4 * np.pi**2], [1, 2 * 0.2 * 2 * np.pi, 4 * np.pi**2], .05,
350350
[2.3842, 18.161, 0.26953, 11.712, 8.7478, 9.1504],
351-
1e-4),
351+
1e-4, False),
352+
( # gh-523 b
353+
# H1 = w1**2 / (z**2 + 2*zt*w1 * z + w1**2)
354+
# H2 = w2**2 / (z**2 + 2*zt*w2 * z + w2**2)
355+
# H = H1 * H2
356+
# w1 = 1, w2 = 100, zt = 0.5
357+
[5e4], [1., 101., 10101., 10100., 10000.], 1e-3,
358+
[18.8766, 26.3564, 0.406841, 9.76358, 2.32933, 2.55986],
359+
1e-5, True),
352360
])
353-
def test_stability_margins_discrete(cnum, cden, dt, ref, rtol):
361+
@pytest.mark.filterwarnings("error")
362+
def test_stability_margins_discrete(cnum, cden, dt,
363+
ref,
364+
rtol, poly_is_inaccurate):
354365
"""Test stability_margins with discrete TF input"""
355366
tf = TransferFunction(cnum, cden).sample(dt)
356-
out = stability_margins(tf, method='poly')
367+
if poly_is_inaccurate:
368+
with pytest.warns(UserWarning, match="numerical inaccuracy in 'poly'"):
369+
out = stability_margins(tf)
370+
# cover the explicit frd branch and make sure it yields the same
371+
# results as the fallback mechanism
372+
out_frd = stability_margins(tf, method='frd')
373+
assert_allclose(out, out_frd)
374+
else:
375+
out = stability_margins(tf)
357376
assert_allclose(out, ref, rtol=rtol)
358-
359-
360-
def test_stability_margins_methods():
361-
# the following system gives slightly inaccurate result for DT systems
362-
# because of numerical issues
363-
omegan = 1
364-
zeta = 0.5
365-
resonance = TransferFunction(omegan**2, [1, 2*zeta*omegan, omegan**2])
366-
omegan2 = 100
367-
resonance2 = TransferFunction(omegan2**2, [1, 2*zeta*omegan2, omegan2**2])
368-
sys = 5 * resonance * resonance2
369-
sysd = sys.sample(0.001, 'zoh')
370-
"""Test stability_margins() function with different methods"""
371-
out = stability_margins(sysd, method='best')
372-
# confirm getting reasonable results using FRD method
373-
assert_allclose(
374-
(18.876634740386308, 26.356358386241055, 0.40684127995261044,
375-
9.763585494645046, 2.3293357226374805, 2.55985695034263),
376-
stability_margins(sysd, method='frd'), rtol=1e-5)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy