24
24
from .iosys import isdtime
25
25
from .xferfcn import _convert_to_transfer_function
26
26
from .exception import ControlMIMONotImplemented
27
- from .grid import sgrid , zgrid
28
27
from . import config
29
28
import warnings
30
29
@@ -96,19 +95,25 @@ def root_locus_plot(
96
95
(see :doc:`matplotlib:api/axes_api`).
97
96
plotstr : :func:`matplotlib.pyplot.plot` format string, optional
98
97
plotting style specification
98
+ TODO: check
99
99
plot : boolean, optional
100
100
If True (default), plot root locus diagram.
101
+ TODO: legacy
101
102
print_gain : bool
102
103
If True (default), report mouse clicks when close to the root locus
103
104
branches, calculate gain, damping and print.
104
- grid : bool
105
- If True plot omega-damping grid. Default is False.
105
+ TODO: update
106
+ grid : bool or str, optional
107
+ If `True` plot omega-damping grid, if `False` show imaginary axis
108
+ for continuous time systems, unit circle for discrete time systems.
109
+ If `empty`, do not draw any additonal lines. Default value is set
110
+ by config.default['rlocus.grid'].
106
111
ax : :class:`matplotlib.axes.Axes`
107
112
Axes on which to create root locus plot
108
113
initial_gain : float, optional
109
114
Specify the initial gain to use when marking current gain. [TODO: update]
110
115
111
- Returns
116
+ Returns (TODO: update)
112
117
-------
113
118
roots : ndarray
114
119
Closed-loop root locations, arranged in which each row corresponds
@@ -156,8 +161,7 @@ def root_locus_plot(
156
161
return out
157
162
158
163
159
- # TODO: get rid of zoom functionality?
160
- def _default_gains (num , den , xlim , ylim , zoom_xlim = None , zoom_ylim = None ):
164
+ def _default_gains (num , den , xlim , ylim ):
161
165
"""Unsupervised gains calculation for root locus plot.
162
166
163
167
References
@@ -237,8 +241,7 @@ def _default_gains(num, den, xlim, ylim, zoom_xlim=None, zoom_ylim=None):
237
241
tolerance = x_tolerance
238
242
else :
239
243
tolerance = np .min ([x_tolerance , y_tolerance ])
240
- indexes_too_far = _indexes_filt (
241
- root_array , tolerance , zoom_xlim , zoom_ylim )
244
+ indexes_too_far = _indexes_filt (root_array , tolerance )
242
245
243
246
# Add more points into the root locus for points that are too far apart
244
247
while len (indexes_too_far ) > 0 and kvect .size < 5000 :
@@ -250,8 +253,7 @@ def _default_gains(num, den, xlim, ylim, zoom_xlim=None, zoom_ylim=None):
250
253
root_array = np .insert (root_array , index + 1 , new_points , axis = 0 )
251
254
252
255
root_array = _RLSortRoots (root_array )
253
- indexes_too_far = _indexes_filt (
254
- root_array , tolerance , zoom_xlim , zoom_ylim )
256
+ indexes_too_far = _indexes_filt (root_array , tolerance )
255
257
256
258
new_gains = kvect [- 1 ] * np .hstack ((np .logspace (0 , 3 , 4 )))
257
259
new_points = _RLFindRoots (num , den , new_gains [1 :4 ])
@@ -261,7 +263,7 @@ def _default_gains(num, den, xlim, ylim, zoom_xlim=None, zoom_ylim=None):
261
263
return kvect , root_array , xlim , ylim
262
264
263
265
264
- def _indexes_filt (root_array , tolerance , zoom_xlim = None , zoom_ylim = None ):
266
+ def _indexes_filt (root_array , tolerance ):
265
267
"""Calculate the distance between points and return the indices.
266
268
267
269
Filter the indexes so only the resolution of points within the xlim and
@@ -270,48 +272,6 @@ def _indexes_filt(root_array, tolerance, zoom_xlim=None, zoom_ylim=None):
270
272
"""
271
273
distance_points = np .abs (np .diff (root_array , axis = 0 ))
272
274
indexes_too_far = list (np .unique (np .where (distance_points > tolerance )[0 ]))
273
-
274
- if zoom_xlim is not None and zoom_ylim is not None :
275
- x_tolerance_zoom = 0.05 * (zoom_xlim [1 ] - zoom_xlim [0 ])
276
- y_tolerance_zoom = 0.05 * (zoom_ylim [1 ] - zoom_ylim [0 ])
277
- tolerance_zoom = np .min ([x_tolerance_zoom , y_tolerance_zoom ])
278
- indexes_too_far_zoom = list (
279
- np .unique (np .where (distance_points > tolerance_zoom )[0 ]))
280
- indexes_too_far_filtered = []
281
-
282
- for index in indexes_too_far_zoom :
283
- for point in root_array [index ]:
284
- if (zoom_xlim [0 ] <= point .real <= zoom_xlim [1 ]) and \
285
- (zoom_ylim [0 ] <= point .imag <= zoom_ylim [1 ]):
286
- indexes_too_far_filtered .append (index )
287
- break
288
-
289
- # Check if zoom box is not overshot & insert points where neccessary
290
- if len (indexes_too_far_filtered ) == 0 and len (root_array ) < 500 :
291
- limits = [zoom_xlim [0 ], zoom_xlim [1 ], zoom_ylim [0 ], zoom_ylim [1 ]]
292
- for index , limit in enumerate (limits ):
293
- if index <= 1 :
294
- asign = np .sign (real (root_array )- limit )
295
- else :
296
- asign = np .sign (imag (root_array ) - limit )
297
- signchange = ((np .roll (asign , 1 , axis = 0 )
298
- - asign ) != 0 ).astype (int )
299
- signchange [0 ] = np .zeros ((len (root_array [0 ])))
300
- if len (np .where (signchange == 1 )[0 ]) > 0 :
301
- indexes_too_far_filtered .append (
302
- np .where (signchange == 1 )[0 ][0 ]- 1 )
303
-
304
- if len (indexes_too_far_filtered ) > 0 :
305
- if indexes_too_far_filtered [0 ] != 0 :
306
- indexes_too_far_filtered .insert (
307
- 0 , indexes_too_far_filtered [0 ]- 1 )
308
- if not indexes_too_far_filtered [- 1 ] + 1 >= len (root_array ) - 2 :
309
- indexes_too_far_filtered .append (
310
- indexes_too_far_filtered [- 1 ] + 1 )
311
-
312
- indexes_too_far .extend (indexes_too_far_filtered )
313
-
314
- indexes_too_far = list (np .unique (indexes_too_far ))
315
275
indexes_too_far .sort ()
316
276
return indexes_too_far
317
277
0 commit comments