@@ -88,7 +88,7 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
88
88
----------
89
89
sys : LTI object
90
90
Linear input/output systems (SISO only, for now).
91
- kvect : list or ndarray , optional
91
+ kvect : float or array_like , optional
92
92
List of gains to use in computing diagram.
93
93
xlim : tuple or list, optional
94
94
Set limits of x axis, normally with tuple
@@ -110,10 +110,11 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
110
110
111
111
Returns
112
112
-------
113
- rlist : ndarray
114
- Computed root locations, given as a 2D array
115
- klist : ndarray or list
116
- Gains used. Same as klist keyword argument if provided.
113
+ roots : ndarray
114
+ Closed-loop root locations, arranged in which each row corresponds
115
+ to a gain in gains
116
+ gains : ndarray
117
+ Gains used. Same as kvect keyword argument if provided.
117
118
118
119
Notes
119
120
-----
@@ -145,10 +146,12 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
145
146
print_gain = config ._get_param (
146
147
'rlocus' , 'print_gain' , print_gain , _rlocus_defaults )
147
148
148
- sys_loop = sys if sys .issiso () else sys [0 , 0 ]
149
+ if not sys .issiso ():
150
+ raise ControlMIMONotImplemented (
151
+ 'sys must be single-input single-output (SISO)' )
149
152
150
153
# Convert numerator and denominator to polynomials if they aren't
151
- (nump , denp ) = _systopoly1d (sys_loop )
154
+ (nump , denp ) = _systopoly1d (sys )
152
155
153
156
# if discrete-time system and if xlim and ylim are not given,
154
157
# that we a view of the unit circle
@@ -158,12 +161,13 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
158
161
xlim = (- 1.3 , 1.3 )
159
162
160
163
if kvect is None :
161
- start_mat = _RLFindRoots (nump , denp , [ 1 ] )
162
- kvect , mymat , xlim , ylim = _default_gains (nump , denp , xlim , ylim )
164
+ start_roots = _RLFindRoots (nump , denp , 1 )
165
+ kvect , root_array , xlim , ylim = _default_gains (nump , denp , xlim , ylim )
163
166
else :
164
- start_mat = _RLFindRoots (nump , denp , [kvect [0 ]])
165
- mymat = _RLFindRoots (nump , denp , kvect )
166
- mymat = _RLSortRoots (mymat )
167
+ kvect = np .atleast_1d (kvect )
168
+ start_roots = _RLFindRoots (nump , denp , kvect [0 ])
169
+ root_array = _RLFindRoots (nump , denp , kvect )
170
+ root_array = _RLSortRoots (root_array )
167
171
168
172
# Check for sisotool mode
169
173
sisotool = False if 'sisotool' not in kwargs else True
@@ -190,10 +194,10 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
190
194
ax_rlocus = fig .axes [0 ], plotstr = plotstr ))
191
195
elif sisotool :
192
196
fig .axes [1 ].plot (
193
- [root .real for root in start_mat ],
194
- [root .imag for root in start_mat ],
197
+ [root .real for root in start_roots ],
198
+ [root .imag for root in start_roots ],
195
199
marker = 's' , markersize = 6 , zorder = 20 , color = 'k' , label = 'gain_point' )
196
- s = start_mat [0 ][0 ]
200
+ s = start_roots [0 ][0 ]
197
201
if isdtime (sys , strict = True ):
198
202
zeta = - np .cos (np .angle (np .log (s )))
199
203
else :
@@ -229,7 +233,7 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
229
233
ax .plot (real (zeros ), imag (zeros ), 'o' )
230
234
231
235
# Now plot the loci
232
- for index , col in enumerate (mymat .T ):
236
+ for index , col in enumerate (root_array .T ):
233
237
ax .plot (real (col ), imag (col ), plotstr , label = 'rootlocus' )
234
238
235
239
# Set up plot axes and labels
@@ -257,7 +261,7 @@ def root_locus(sys, kvect=None, xlim=None, ylim=None,
257
261
(0 , 0 ), radius = 1.0 , linestyle = ':' , edgecolor = 'k' ,
258
262
linewidth = 0.75 , fill = False , zorder = - 20 ))
259
263
260
- return mymat , kvect
264
+ return root_array , kvect
261
265
262
266
263
267
def _default_gains (num , den , xlim , ylim , zoom_xlim = None , zoom_ylim = None ):
@@ -509,28 +513,27 @@ def _RLFindRoots(nump, denp, kvect):
509
513
"""Find the roots for the root locus."""
510
514
# Convert numerator and denominator to polynomials if they aren't
511
515
roots = []
512
- for k in np .array (kvect , ndmin = 1 ):
516
+ for k in
23D3
np .atleast_1d (kvect ):
513
517
curpoly = denp + k * nump
514
518
curroots = curpoly .r
515
519
if len (curroots ) < denp .order :
516
520
# if I have fewer poles than open loop, it is because i have
517
521
# one at infinity
518
- curroots = np .insert (curroots , len ( curroots ) , np .inf )
522
+ curroots = np .append (curroots , np .inf )
519
523
520
524
curroots .sort ()
521
525
roots .append (curroots )
522
526
523
- mymat = row_stack (roots )
524
- return mymat
527
+ return row_stack (roots )
525
528
526
529
527
- def _RLSortRoots (mymat ):
528
- """Sort the roots from sys. _RLFindRoots, so that the root
530
+ def _RLSortRoots (roots ):
531
+ """Sort the roots from _RLFindRoots, so that the root
529
532
locus doesn't show weird pseudo-branches as roots jump from
530
533
one branch to another."""
531
534
532
- sorted = zeros_like (mymat )
533
- for n , row in enumerate (mymat ):
535
+ sorted = zeros_like (roots )
536
+ for n , row in enumerate (roots ):
534
537
if n == 0 :
535
538
sorted [n , :] = row
536
539
else :
@@ -539,7 +542,7 @@ def _RLSortRoots(mymat):
539
542
# previous row
540
543
available = list (range (len (prevrow )))
541
544
for elem in row :
542
- evect = elem - prevrow [available ]
545
+ evect = elem - prevrow [available ]
543
546
ind1 = abs (evect ).argmin ()
544
547
ind = available .pop (ind1 )
545
548
sorted [n , ind ] = elem
@@ -549,9 +552,7 @@ def _RLSortRoots(mymat):
549
552
550
553
def _RLZoomDispatcher (event , sys , ax_rlocus , plotstr ):
551
554
"""Rootlocus plot zoom dispatcher"""
552
- sys_loop = sys if sys .issiso () else sys [0 ,0 ]
553
-
554
- nump , denp = _systopoly1d (sys_loop )
555
+ nump , denp = _systopoly1d (sys )
555
556
xlim , ylim = ax_rlocus .get_xlim (), ax_rlocus .get_ylim ()
556
557
557
558
kvect , mymat , xlim , ylim = _default_gains (
@@ -583,9 +584,7 @@ def _RLClickDispatcher(event, sys, fig, ax_rlocus, plotstr, sisotool=False,
583
584
584
585
def _RLFeedbackClicksPoint (event , sys , fig , ax_rlocus , sisotool = False ):
585
586
"""Display root-locus gain feedback point for clicks on root-locus plot"""
586
- sys_loop = sys if sys .issiso () else sys [0 ,0 ]
587
-
588
- (nump , denp ) = _systopoly1d (sys_loop )
587
+ (nump , denp ) = _systopoly1d (sys )
589
588
590
589
xlim = ax_rlocus .get_xlim ()
591
590
ylim = ax_rlocus .get_ylim ()
@@ -596,10 +595,10 @@ def _RLFeedbackClicksPoint(event, sys, fig, ax_rlocus, sisotool=False):
596
595
# Catch type error when event click is in the figure but not in an axis
597
596
try :
598
597
s = complex (event .xdata , event .ydata )
599
- K = - 1. / sys_loop (s )
600
- K_xlim = - 1. / sys_loop (
598
+ K = - 1. / sys (s )
599
+ K_xlim = - 1. / sys (
601
600
complex (event .xdata + 0.05 * abs (xlim [1 ] - xlim [0 ]), event .ydata ))
602
- K_ylim = - 1. / sys_loop (
601
+ K_ylim = - 1. / sys (
603
602
complex (event .xdata , event .ydata + 0.05 * abs (ylim [1 ] - ylim [0 ])))
604
603
605
604
except TypeError :
0 commit comments