Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitff7d827

Browse files
murrayrmbnavigator
authored andcommitted
fix rlocus timeout due to inefficient _default_wn calculation
1 parent73f65df commitff7d827

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

‎control/rlocus.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,9 @@ def _sgrid_func(fig=None, zeta=None, wn=None):
646646
else:
647647
ax=fig.axes[1]
648648

649-
# Get locator function for x-axis tick marks
649+
# Get locator function for x-axis, y-axis tick marks
650650
xlocator=ax.get_xaxis().get_major_locator()
651+
ylocator=ax.get_yaxis().get_major_locator()
651652

652653
# Decide on the location for the labels (?)
653654
ylim=ax.get_ylim()
@@ -690,7 +691,7 @@ def _sgrid_func(fig=None, zeta=None, wn=None):
690691
# omega-constant lines
691692
angles=np.linspace(-90,90,20)*np.pi/180
692693
ifwnisNone:
693-
wn=_default_wn(xlocator(),ylim)
694+
wn=_default_wn(xlocator(),ylocator())
694695

695696
forominwn:
696697
ifom<0:
@@ -746,7 +747,7 @@ def _default_zetas(xlim, ylim):
746747
returnzeta.tolist()
747748

748749

749-
def_default_wn(xloc,ylim):
750+
def_default_wn(xloc,yloc,max_lines=7):
750751
"""Return default wn for root locus plot
751752
752753
This function computes a list of natural frequencies based on the grid
@@ -758,23 +759,30 @@ def _default_wn(xloc, ylim):
758759
List of x-axis tick values
759760
ylim : array_like
760761
List of y-axis limits [min, max]
762+
max_lines : int, optional
763+
Maximum number of frequencies to generate (default = 7)
761764
762765
Returns
763766
-------
764767
wn : list
765768
List of default natural frequencies for the plot
766769
767770
"""
771+
sep=xloc[1]-xloc[0]# separation between x-ticks
772+
773+
# Decide whether to use the x or y axis for determining wn
774+
ifyloc[-1]/sep>max_lines*10:
775+
# y-axis scale >> x-axis scale
776+
wn=yloc# one frequency per y-axis tick mark
777+
else:
778+
wn=xloc# one frequency per x-axis tick mark
768779

769-
wn=xloc# one frequency per x-axis tick mark
770-
sep=xloc[1]-xloc[0]# separation between ticks
771-
772-
# Insert additional frequencies to span the y-axis
773-
whilenp.abs(wn[0])<ylim[1]:
774-
wn=np.insert(wn,0,wn[0]-sep)
780+
# Insert additional frequencies to span the y-axis
781+
whilenp.abs(wn[0])<yloc[-1]:
782+
wn=np.insert(wn,0,wn[0]-sep)
775783

776784
# If there are too many values, cut them in half
777-
whilelen(wn)>7:
785+
whilelen(wn)>max_lines:
778786
wn=wn[0:-1:2]
779787

780788
returnwn

‎control/tests/rlocus_test.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
fromnumpy.testingimportassert_array_almost_equal
99
importpytest
1010

11+
importcontrolasct
1112
fromcontrol.rlocusimportroot_locus,_RLClickDispatcher
1213
fromcontrol.xferfcnimportTransferFunction
1314
fromcontrol.statespimportStateSpace
@@ -74,3 +75,31 @@ def test_root_locus_zoom(self):
7475

7576
assert_array_almost_equal(zoom_x,zoom_x_valid)
7677
assert_array_almost_equal(zoom_y,zoom_y_valid)
78+
79+
deftest_rlocus_default_wn(self):
80+
"""Check that default wn calculation works properly"""
81+
#
82+
# System that triggers use of y-axis as basis for wn (for coverage)
83+
#
84+
# This system generates a root locus plot that used to cause the
85+
# creation (and subsequent deletion) of a large number of natural
86+
# frequency contours within the `_default_wn` function in `rlocus.py`.
87+
# This unit test makes sure that is fixed by generating a test case
88+
# that will take a long time to do the calculation (minutes).
89+
#
90+
importscipyassp
91+
importsignal
92+
93+
# Define a system that exhibits this behavior
94+
sys=ct.tf(*sp.signal.zpk2tf(
95+
[-1e-2,1-1e7j,1+1e7j], [0,-1e7j,1e7j],1))
96+
97+
# Set up a timer to catch execution time
98+
defsignal_handler(signum,frame):
99+
raiseException("rlocus took too long to complete")
100+
signal.signal(signal.SIGALRM,signal_handler)
101+
102+
# Run the command and reset the alarm
103+
signal.alarm(2)# 2 second timeout
104+
ct.root_locus(sys)
105+
signal.alarm(0)# reset the alarm

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp