PageRenderTime 41ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/octave-forge/extra/control-legacy/inst/rlocus.m

#
MATLAB | 330 lines | 315 code | 15 blank | 0 comment | 26 complexity | aab0d853b489f09fe862f66c96c55670 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, GPL-3.0, LGPL-3.0
  1. ## Copyright (C) 1996, 2000, 2004, 2005, 2006, 2007
  2. ## Auburn University. All rights reserved.
  3. ##
  4. ##
  5. ## This program is free software; you can redistribute it and/or modify it
  6. ## under the terms of the GNU General Public License as published by
  7. ## the Free Software Foundation; either version 3 of the License, or (at
  8. ## your option) any later version.
  9. ##
  10. ## This program is distributed in the hope that it will be useful, but
  11. ## WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. ## General Public License for more details.
  14. ##
  15. ## You should have received a copy of the GNU General Public License
  16. ## along with this program; see the file COPYING. If not, see
  17. ## <http://www.gnu.org/licenses/>.
  18. ## -*- texinfo -*-
  19. ## @deftypefn {Function File} {[@var{rldata}, @var{k}] =} rlocus (@var{sys}[, @var{increment}, @var{min_k}, @var{max_k}])
  20. ##
  21. ## Display root locus plot of the specified @acronym{SISO} system.
  22. ## @example
  23. ## @group
  24. ## ----- --- --------
  25. ## --->| + |---|k|---->| SISO |----------->
  26. ## ----- --- -------- |
  27. ## - ^ |
  28. ## |_____________________________|
  29. ## @end group
  30. ## @end example
  31. ##
  32. ## @strong{Inputs}
  33. ## @table @var
  34. ## @item sys
  35. ## system data structure
  36. ## @item min_k
  37. ## Minimum value of @var{k}
  38. ## @item max_k
  39. ## Maximum value of @var{k}
  40. ## @item increment
  41. ## The increment used in computing gain values
  42. ## @end table
  43. ##
  44. ## @strong{Outputs}
  45. ##
  46. ## Plots the root locus to the screen.
  47. ## @table @var
  48. ## @item rldata
  49. ## Data points plotted: in column 1 real values, in column 2 the imaginary values.
  50. ## @item k
  51. ## Gains for real axis break points.
  52. ## @end table
  53. ## @end deftypefn
  54. ## Author: David Clem
  55. ## Author: R. Bruce Tenison <btenison@eng.auburn.edu>
  56. ## Updated by Kristi McGowan July 1996 for intelligent gain selection
  57. ## Updated by John Ingram July 1996 for systems
  58. function [rldata, k_break, rlpol, gvec, real_ax_pts] = rlocus (sys, increment, min_k, max_k)
  59. if (nargin < 1 || nargin > 4)
  60. print_usage ();
  61. endif
  62. ## Convert the input to a transfer function if necessary
  63. [num, den] = sys2tf (sys); # extract numerator/denom polyomials
  64. lnum = length (num);
  65. lden = length (den);
  66. ## equalize length of num, den polynomials
  67. if (lden < 2)
  68. error ("system has no poles");
  69. elseif (lnum < lden)
  70. num = [zeros(1,lden-lnum), num]; # so that derivative is shortened by one
  71. endif
  72. olpol = roots (den);
  73. olzer = roots (num);
  74. nas = lden - lnum; # number of asymptotes
  75. maxk = 0;
  76. if (nas > 0)
  77. cas = (sum (olpol) - sum (olzer)) / nas;
  78. angles = (2*[1:nas]-1)*pi/nas;
  79. # printf("rlocus: there are %d asymptotes centered at %f\n", nas, cas);
  80. else
  81. cas = angles = [];
  82. maxk = 100*den(1)/num(1);
  83. endif
  84. # compute real axis break points and corresponding gains
  85. dnum = polyderiv (num);
  86. dden = polyderiv (den);
  87. brkp = conv (den, dnum) - conv (num, dden);
  88. real_ax_pts = roots (brkp);
  89. real_ax_pts = real_ax_pts(find (imag (real_ax_pts) == 0));
  90. k_break = -polyval (den, real_ax_pts) ./ polyval (num, real_ax_pts);
  91. idx = find (k_break >= 0);
  92. k_break = k_break(idx);
  93. real_ax_pts = real_ax_pts(idx);
  94. if (! isempty (k_break))
  95. maxk = max (max (k_break), maxk);
  96. endif
  97. if (nas == 0)
  98. maxk = max (1, 2*maxk); # get at least some root locus
  99. else
  100. ## get distance from breakpoints, poles, and zeros to center of asymptotes
  101. dmax = 3*max (abs ([vec(olzer); vec(olpol); vec(real_ax_pts)] - cas));
  102. if (dmax == 0)
  103. dmax = 1;
  104. endif
  105. # get gain for dmax along each asymptote, adjust maxk if necessary
  106. svals = cas + dmax * exp (j*angles);
  107. kvals = -polyval (den, svals) ./ polyval (num, svals);
  108. maxk = max (maxk, max (real (kvals)));
  109. endif
  110. ## check for input arguments:
  111. if (nargin > 2)
  112. mink = min_k;
  113. else
  114. mink = 0;
  115. endif
  116. if (nargin > 3)
  117. maxk = max_k;
  118. endif
  119. if (nargin > 1)
  120. if (increment <= 0)
  121. error ("increment must be positive");
  122. else
  123. ngain = (maxk-mink)/increment;
  124. endif
  125. else
  126. ngain = 30;
  127. endif
  128. ## vector of gains
  129. ngain = max (30, ngain);
  130. gvec = linspace (mink, maxk, ngain);
  131. if (length (k_break))
  132. gvec = sort ([gvec, vec(k_break)']);
  133. endif
  134. ## Find the open loop zeros and the initial poles
  135. rlzer = roots (num);
  136. ## update num to be the same length as den
  137. lnum = length (num);
  138. if (lnum < lden)
  139. num = [zeros(1,lden - lnum),num];
  140. endif
  141. ## compute preliminary pole sets
  142. nroots = lden - 1;
  143. for ii = 1:ngain
  144. gain = gvec(ii);
  145. rlpol(1:nroots,ii) = vec(sortcom (roots (den + gain*num)));
  146. endfor
  147. ## set smoothing tolerance
  148. smtolx = 0.01*(max (max (real (rlpol))) - min (min (real (rlpol))));
  149. smtoly = 0.01*(max (max (imag (rlpol))) - min (min (imag (rlpol))));
  150. smtol = max (smtolx, smtoly);
  151. ## sort according to nearest-neighbor
  152. rlpol = sort_roots (rlpol, smtolx, smtoly);
  153. done = (nargin == 4); # perform a smoothness check
  154. while (! done && ngain < 1000)
  155. done = 1 ; # assume done
  156. dp = abs (diff (rlpol'))';
  157. maxdp = max (dp);
  158. ## search for poles whose neighbors are distant
  159. if (lden == 2)
  160. idx = find (dp > smtol);
  161. else
  162. idx = find (maxdp > smtol);
  163. endif
  164. for ii = 1:length(idx)
  165. i1 = idx(ii);
  166. g1 = gvec(i1);
  167. p1 = rlpol(:,i1);
  168. i2 = idx(ii)+1;
  169. g2 = gvec(i2);
  170. p2 = rlpol(:,i2);
  171. ## isolate poles in p1, p2
  172. if (max (abs (p2-p1)) > smtol)
  173. newg = linspace (g1, g2, 5);
  174. newg = newg(2:4);
  175. gvec = [gvec,newg];
  176. done = 0; # need to process new gains
  177. endif
  178. endfor
  179. ## process new gain values
  180. ngain1 = length (gvec);
  181. for ii = (ngain+1):ngain1
  182. gain = gvec(ii);
  183. rlpol(1:nroots,ii) = vec(sortcom (roots (den + gain*num)));
  184. endfor
  185. [gvec, idx] = sort (gvec);
  186. rlpol = rlpol(:,idx);
  187. ngain = length (gvec);
  188. ## sort according to nearest-neighbor
  189. rlpol = sort_roots (rlpol, smtolx, smtoly);
  190. endwhile
  191. rldata = rlpol;
  192. ## Plot the data
  193. if (nargout == 0)
  194. rlpolv = vec(rlpol);
  195. axdata = [real(rlpolv), imag(rlpolv); real(olzer), imag(olzer)];
  196. axlim = __axis2dlim__ (axdata);
  197. rldata = [real(rlpolv), imag(rlpolv) ];
  198. [stn, inname, outname] = sysgetsignals (sys);
  199. ## build plot command args pole by pole
  200. n_rlpol = rows (rlpol);
  201. nelts = n_rlpol+1;
  202. if (! isempty (rlzer))
  203. nelts++;
  204. endif
  205. # add asymptotes
  206. n_A = length (olpol) - length (olzer);
  207. if (n_A > 0)
  208. nelts += n_A;
  209. endif
  210. args = cell (3, nelts);
  211. kk = 0;
  212. # asymptotes first
  213. if (n_A > 0)
  214. len_A = 2*max (abs (axlim));
  215. sigma_A = (sum(olpol) - sum(olzer))/n_A;
  216. for i_A=0:n_A-1
  217. phi_A = pi*(2*i_A + 1)/n_A;
  218. args{1,++kk} = [sigma_A sigma_A+len_A*cos(phi_A)];
  219. args{2,kk} = [0 len_A*sin(phi_A)];
  220. if (i_A == 1)
  221. args{3,kk} = "k--;asymptotes;";
  222. else
  223. args{3,kk} = "k--";
  224. endif
  225. endfor
  226. endif
  227. # locus next
  228. for ii = 1:rows(rlpol)
  229. args{1,++kk} = real (rlpol (ii,:));
  230. args{2,kk} = imag (rlpol (ii,:));
  231. if (ii == 1)
  232. args{3,kk} = "b-;locus;";
  233. else
  234. args{3,kk} = "b-";
  235. endif
  236. endfor
  237. # poles and zeros last
  238. args{1,++kk} = real (olpol);
  239. args{2,kk} = imag (olpol);
  240. args{3,kk} = "rx;open loop poles;";
  241. if (! isempty (rlzer))
  242. args{1,++kk} = real (rlzer);
  243. args{2,kk} = imag (rlzer);
  244. args{3,kk} = "go;zeros;";
  245. endif
  246. set (gcf,"visible","off");
  247. hplt = plot (args{:});
  248. set (hplt(kk--), "markersize", 2);
  249. if (! isempty (rlzer))
  250. set (hplt(kk--), "markersize", 2);
  251. endif
  252. for ii = 1:rows(rlpol)
  253. set (hplt(kk--), "linewidth", 2);
  254. endfor
  255. legend ("boxon", 2);
  256. grid ("on");
  257. axis (axlim);
  258. xlabel (sprintf ("Root locus from %s to %s, gain=[%f,%f]: Real axis",
  259. inname{1}, outname{1}, gvec(1), gvec(ngain)));
  260. ylabel ("Imag. axis");
  261. set (gcf (), "visible","on");
  262. rldata = [];
  263. endif
  264. endfunction
  265. function rlpol = sort_roots (rlpol,tolx, toly)
  266. # no point sorting of you've only got one pole!
  267. if (rows (rlpol) == 1)
  268. return;
  269. endif
  270. # reorder entries in each column of rlpol to be by their nearest-neighbors
  271. dp = diff (rlpol')';
  272. drp = max (real (dp));
  273. dip = max (imag (dp));
  274. idx = find (drp > tolx | dip > toly);
  275. if (isempty (idx))
  276. return;
  277. endif
  278. [np, ng] = size (rlpol); # num poles, num gains
  279. for jj = idx
  280. vals = rlpol(:,[jj,jj+1]);
  281. jdx = (jj+1):ng;
  282. for ii = 1:rows(rlpol-1)
  283. rdx = ii:np;
  284. dval = abs (rlpol(rdx,jj+1)-rlpol(ii,jj));
  285. mindist = min (dval);
  286. sidx = min (find (dval == mindist)) + ii - 1;
  287. if (sidx != ii)
  288. c1 = norm (diff(vals'));
  289. [vals(ii,2), vals(sidx,2)] = swap (vals(ii,2), vals(sidx,2));
  290. c2 = norm (diff (vals'));
  291. if (c1 > c2)
  292. ## perform the swap
  293. [rlpol(ii,jdx), rlpol(sidx,jdx)] = swap (rlpol(ii,jdx), rlpol(sidx,jdx));
  294. vals = rlpol(:,[jj,jj+1]);
  295. endif
  296. endif
  297. endfor
  298. endfor
  299. endfunction