summaryrefslogtreecommitdiff
path: root/modules/cacsd/macros/nyquist.sci
diff options
context:
space:
mode:
Diffstat (limited to 'modules/cacsd/macros/nyquist.sci')
-rwxr-xr-xmodules/cacsd/macros/nyquist.sci275
1 files changed, 275 insertions, 0 deletions
diff --git a/modules/cacsd/macros/nyquist.sci b/modules/cacsd/macros/nyquist.sci
new file mode 100755
index 000000000..10fb2dda3
--- /dev/null
+++ b/modules/cacsd/macros/nyquist.sci
@@ -0,0 +1,275 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 1984-2011 - INRIA - Serge STEER
+// This file must be used under the terms of the CeCILL.
+// This source file is licensed as described in the file COPYING, which
+// you should have received as part of this distribution. The terms
+// are also available at
+// http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+
+function nyquist(varargin)
+ // Nyquist plot
+ //!
+ rhs=size(varargin);
+
+ if rhs == 0 then
+ //Hall chart as a grid for nyquist
+ s=poly(0,"s");
+ Plant=syslin("c",16000/((s+1)*(s+10)*(s+100)));
+ //two degree of freedom PID
+ tau=0.2;xsi=1.2;
+ PID=syslin("c",(1/(2*xsi*tau*s))*(1+2*xsi*tau*s+tau^2*s^2));
+ nyquist([Plant;Plant*PID],0.5,100,["Plant";"Plant and PID corrector"]);
+ hallchart(colors=color("light gray")*[1 1])
+ //move the caption in the lower rigth corner
+ ax=gca();Leg=ax.children(1);
+ Leg.legend_location="in_upper_left";
+ return;
+ end
+
+ symmetry=%t
+ if type(varargin(rhs))==4 then //symmetrization flag
+ symmetry=varargin(rhs)
+ rhs=rhs-1
+ end
+ if type(varargin(rhs))==10 then
+ comments=varargin(rhs);
+ rhs=rhs-1;
+ else
+ comments=[];
+ end
+ fname="nyquist";//for error messages
+ fmax=[];
+ if or(typeof(varargin(1))==["state-space" "rational"]) then
+ //sys,fmin,fmax [,pas] or sys,frq
+ refdim=1; //for error message
+ sltyp=varargin(1).dt;
+ if rhs==1 then
+ [frq,repf,splitf]=repfreq(varargin(1),1d-3,1d3);
+ elseif rhs==2 then //sys,frq
+ if size(varargin(2),2)<2 then
+ error(msprintf(_("%s: Wrong size for input argument #%d: A row vector with length>%d expected.\n"),fname,2,1))
+ end
+ [frq,repf]=repfreq(varargin(1:rhs));
+ elseif or(rhs==(3:4)) then //sys,fmin,fmax [,pas]
+ [frq,repf,splitf]=repfreq(varargin(1:rhs));
+ else
+ error(msprintf(_("%s: Wrong number of input arguments: %d to %d expected.\n"),fname,1,5))
+ end
+ elseif type(varargin(1))==1 then
+ //frq,db,phi [,comments] or frq, repf [,comments]
+ refdim=2;
+ sltyp="x";
+ splitf=[];
+ splitf=1;
+ select rhs
+ case 2 then //frq,repf
+ frq=varargin(1);
+ repf=varargin(2);
+ if size(frq,2)<2 then
+ error(msprintf(_("%s: Wrong size for input argument #%d: A row vector with length>%d expected.\n"),fname,1,1))
+ end
+ if size(frq,2)<>size(varargin(2),2) then
+ error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"),fname,1,2))
+ end
+
+ case 3 then //frq,db,phi
+ frq=varargin(1);
+ if size(frq,2)<>size(varargin(2),2) then
+ error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"),fname,1,2));
+ end
+ if size(frq,2)<>size(varargin(3),2) then
+ error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"),fname,1,3));
+ end
+ repf=exp(log(10)*varargin(2)/20 + %pi*%i/180*varargin(3));
+
+ else
+ error(msprintf(_("%s: Wrong number of input arguments: %d to %d expected.\n"),fname,2,4))
+ end
+ else
+ error(msprintf(_("%s: Wrong type for input argument #%d: Linear dynamical system or row vector of floats expected.\n"),fname,1));
+ end;
+ if size(frq,1)==1 then
+ ilf=0;
+ else
+ ilf=1;
+ end
+
+ [mn,n]=size(repf);
+ if and(size(comments,"*")<>[0 mn]) then
+ error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same number of elements expected.\n"),fname,refdim,rhs+1));
+ end
+ //
+
+ repi=imag(repf);
+ repf=real(repf);
+
+ // computing bounds of graphic window
+ mnx=min(-1,min(repf));// to make the critical point visible
+ mxx=max(-1,max(repf));
+
+ if symmetry then
+ mxy=max(0,max(abs(repi)));
+ mny=min(0,-mxy);
+ else
+ mxy=max(0,max(repi));
+ mny=min(0,min(repi));
+ end
+ dx=(mxx-mnx)/30;
+ dy=(mxy-mny)/30;
+ rect=[mnx-dx,mny-dy;mxx+dx,mxy+dy];
+
+ fig=gcf();
+ immediate_drawing=fig.immediate_drawing;
+ fig.immediate_drawing="off";
+
+ ax=gca();
+ if ax.children==[] then
+ ax.data_bounds=rect;
+ ax.axes_visible="on";
+ ax.grid=color("lightgrey")*ones(1,3)
+ ax.title.text=_("Nyquist plot");
+ if sltyp=="c" then
+ ax.x_label.text=_("Re(h(2iπf))");
+ ax.y_label.text=_("Im(h(2iπf))");
+ elseif sltyp=="x" then
+ ax.x_label.text=_("Re");
+ ax.y_label.text=_("Im");
+ else
+ ax.x_label.text=_("Re(h(exp(2iπf*dt)))");
+ ax.y_label.text=_("Im(h(exp(2iπf*dt)))");
+ end
+ else
+ rect= ax.data_bounds
+ mnx=rect(1,1);
+ mxx=rect(2,1)
+ mny=rect(1,2)
+ mxy=rect(2,2)
+ end
+
+ // drawing the curves
+ splitf($+1)=n+1;
+
+ ksplit=1;sel=splitf(ksplit):splitf(ksplit+1)-1;
+ R=[repf(:,sel)]; I=[repi(:,sel)];
+ F=frq(:,sel);
+ for ksplit=2:size(splitf,"*")-1
+ sel=splitf(ksplit):splitf(ksplit+1)-1;
+ R=[R %nan(ones(mn,1)) repf(:,sel)];
+ I=[I %nan(ones(mn,1)) repi(:,sel)];
+ F=[F %nan(ones(size(frq,1),1)) frq(:,sel)];
+ end
+ Curves=[]
+
+ kf=1
+ if symmetry then
+ for k=1:mn
+ xpoly([R(k,:) R(k,$:-1:1)],[I(k,:) -I(k,$:-1:1)]);
+ e=gce();e.foreground=k;
+ e.display_function = "formatNyquistTip";
+ e.display_function_data = [F(kf,:) -1*F(kf,$:-1:1)];
+ Curves=[Curves,e];
+ kf=kf+ilf;
+ end
+ else
+ for k=1:mn
+ xpoly(R(k,:),I(k,:));
+ e=gce();e.foreground=k;
+ e.display_function = "formatNyquistTip";
+ e.display_function_data = F(kf,:);
+ Curves=[Curves,e];
+ kf=kf+ilf;
+ end
+ end
+ clear R I
+
+ kk=1;p0=[repf(:,kk) repi(:,kk)];ks=1;d=0;
+ dx=rect(2,1)-rect(1,1);
+ dy=rect(2,2)-rect(1,2);
+ dx2=dx^2;
+ dy2=dy^2;
+
+ // collect significant frequencies along the curve
+ //-------------------------------------------------------
+ Ic=min(cumsum(sqrt((diff(repf,1,"c").^2)/dx2+ (diff(repi,1,"c").^2)/dy2),2),"r");
+ kk=1;
+ L=0;
+ DIc=0.2;
+ while %t
+ ksup=find(Ic-L>DIc);
+ if ksup==[] then break,end
+ kk1=min(ksup);
+ L=Ic(kk1);
+ Ic(1:kk1)=[];
+ kk=kk+kk1;
+
+ if min(abs(frq(:,ks($))-frq(:,kk))./abs(frq(:,kk)))>0.001 then
+ if min(sqrt(((repf(:,ks)-repf(:,kk)*ones(ks)).^2)/dx2+..
+ ((repi(:,ks)-repi(:,kk)*ones(ks)).^2)/dy2)) >DIc then
+ ks=[ks kk];
+ d=0;
+ end
+ end
+ end
+ if ks($)~=n then
+ if min(((repf(:,ks(1))-repf(:,n)).^2)/dx2+((repi(:,ks(1))-repi(:,n)).^2)/dy2)>0.01 then
+ ks=[ks n];
+ end
+ end
+ // display of parametrization (frequencies along the curve)
+ //-------------------------------------------------------
+ kf=1
+ if ks($)<size(repf,2) then last=$;else last=$-1;end
+ for k=1:mn,
+ L=[];
+ for kks=ks
+ xstring(repf(k,kks),repi(k,kks),msprintf("%-0.3g",frq(kf,kks)),0);
+ e=gce();e.font_foreground=k;
+ L=[e L];
+ if symmetry&(abs(repi(k,kks))>mxy/20) then //not to overlap labels
+ xstring(repf(k,kks),-repi(k,kks),msprintf("%-0.3g",-frq(kf,kks)),0);
+ e=gce();e.font_foreground=k;
+ L=[e L];
+ end
+ end
+ L=glue(L);
+ A=[];
+
+ if size(ks,"*")>1 then
+ dr=repf(k,ks(1:last)+1)-repf(k,ks(1:last));
+ di=repi(k,ks(1:last)+1)-repi(k,ks(1:last));
+ dd=1500*sqrt((dr/dx).^2+(di/dy).^2);
+ dr=dr./dd;
+ di=di./dd;
+ // we should use xarrows or xsegs here.
+ // However their displayed arrow size depends
+ // on the data bounds and we want to avoid this
+ if symmetry then
+ xx=[repf(k,ks(1:last)) repf(k,ks(last:-1:1))+dr($:-1:1) ;
+ repf(k,ks(1:last))+dr repf(k,ks(last:-1:1))]
+ yy=[repi(k,ks(1:last)) -repi(k,ks(last:-1:1))-di($:-1:1) ;
+ repi(k,ks(1:last))+di -repi(k,ks(last:-1:1))]
+ else
+ xx=[repf(k,ks(1:last)) ;
+ repf(k,ks(1:last))+dr]
+ yy=[repi(k,ks(1:last));
+ repi(k,ks(1:last))+di]
+ end
+ xpolys(xx,yy)
+ //xarrows([repf(k,ks(1:last));repf(k,ks(1:last))+dr],..
+ // [repi(k,ks(1:last));repi(k,ks(1:last))+di],1.5)
+ A=gce();
+ A.children.arrow_size_factor = 1.5;
+ A.children.polyline_style = 4;
+ A.children.foreground=k;
+ end
+
+ kf=kf+ilf;
+ glue([Curves(k) glue([L A])]);
+
+ end;
+
+ if comments<>[] then
+ legend(Curves, comments);
+ end
+ fig.immediate_drawing=immediate_drawing;
+endfunction