Skip to content

Commit de87bb0

Browse files
committed
reorder code that calculate defaults damp coefficents constant lines and wn constant lines.
grids ok in most of the examples.
1 parent 3fb2c86 commit de87bb0

File tree

1 file changed

+43
-26
lines changed

1 file changed

+43
-26
lines changed

control/rlocus.py

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None, plotstr='-', Plot=True,
139139
ax.set_ylabel('Imaginary')
140140
if grid:
141141
sgrid_func(f)
142-
143142
return mymat, kvect
144143

145144

@@ -162,7 +161,7 @@ def _default_gains(num, den, xlim, ylim):
162161
mymat_xl = mymat
163162
singular_points = np.concatenate((num.roots, den.roots), axis=0)
164163
important_points = np.concatenate((singular_points, real_break), axis=0)
165-
important_points = np.concatenate((singular_points, np.zeros(2)), axis=0)
164+
important_points = np.concatenate((important_points, np.zeros(2)), axis=0)
166165
mymat_xl = np.append(mymat_xl, important_points)
167166

168167
if xlim is None:
@@ -267,6 +266,7 @@ def _systopoly1d(sys):
267266
# Check to see if num, den are already polynomials; otherwise convert
268267
if (not isinstance(nump, poly1d)):
269268
nump = poly1d(nump)
269+
270270
if (not isinstance(denp, poly1d)):
271271
denp = poly1d(denp)
272272

@@ -321,55 +321,72 @@ def _RLFeedbackClicks(event, sys):
321321
(s.real, s.imag, K.real, -1 * s.real / abs(s)))
322322

323323

324-
def sgrid_func(fig):
324+
def sgrid_func(fig, zeta=None, wn=None):
325325
ax = fig.gca()
326326
ylocator = ax.get_yaxis().get_major_locator()
327-
xlocator = ax.get_yaxis().get_major_locator()
327+
xlocator = ax.get_xaxis().get_major_locator()
328328

329-
angules = np.arange(-90, 80, 15)*np.pi/180
329+
if zeta is None:
330+
zeta = _default_zetas(xlocator(), ylocator())
331+
332+
angules = []
333+
for z in zeta:
334+
if (z >= 1e-4) & (z < 1):
335+
angules.append(np.pi/2 + np.arcsin(z))
336+
else:
337+
zeta.remove(z)
338+
y_over_x = np.tan(angules)
330339

331340
# zeta-constant lines
332-
y_over_x = np.tan(angules[1::])*ylocator()[-1]/xlocator()[-1]
333341
ylim = ax.get_ylim()
334342
ytext_pos_lim = ylim[1]-(ylim[1]-ylim[0])*0.03
335343
xlim = ax.get_xlim()
336344
xtext_pos_lim = xlim[0]+(xlim[1]-xlim[0])*0.0
337345
index = 0
338-
zeta = np.sin(np.pi/2-angules[1::])
339346

340347
for yp in y_over_x:
341348
ax.plot([0, xlocator()[0]], [0, yp*xlocator()[0]], color='gray',
342349
linestyle='dashed', linewidth=0.5)
350+
ax.plot([0, xlocator()[0]], [0, -yp * xlocator()[0]], color='gray',
351+
linestyle='dashed', linewidth=0.5)
343352
an = "%.2f" % zeta[index]
344-
if yp > 0:
345-
xtext_pos = -1/yp * ylim[1]
346-
ytext_pos = -yp * xtext_pos_lim
347-
if np.abs(xtext_pos) > np.abs(xtext_pos_lim):
348-
xtext_pos = xtext_pos_lim
349-
else:
350-
ytext_pos = ytext_pos_lim
351-
ax.annotate(an, textcoords='data', xy=[xtext_pos, ytext_pos], fontsize=8)
352-
elif yp < 0:
353-
xtext_pos = -1/yp * ylim[1]
353+
if yp < 0:
354+
xtext_pos = 1/yp * ylim[1]
354355
ytext_pos = yp * xtext_pos_lim
355356
if np.abs(xtext_pos) > np.abs(xtext_pos_lim):
356357
xtext_pos = xtext_pos_lim
357-
ytext_pos = - ytext_pos
358358
else:
359-
ytext_pos = ylim[0]
360-
xtext_pos = -xtext_pos
359+
ytext_pos = ytext_pos_lim
361360
ax.annotate(an, textcoords='data', xy=[xtext_pos, ytext_pos], fontsize=8)
362361
index += 1
363362
ax.plot([0, 0], [ylim[0], ylim[1]], color='gray', linestyle='dashed', linewidth=0.5)
364363

365364
angules = np.linspace(-90, 90, 20)*np.pi/180
366-
for xt in xlocator():
367-
if xt < 0:
368-
yp = np.sin(angules)*np.abs(xt)
369-
xp = -np.cos(angules)*np.abs(xt)
365+
if wn is None:
366+
wn = _default_wn(xlocator(), ylocator())
367+
368+
for om in wn:
369+
if om < 0:
370+
yp = np.sin(angules)*np.abs(om)
371+
xp = -np.cos(angules)*np.abs(om)
370372
ax.plot(xp, yp, color='gray',
371373
linestyle='dashed', linewidth=0.5)
372-
an = "%.2f" % -xt
373-
ax.annotate(an, textcoords='data', xy=[xt, 0], fontsize=8)
374+
an = "%.2f" % -om
375+
ax.annotate(an, textcoords='data', xy=[om, 0], fontsize=8)
376+
377+
378+
def _default_zetas(xloc, yloc):
379+
"""Return default list of dumps coefficients"""
380+
# TODO: smart selection on zetas to draw in root locus plot
381+
angules = np.arange(0, 80, 15) * np.pi / 180
382+
zeta = np.sin(np.pi/2 - angules[1::])
383+
return zeta.tolist()
384+
385+
386+
def _default_wn(xloc, yloc):
387+
"""Return default wn for root locus plot"""
388+
# TODO: better selection of wn (up to maximum ylim with same separation in xloc)
389+
wn = xloc
390+
return wn
374391

375392
rlocus = root_locus

0 commit comments

Comments
 (0)