Skip to content

Commit 346bc40

Browse files
authored
Merge pull request #863 from henklaak/main
Solve #862 and #864: bode_plot phase wrapping incorrect for multiple systems
2 parents c4d1764 + 4c4b3fc commit 346bc40

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

control/freqplot.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -276,18 +276,21 @@ def bode_plot(syslist, omega=None,
276276
if initial_phase is None:
277277
# Start phase in the range 0 to -360 w/ initial phase = -180
278278
# If wrap_phase is true, use 0 instead (phase \in (-pi, pi])
279-
initial_phase = -math.pi if wrap_phase is not True else 0
279+
initial_phase_value = -math.pi if wrap_phase is not True else 0
280280
elif isinstance(initial_phase, (int, float)):
281281
# Allow the user to override the default calculation
282282
if deg:
283-
initial_phase = initial_phase/180. * math.pi
283+
initial_phase_value = initial_phase/180. * math.pi
284+
else:
285+
initial_phase_value = initial_phase
286+
284287
else:
285288
raise ValueError("initial_phase must be a number.")
286289

287290
# Shift the phase if needed
288-
if abs(phase[0] - initial_phase) > math.pi:
291+
if abs(phase[0] - initial_phase_value) > math.pi:
289292
phase -= 2*math.pi * \
290-
round((phase[0] - initial_phase) / (2*math.pi))
293+
round((phase[0] - initial_phase_value) / (2*math.pi))
291294

292295
# Phase wrapping
293296
if wrap_phase is False:
@@ -1021,9 +1024,11 @@ def _parse_linestyle(style_name, allow_false=False):
10211024
# Plot the scaled sections of the curve (changing linestyle)
10221025
x_scl = np.ma.masked_where(scale_mask, resp.real)
10231026
y_scl = np.ma.masked_where(scale_mask, resp.imag)
1024-
plt.plot(
1025-
x_scl * (1 + curve_offset), y_scl * (1 + curve_offset),
1026-
primary_style[1], color=c, **kwargs)
1027+
if x_scl.count() >= 1 and y_scl.count() >= 1:
1028+
plt.plot(
1029+
x_scl * (1 + curve_offset),
1030+
y_scl * (1 + curve_offset),
1031+
primary_style[1], color=c, **kwargs)
10271032

10281033
# Plot the primary curve (invisible) for setting arrows
10291034
x, y = resp.real.copy(), resp.imag.copy()
@@ -1041,10 +1046,11 @@ def _parse_linestyle(style_name, allow_false=False):
10411046
# Plot the regular and scaled segments
10421047
plt.plot(
10431048
x_reg, -y_reg, mirror_style[0], color=c, **kwargs)
1044-
plt.plot(
1045-
x_scl * (1 - curve_offset),
1046-
-y_scl * (1 - curve_offset),
1047-
mirror_style[1], color=c, **kwargs)
1049+
if x_scl.count() >= 1 and y_scl.count() >= 1:
1050+
plt.plot(
1051+
x_scl * (1 - curve_offset),
1052+
-y_scl * (1 - curve_offset),
1053+
mirror_style[1], color=c, **kwargs)
10481054

10491055
# Add the arrows (on top of an invisible contour)
10501056
x, y = resp.real.copy(), resp.imag.copy()

control/tests/freqresp_test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,18 @@ def test_phase_wrap(TF, wrap_phase, min_phase, max_phase):
375375
assert(max(phase) <= max_phase)
376376

377377

378+
def test_phase_wrap_multiple_systems():
379+
sys_unstable = ctrl.zpk([],[1,1], gain=1)
380+
381+
mag, phase, omega = ctrl.bode(sys_unstable, plot=False)
382+
assert(np.min(phase) >= -2*np.pi)
383+
assert(np.max(phase) <= -1*np.pi)
384+
385+
mag, phase, omega = ctrl.bode((sys_unstable, sys_unstable), plot=False)
386+
assert(np.min(phase) >= -2*np.pi)
387+
assert(np.max(phase) <= -1*np.pi)
388+
389+
378390
def test_freqresp_warn_infinite():
379391
"""Test evaluation warnings for transfer functions w/ pole at the origin"""
380392
sys_finite = ctrl.tf([1], [1, 0.01])

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