home *** CD-ROM | disk | FTP | other *** search
- function [rout,k] = rlocus(a,b,c,d,e,f)
- %RLOCUS Evans root locus.
- % RLOCUS(NUM,DEN) calculates and plots the locus of the roots of:
- % NUM(s)
- % H(s) = 1 + k ---------- = 0
- % DEN(s)
- % for a set of gains K which are adaptively calculated to produce a
- % smooth plot. Alternatively the vector K can be specified with an
- % optional right-hand argument RLOCUS(NUM,DEN,K). Vectors NUM and
- % DEN must contain the numerator and denominator coefficients in
- % descending powers of s or z. When invoked with left hand arguments
- % R = RLOCUS(NUM,DEN,K) or [R,K] = RLOCUS(NUM,DEN)
- % returns the matrix R with LENGTH(K) rows and (LENGTH(DEN(-1)
- % columns containing the complex root locations. Each row of the
- % matrix corresponds to a gain from vector K. If a second left hand
- % argument is included, the gains are returned in K.
- %
- % RLOCUS(A,B,C,D), R = RLOCUS(A,B,C,D,K), or [R,K] = RLOCUS(A,B,C,D)
- % finds the root-locus from the equivalent SISO state-space system
- % (A,B,C,D).
- % dx/dt = Ax + Bu u = -k*y
- % y = Cx + Du
- %
- % See also: PZMAP and RLOCFIND.
-
- % J.N. Little 10-11-85
- % Revised A.C.W.Grace 7-8-89, 6-21-92
- % Copyright (c) 1986-93 by the MathWorks, Inc.
-
- if nargin==0, eval('exresp(''rlocus'');'), return, end
-
- error(nargchk(2,6,nargin));
-
- % The next variable controls how many points are plotted on the graph.
- precision = 1; %Set to a higher number (e.g. 2 for more points on the graph).
- k=[];
-
- if (nargin==3 | nargin==2 ) % Convert to state space
- if nargin==3, k = c; end
- [num,den] = tfchk(a,b);
- [a,b,c,d] = tf2ss(a,b);
- end
-
- [ny,nu] = size(d);
- if (ny*nu==0)|isempty(a), k=[]; if nargout~=0, rout=[]; end, return, end
-
- % Multivariable systems
- error(abcdchk(a,b,c,d));
- if nargin==5,
- k=e;
- elseif nargin==6,
- b=b(:,e); d=d(:,e); k = f;
- end
-
- % Trap MIMO case
- [ny,nu] = size(d);
- if ny*nu~=1,
- if nargout~=0,
- disp('Warning: Root locus with outputs must be SISO.'),
- return,
- end
- [e,nargin,r]=mulresp('rlocus',a,b,c,d,k,0,0);
- if ~e, if nargout, rout = r; end, return, end
- end
-
- sp=sum([1:length(a)].^2);
-
- % Set up graphics and other parameters.
-
- if isempty(k) | nargout==0
- % Work out scales and ranges
- kgiven = 0;
- ep=eig(a);
- p=length(ep);
- if nargin>=4
- tz=tzero(a,b,c,d);
- z=length(tz);
- sp2=[1:z].^2;
- den=poly(ep);
- num=poly(tz);
- else
- tz=roots(num);
- z=length(tz);
- end
- den2 = den + 1e-20*(den==0);
- dcgain=num(length(num))/den2(length(den));
- % Normalize for better numerical properties
- if abs(den(1)) > eps & den(1) ~= 1
- den=den/den(1);
- num=num/den(1);
- end
- mep=max([eps;abs([real(ep);real(tz);imag(ep);imag(tz)])]);
- if z==p
- % Round up axis to units to the nearest 5
- ax=1.2*mep;
- else
- % Round graph axis
- exponent=5*10^(floor(log10(mep))-1);
- ax=2*round(mep/exponent)*exponent;
- end
- if nargout==0
- % Real and imaginary axis - uncomment these if you don't want them
- axstate = axis('state');
- holdon = ishold;
- newplot;
- if ~holdon
- plot([-ax,ax],[0,0],'w:',[0,0],[-ax,ax],'w:');
- axis([-ax,ax,-ax,ax])
- else
- ax4 = axis;
- ax = sum(abs(ax4))/4;
- plot([ax4(1:2)],[0,0],'w:',[0,0],[ax4(3:4)],'w:');
- axis(ax4)
- end
- % If plotting is required then set up axis and titles
- hold on
- plot(real(ep),imag(ep),'x');
- if ~isempty(tz)
- plot(real(tz),imag(tz),'o');
- end
- xlabel('Real Axis')
- ylabel('Imag Axis')
- % Use none as Erasemode for fast plotting
- erasemode = 'none';
- drawnow
- end
- end
-
- % Adaptively search for values of gain if K is not specified
-
- if isempty(k)
- % Set up initial gain based on D.C.Gain of open loop and
- % positions of zeros and poles.
- % Since closed loop den = num + k*den, sensitivity is related
- % to difference between num and denominator coefficients.
- diff=abs(num)./abs(den2(1:length(num)));
- kinit=0.01/(abs(dcgain) + polyval(diff,4))+1e-12;
- bc=b*c;
- k=[0,1e-4*kinit,kinit]; dist=kinit;
- r(:,1)=ep;
- r(:,2)=vsort(ep, eig(a-bc*(k(2)./(1+k(2)*d))), sp);
- if nargout==0, plot( real([ep,r(:,2)])', imag([ep,r(:,2)])','-' ,'Erasemode', erasemode), end
- i=2; ij=sqrt(-1); perr=1;
- terminate=0;
- while ~terminate
- i=i+1;
- ki=k(i)./(1+k(i)*d);
- r1=eig(a-bc*ki);
- mx=max(abs([real(r1).';imag(r1).']));
- % If any line outside box then set erasemode back to normal
- % for clipping
- if any(mx > ax), erasemode = 'normal'; end
- % Sort out eigenvalues so that plotting appears continuous.
- [r(:,i),pind]=vsort(r(:,i-1),r1,sp);
- % Adjust values of k based on linearity of the roots:
- % First two points in line
- y1=imag(r(:,i-2)); y2=imag(r(:,i-1));
- x1=real(r(:,i-2)); x2=real(r(:,i-1));
- % Current points
- y=imag(r(:,i)); x=real(r(:,i));
- % Nearest x-y co-ordinates of new point to line
- [newx,newy]=perpxy(x1,y1,x2,y2,x,y);
- % Error estimation
- err=sqrt((newy-y).^2+(newx-x).^2);
- distm=norm((y-y2)+ij*(x-x2));
- fferr=find(~finite(err));
- err(fferr)=zeros(length(fferr),1);
- perr=precision*max(err(find(finite(err))))/(distm+ax/(1e3*(distm+eps)));
-
- % If percentage error greater than threshold then go back and
- % re-evaluate more roots:
- pind = any((y==0)~=(y2==0));
- if perr>0.2 | pind
- % Decrement distance between gains
- npts=3+5*round(min([5,perr*3]))+17*pind;
- kval=logspace(log10(k(i-1)),log10(k(i)),npts);
- dist=(k(i)-k(i-1))/(npts-7*pind);
- i=i-1;
- for kcnt=kval(2:npts)
- i=i+1;
- k(i)=kcnt;
- ki=kcnt./(1+kcnt*d);
- r1=eig(a-bc*ki);
- r(:,i) = vsort(r(:,i-1),r1,sp);
- y=imag(r(:,i)); y2=imag(r(:,i-1));
- x=real(r(:,i)); x2=real(r(:,i-1));
- ind = 0;
- if nargout==0
- % Intersection of rlocus on the real axis.
- if pind
- % The inequality abs(y+y2)<ax makes sure that its not one that
- % goes off to inf and then
- % comes back on the real axis.
- ind = find((y==0)~=(y2==0) & abs(y+y2)<ax);
- if ~isempty(ind)
- if (imag(r(ind(1),i))==0), cix = 1; else, cix = 0; end
- realr = r(:,i-cix);
- realr(ind)=real(r(ind,i-cix));
- plot( real([realr,r(:,i-1)])', imag([realr,r(:,i-1)])','-','Erasemode',erasemode)
- plot( real([r(:,i),realr])', imag([r(:,i),realr])','-' ,'Erasemode',erasemode)
- else
- ind=0;
- end
- end
- if ~ind
- % Fix for plot when rlocus goes from -inf to inf or -inf to inf
- infind = find(abs(x)>ax & sign(x2)~=sign(x));
- if length(infind)>0
- x(infind) = sign(x2(infind))*ax;
- end
- plot([x,x2]',[y,y2]','-','Erasemode',erasemode)
- end
-
- end
- end
- else
- % Fix for plot when rlocus goes comes from -inf to inf or -inf to inf
- infind = find(abs(x)>ax & sign(x2)~=sign(x) );
- if length(infind)>0
- x(infind) = sign(x2(infind))*ax;
- end
- % Use none as Erasemode for fast plotting
- if nargout==0, plot([x,x2]',[y,y2]','-','Erasemode',erasemode), end
- % Increase/decrease distance to next k based on linearity estimate:
- dist=dist*(0.3/precision+exp(1-15*perr));
- end
- % Next gain value
- k(i+1)=k(i)+dist;
- % Termination criterion
- terminate=1;
- if z==p
- tz = vsort(r1, tz);
- terminate=max(abs(tz-r1))<ax/100;
- else
- % Make sure all loci tending to infinity are out of graph before terminating
- % Terminate when all poles have approached their corresponding zeros
- % Note: this may not work well if zeros are close together
- if z > 0
- terminate=max(min(abs(r1*ones(1,z)-ones(p,1)*tz.')))<ax/100;
- end
- mx=max(abs([real(r1).';imag(r1).']));
- terminate = ( sum(mx>1.2*ax)>=p-z & terminate );
- end
- terminate = terminate | abs(k(i)) > 1e30;
- if nargout == 0
- if rem(i,10) == 0 % Draw graph every ten iterations
- drawnow
- end
- end
- end
-
- else
- % When K is given:
- kgiven = 1;
- [ns,nu] = size(b);
- nk = length(k); i=1;
- r = sqrt(-1) * ones(ns,nk);
- bc = b*c;
- % Find eigenvalues of: A - B*inv(I+k*D)*k*C:
- k2 = k./(1+k.*d);
- r(:,1)=eig(a-bc*k2(1)); k2(1)=[];
- if nk == 1 & nargout == 0
- % Special case when only one point
- plot(real(r(:,1))', imag(r(:,1)), '+');
- end
- for ki=k2
- i = i + 1;
- r1 = eig(a-bc*ki);
- % Sort eigenvalues
- r(:,i)=vsort(r(:,i-1),r1,sp);
- if nargout==0
- % Plot in pairs to get colored crosses
- plot( real([r(:,i),r(:,i-1)])', imag([r(:,i),r(:,i-1)])','+','Erasemode','none')
- end
- end
- end
- r = r.';
-
- if nargout==0,
- % Uncomment the next line to obtain grid on plot
- %grid
- % Return graphics to original state
- if ~holdon, hold off, end
- % axis(axstate);
- return % Suppress output
- end
-
- rout = r;
- % Last element of k is never used
- if ~kgiven
- k(length(k))=[];
- k = k.';
- end
-