milanmetal

[MATLAB] nyquist1 / Poles & zeros on imaginary axis

Feb 23rd, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
MatLab 11.50 KB | None | 0 0
  1. function [reout,imt,w] = nyquist1(a,b,c,d,iu,w)
  2. %NYQUIST1 Nyquist frequency response for continuous-time linear systems.
  3. %
  4. %       This Version of the  NYQUIST Command takes into account poles at the
  5. %       jw-axis and loops around them when creating the frequency vector  in order
  6. %       to produce the appropriate Nyquist Diagram (The NYQUIST command does
  7. %       not do this and therefore produces an incorrect plot when we have poles in the
  8. %       jw axis).  
  9. %
  10. %       NOTE: This version of NYQUIST1 does not account for pole-zero
  11. %       cancellation.  Therefore, the user must simplify the transfer function before using
  12. %       this command.
  13. %
  14. %       NYQUIST(A,B,C,D,IU) produces a Nyquist plot from the single input
  15. %       IU to all the outputs of the system:            
  16. %               .                                    -1
  17. %               x = Ax + Bu             G(s) = C(sI-A) B + D  
  18. %               y = Cx + Du      RE(w) = real(G(jw)), IM(w) = imag(G(jw))
  19. %
  20. %       The frequency range and number of points are chosen automatically.
  21. %
  22. %       NYQUIST1(NUM,DEN) produces the Nyquist plot for the polynomial
  23. %       transfer function G(s) = NUM(s)/DEN(s) where NUM and DEN contain
  24. %       the polynomial coefficients in descending powers of s.
  25. %
  26. %       NYQUIST1(A,B,C,D,IU,W) or NYQUIST(NUM,DEN,W) uses the user-supplied
  27. %       freq. vector W which must contain the frequencies, in radians/sec,
  28. %       at which the Nyquist response is to be evaluated.  When invoked
  29. %       with left hand arguments,
  30. %               [RE,IM,W] = NYQUIST(A,B,C,D,...)
  31. %               [RE,IM,W] = NYQUIST(NUM,DEN,...)
  32. %       returns the frequency vector W and matrices RE and IM with as many
  33. %       columns as outputs and length(W) rows.  No plot is drawn on the
  34. %       screen.
  35. %       See also: LOGSPACE,MARGIN,BODE, and NICHOLS.
  36.  
  37. %       J.N. Little 10-11-85
  38. %       Revised ACWG 8-15-89, CMT 7-9-90, ACWG 2-12-91, 6-21-92,
  39. %               AFP 2-23-93
  40. %               WCM 8-31-97
  41. %
  42. %  ********************************************************************
  43. %  Modifications made to the nyquist - takes into account poles on jw axis.
  44. %  then goes around these to make up frequency vector
  45. %  
  46.  
  47.  
  48. if nargin==0, eval('exresp(''nyquist'')'), return, end
  49.  
  50. % --- Determine which syntax is being used ---
  51. nargin1 = nargin;
  52. nargout1 = nargout;
  53. if (nargin1==1),    % System form without frequency vector
  54.         [num,den]=tfdata(a,'v');
  55.         z = roots(num);
  56.         p = roots(den);
  57.         zp = [z;p];
  58.         wpos = zp(find(abs(zp)>0));
  59.         if(min(abs(p)) == 0)
  60.             wstart = max(eps, 0.03*min([1;wpos]));
  61.         else
  62.             wstart = max(eps, 0.03*min(abs(zp)));
  63.         end
  64.         wstop = max([1000;30*wpos]);
  65.         w = logspace(log10(wstart),log10(wstop),max(51,10*max(size(zp))+1));
  66.  
  67.         %w = freqint2(num,den,30);
  68.         [ny,nn] = size(num); nu = 1;
  69.         %error('Wrong number of input arguments.');
  70.  
  71. elseif (nargin1==2),    
  72.         if(isa(a,'ss')|isa(a,'tf')|isa(a,'zpk')) % System with frequency vector
  73.             [num,den]=tfdata(a,'v');
  74.             w = b;
  75.         else    % Transfer function form without frequency vector
  76.             num  = a; den = b;
  77.             z = roots(num);
  78.             p = roots(den);
  79.             zp = [z;p];
  80.             wpos = zp(find(abs(zp)>0));
  81.             if(min(abs(p)) == 0)
  82.             wstart = max(eps, 0.03*min([1;wpos]));
  83.         else
  84.             wstart = max(eps, 0.03*min(abs(zp)));
  85.         end
  86.             wstop = max([1000;30*wpos]);
  87.             w = logspace(log10(wstart),log10(wstop),max(51,10*max(size(zp))+1));
  88.             %w = freqint2(num,den,30);
  89.         end
  90.         [ny,nn] = size(num); nu = 1;
  91.  
  92. elseif (nargin1==3),     % Transfer function form with frequency vector
  93.         num = a; den = b;
  94.         w = c;
  95.         [ny,nn] = size(num); nu = 1;
  96.  
  97. elseif (nargin1==4),     % State space system, w/o iu or frequency vector
  98.         error(abcdchk(a,b,c,d));
  99.             [num,den] = ss2tf(a,b,c,d);
  100.             [z,p,k]= ss2zp(a,b,c,d);
  101.             [num,den] = zp2tf(z,p,k);
  102.             zp = [z;p];
  103.             wpos = zp(find(abs(zp)>0));
  104.             if(min(abs(p)) == 0)
  105.             wstart = max(eps, 0.03*min([1;wpos]));
  106.         else
  107.             wstart = max(eps, 0.03*min(abs(zp)));
  108.         end
  109.             wstop = max([1000;30*wpos]);
  110.             w = logspace(log10(wstart),log10(wstop),max(51,10*max(size(zp))+1));
  111.             %w = freqint2(a,b,c,d,30);
  112.         nargin1 = 2;%[iu,nargin,re,im]=mulresp('nyquist',a,b,c,d,w,nargout1,0);
  113.         %if ~iu, if nargout, reout = re; end, return, end
  114.         [ny,nu] = size(d);
  115.  
  116. elseif (nargin1==5),     % State space system, with iu but w/o freq. vector
  117.         error(abcdchk(a,b,c,d));
  118.         z = tzero(a,b,c,d);
  119.         p = eig(a);
  120.         zp = [z;p];
  121.         wpos = zp(find(abs(zp)>0));
  122.         if(min(abs(p)) == 0)
  123.             wstart = max(eps, 0.03*min([1;wpos]));
  124.         else
  125.             wstart = max(eps, 0.03*min(abs(zp)));
  126.         end
  127.         wstop = max([1000;30*wpos]);
  128.         w = logspace(log10(wstart),log10(wstop),max(51,10*max(size(zp))+1));
  129.         %w = freqint2(a,b,c,d,30);
  130.         [ny,nu] = size(d);
  131.  
  132. else
  133.         error(abcdchk(a,b,c,d));
  134.         [ny,nu] = size(d);
  135.  
  136. end
  137.  
  138. if nu*ny==0, im=[]; w=[]; if nargout~=0, reout=[]; end, return, end
  139.  
  140. % *********************************************************************
  141. % depart from the regular nyquist program here
  142. % now we have a frequency vector, a numerator and denominator
  143. % now we create code to go around all poles and zeroes here.
  144.  
  145. if (nargin1==5) | (nargin1 ==4) | (nargin1 == 6)
  146.         [num,den]=ss2tf(a,b,c,d);
  147. end
  148. tol = 1e-6;  %defined tolerance for finding imaginary poles
  149. z = roots(num);
  150. p = roots(den);
  151. % ***** If all of the poles are at the origin, just move them a tad to the left***
  152. if norm(p) == 0
  153.  if(isempty(z))
  154.   tad = 1e-1;
  155.  else
  156.     tad = min([1e-1; 0.1*abs(z)]);
  157. end
  158.  
  159.  
  160.  length_p = length(p);
  161.  p = -tad*ones(length_p,1);
  162.  den = den(1,1)*[1  tad];
  163.  for ii = 2:length_p
  164.   den = conv(den,[1  tad]);
  165. end
  166.  
  167.     zp = [z;p];
  168.     wpos = zp(find(abs(zp)>0));
  169.     if(min(abs(p)) == 0)
  170.             wstart = max(eps, 0.03*min([1;wpos]));
  171.         else
  172.             wstart = max(eps, 0.03*min(abs(zp)));
  173.         end
  174.     wstop = max([1000;30*wpos]);
  175.     w = logspace(log10(wstart),log10(wstop),max(51,10*max(size(zp))+1));
  176.  %w = freqint2(num,den,30);
  177. end
  178.  
  179. zp = [z;p];        % combine the zeros and poles of the system
  180. nzp = length(zp);  % number of zeros and poles
  181. ones_zp=ones(nzp,1);
  182.  
  183. Ipo = find((abs(real(p))< tol) & (imag(p)>=0)); %index poles with zero real part + non-neg imag part
  184. if  ~isempty(Ipo)   %
  185. % **** only if we have such poles do we do the following:*************************
  186. po = p(Ipo); % poles with 0 real part and non-negative imag part
  187. % check for distinct poles
  188. [y,ipo] = sort(imag(po));  % sort imaginary parts
  189. po = po(ipo);
  190. dpo = diff(po);
  191. idpo = find(abs(dpo)> tol);
  192. idpo = [1;idpo+1];   % indexes of the distinct poles
  193.  
  194. po = po(idpo);   % only distinct poles are used
  195. nIpo = length(idpo); % # of such poles
  196. originflag = find(imag(po)==0);  % locate origin pole
  197.  
  198. s = [];  % s is our frequency response vector
  199. w = sqrt(-1)*w;  % create a jwo vector to evaluate all frequencies with
  200. for ii=1:nIpo % for all Ipo poles
  201.        
  202.         [nrows,ncolumns]=size(w);
  203.         if nrows == 1
  204.                 w = w.';  % if w is a row, make it a column
  205.         end;
  206.         if nIpo == 1
  207.                 r(ii) = .1;
  208.         else            % check distances to other poles and zeroes
  209.                 pdiff = zp-po(ii)*ones_zp;  % find the differences between
  210.                 % poles you are checking and other poles and zeros
  211.                 ipdiff = find(abs(pdiff)> tol); % ipdiff is all nonzero differences
  212.                
  213.                 r(ii)=0.2*min(abs(pdiff(ipdiff))); % take half this difference
  214.                 r(ii)=min(r(ii),0.1);  % take the minimum of this diff.and .1
  215.         end;
  216.         t = linspace(-pi/2,pi/2,25);
  217.         if (ii == originflag)
  218.                 t = linspace(0,pi/2,25);
  219.         end;    % gives us a vector of points around each Ipo  
  220.         s1 = po(ii)+r(ii)*(cos(t)+sqrt(-1)*sin(t));  % detour here
  221.         s1 = s1.';  % make sure it is a column
  222.  
  223.         % Now here I reconstitute s - complex frequency - and
  224.         % evaluate again.  
  225.  
  226.         bottomvalue = po(ii)-sqrt(-1)*r(ii);  % take magnitude of imag part
  227.         if (ii ==  originflag)  % if this is an origin point
  228.                 bottomvalue = 0;
  229.         end;
  230.         topvalue = po(ii)+sqrt(-1)*r(ii); % the top value where detour stops
  231.         nbegin = find(imag(w) < imag(bottomvalue)); %
  232.         nnbegin = length(nbegin); % find all the points less than encirclement
  233.         if (nnbegin == 0)& (ii ~= originflag)    % around jw root
  234.                 sbegin = 0;
  235.         else sbegin = w(nbegin);
  236.         end;
  237.         nend = find(imag(w) > imag(topvalue));  % find all points greater than
  238.         nnend = length(nend);    % encirclement around jw root
  239.         if (nnend == 0)
  240.                 send = 0;        
  241.         else send = w(nend);
  242.         end
  243.         w = [sbegin; s1; send];  % reconstituted half of jw axis
  244. end
  245. else
  246.         w = sqrt(-1)*w;
  247. end
  248. %end  % this ends the loop for imaginary axis poles
  249. % *************************************************************
  250. % back to the regular nyquist program here
  251. % Compute frequency response
  252. if (nargin1==1)|(nargin1==2)|(nargin1==3)
  253.         gt = freqresp(num,den,w);
  254. else
  255.         gt = freqresp(a,b,c,d,iu,w);
  256. end
  257. % ***********************************************************
  258.  
  259. %        nw = length(gt);
  260. %        mag = abs(gt);   % scaling factor added
  261. %        ang = angle(gt);
  262. %        mag = log2(mag+1);    % scale by log2(mag) throughout
  263.        
  264. %        for n = 1:nw
  265. %                h(n,1) = mag(n,1)*(cos(ang(n,1))+sqrt(-1)*sin(ang(n,1)));
  266. %        end;  % recalculate G(jw) with scaling factor
  267.        
  268. %        gt = h;
  269. % ***********************************************************
  270. ret=real(gt);
  271. imt=imag(gt);
  272.  
  273. % If no left hand arguments then plot graph.
  274. if nargout==0,
  275.    status = ishold;
  276.    plot(ret,imt,'r-',ret,-imt,'g--')  
  277.  
  278. %  plot(real(w),imag(w))        
  279.  
  280.  
  281.    set(gca, 'YLimMode', 'auto')
  282.    limits = axis;
  283.    % Set axis hold on because next plot command may rescale
  284.    set(gca, 'YLimMode', 'auto')
  285.    set(gca, 'XLimMode', 'manual')
  286.    hold on
  287.    % Make arrows
  288.    for k=1:size(gt,2),
  289.         g = gt(:,k);
  290.         re = ret(:,k);
  291.         im = imt(:,k);
  292.         sx = limits(2) - limits(1);
  293.         [sy,sample]=max(abs(2*im));
  294.         arrow=[-1;0;-1] + 0.75*sqrt(-1)*[1;0;-1];
  295.         sample=sample+(sample==1);
  296.         reim=diag(g(sample,:));
  297.         d=diag(g(sample+1,:)-g(sample-1,:));
  298.         % Rotate arrow taking into account scaling factors sx and sy
  299.         d = real(d)*sy + sqrt(-1)*imag(d)*sx;
  300.         rot=d./abs(d);          % Use this when arrow is not horizontal
  301.         arrow = ones(3,1)*rot'.*arrow;
  302.         scalex = (max(real(arrow)) - min(real(arrow)))*sx/50;
  303.         scaley = (max(imag(arrow)) - min(imag(arrow)))*sy/50;
  304.         arrow = real(arrow)*scalex + sqrt(-1)*imag(arrow)*scaley;
  305.         xy =ones(3,1)*reim' + arrow;
  306.         xy2=ones(3,1)*reim' - arrow;
  307.         [m,n]=size(g);
  308.         hold on
  309.         plot(real(xy),-imag(xy),'r-',real(xy2),imag(xy2),'g-')
  310.    end
  311.    xlabel('Real Axis'), ylabel('Imag Axis')
  312.  
  313.    limits = axis;
  314.    % Make cross at s = -1 + j0, i.e the -1 point
  315.    if limits(2) >= -1.5  & limits(1) <= -0.5 % Only plot if -1 point is not far out.
  316.         line1 = (limits(2)-limits(1))/50;
  317.         line2 = (limits(4)-limits(3))/50;
  318.         plot([-1+line1, -1-line1], [0,0], 'w-', [-1, -1], [line2, -line2], 'w-')
  319.    end
  320.  
  321.    % Axis
  322.    plot([limits(1:2);0,0]',[0,0;limits(3:4)]','w:');
  323.    plot(-1,0,'+k');
  324.    
  325.    if ~status, hold off, end    % Return hold to previous status
  326.    return % Suppress output
  327. end
  328. %reout = ret;
  329. %   plot(real(p),imag(p),'x',real(z),imag(z),'o');
Add Comment
Please, Sign In to add comment