init
This commit is contained in:
commit
d5a822831c
|
@ -0,0 +1,28 @@
|
|||
* text=auto
|
||||
|
||||
*.fig binary
|
||||
*.mat binary
|
||||
*.mdl binary diff merge=mlAutoMerge
|
||||
*.mdlp binary
|
||||
*.mex* binary
|
||||
*.mlapp binary
|
||||
*.mldatx binary
|
||||
*.mlproj binary
|
||||
*.mlx binary
|
||||
*.p binary
|
||||
*.sfx binary
|
||||
*.sldd binary
|
||||
*.slreqx binary merge=mlAutoMerge
|
||||
*.slmx binary merge=mlAutoMerge
|
||||
*.sltx binary
|
||||
*.slxc binary
|
||||
*.slx binary merge=mlAutoMerge
|
||||
*.slxp binary
|
||||
|
||||
## Other common binary file types
|
||||
*.docx binary
|
||||
*.exe binary
|
||||
*.jpg binary
|
||||
*.pdf binary
|
||||
*.png binary
|
||||
*.xlsx binary
|
|
@ -0,0 +1,33 @@
|
|||
# Autosave files
|
||||
*.asv
|
||||
*.m~
|
||||
*.autosave
|
||||
*.slx.r*
|
||||
*.mdl.r*
|
||||
|
||||
# Derived content-obscured files
|
||||
*.p
|
||||
|
||||
# Compiled MEX files
|
||||
*.mex*
|
||||
|
||||
# Packaged app and toolbox files
|
||||
*.mlappinstall
|
||||
*.mltbx
|
||||
|
||||
# Deployable archives
|
||||
*.ctf
|
||||
|
||||
# Generated helpsearch folders
|
||||
helpsearch*/
|
||||
|
||||
# Code generation folders
|
||||
slprj/
|
||||
sccprj/
|
||||
codegen/
|
||||
|
||||
# Cache files
|
||||
*.slxc
|
||||
|
||||
# Cloud based storage dotfile
|
||||
.MATLABDriveTag
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,16 @@
|
|||
function H=bode(G,varargin)
|
||||
% bode - draw Bode diagram for an FOSS object
|
||||
%
|
||||
% bode(G,w)
|
||||
% H=bode(G,w)
|
||||
%
|
||||
% G - the FOSS object
|
||||
% w - the frequency vector
|
||||
% H - the frequency response data in FRD format
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, bode(fotf(G),varargin{:});
|
||||
else, H=bode(fotf(G),varargin{:}); end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
function G1=coss_aug(G,k)
|
||||
% coss_aug - state augmentation of an FOSS object
|
||||
%
|
||||
% G1=coss_aug(G,k)
|
||||
%
|
||||
% G - the FOSS object
|
||||
% k - integer so that original n states can be augmented into n*k states
|
||||
% G1 - the augmented FOSS model
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if G.alpha==0 || k==1, G1=G;
|
||||
else, alpha=G.alpha/k; G=fotf(G); [n,m]=size(G);
|
||||
for i=1:n, for j=1:m, g=G(i,j);
|
||||
a=g.den.a; na=g.den.na; b=g.num.a; nb=g.num.na;
|
||||
ii=1:k:k*length(a); a1(ii)=a;
|
||||
ii=1:k:k*length(b); b1(ii)=b; G2(i,j)=tf(b1,a1);
|
||||
end, end
|
||||
G1=foss(ss(G2)); G1.alpha=alpha;
|
||||
end, end
|
|
@ -0,0 +1,13 @@
|
|||
function Tc=ctrb(G)
|
||||
% ctrb - create a controllability test matrix for an FOSS
|
||||
%
|
||||
% Tc=ctrb(G)
|
||||
%
|
||||
% G - the FOSS object
|
||||
% Tc - the controllability test matrix
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
Tc=ctrb(G.a,G.b);
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function disp(G)
|
||||
% display - display an FOSS. This function will be called automatically
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
disp('E*(d^alpha*X)(t)=A*X(t)+B*U(t-T)'), T=G.ioDelay;
|
||||
disp('Y(t)=C*X(t)+D*U(t-T)'); ss(G.a,G.b,G.c,G.d)
|
||||
if ~isempty(G.E), disp('Descriptor matrix'), E=G.E, end
|
||||
if sum(T(:)), disp(['Time Delay is = ' mat2str(T)]); end
|
||||
disp(['alpha = ',num2str(G.alpha)]);
|
||||
if ~isempty(G.x0), x0=G.x0;
|
||||
disp(['Initil state vector x0 = [' num2str(x0(:).'),']'])
|
||||
end, end
|
|
@ -0,0 +1,13 @@
|
|||
function p=eig(G)
|
||||
% eig - finding all the pseudo poles of an FOSS object
|
||||
%
|
||||
% p=eig(G)
|
||||
%
|
||||
% G - the FOSS object
|
||||
% p - all the pseudo-poles of G
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
p=eig(G.a)
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function key=eq(G1,G2)
|
||||
% eq - test whether two FOSS objects are equal or not
|
||||
%
|
||||
% key=G1==G2
|
||||
%
|
||||
% G1, G2 - the two FOSS objects
|
||||
% key = 1 for equal, otherwise key = 0
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
key=fotf(G1)==fotf(G2);
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
function G=feedback(G1,G2)
|
||||
% feedback - find the overall model of two FOSS objects in feedback connection
|
||||
%
|
||||
% G=feedback(G1,G2)
|
||||
%
|
||||
% G1, G2 - the FOSS objects in the forward and backward paths
|
||||
% G - the overall model of the closed-loop system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=foss(G1); G2=foss(G2);
|
||||
if length(G1.alpha)>1 || length(G2.alpha)>1, a=0.0001;
|
||||
else, a=common_order(G1.alpha,G2.alpha); end
|
||||
if a==0
|
||||
G=foss([],[],[],G1.d*inv(eye(size(G1.d))+G2.d*G1.d),0);
|
||||
elseif a<0.001
|
||||
G1=fotf(G1); G2=fotf(G2); G=foss(feedback(G1,G2));
|
||||
else
|
||||
G1=coss_aug(G1,round(G1.alpha/a));
|
||||
G2=coss_aug(G2,round(G2.alpha/a));
|
||||
G=foss(feedback(ss_extract(G1),ss_extract(G2))); G.alpha=a;
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
% foss - class constructor for an FOSS class
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
classdef foss
|
||||
properties, a, b, c, d, alpha, ioDelay, E, x0, end
|
||||
methods
|
||||
function G=foss(a,b,c,d,alpha,L,E,x0)
|
||||
if nargin<=7, x0=[]; end
|
||||
if nargin<=6, E=[]; end, if nargin<=5, L=0; end
|
||||
if nargin==1 && isa(a,'foss'), G=a;
|
||||
elseif nargin==1 && isa(a,'fotf'), G=fotf2foss(a);
|
||||
elseif nargin==1 && isa(a,'double'), G=foss([],[],[],a,0);
|
||||
elseif (nargin==1||nargin==2) && (isa(a,'tf')||isa(a,'ss'))
|
||||
alpha=1; if nargin==2, alpha=b; end
|
||||
a=ss(a); L=a.ioDelay; [a,b,c,d,E]=dssdata(a);
|
||||
G=foss(a,b,c,d,alpha,L,E);
|
||||
elseif nargin>=5, msg=abcdchk(a,b,c,d);
|
||||
if length(msg)>0, error(msg)
|
||||
else, G.alpha=alpha; G.x0=x0;
|
||||
G.a=a; G.b=b; G.c=c; G.d=d; G.E=E; G.ioDelay=L;
|
||||
end
|
||||
else, error('wrong input arguments'); end
|
||||
end, end, end
|
|
@ -0,0 +1,24 @@
|
|||
function G1=foss2fotf(G)
|
||||
% foss2fotf - convert an FOSS object to FOTF one
|
||||
%
|
||||
% G1=foss2fotf(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% G1 - an equivalent FOTF object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); G1=fotf(zeros(n,m));
|
||||
G0=ss_extract(G); G0=tf(G0); key=length(G.alpha)>1;
|
||||
T=G.ioDelay; if isscalar(T), T=T*ones(n,m); end
|
||||
if key~=0
|
||||
n0=G.alpha; n1=n0(end:-1:1); n2=0;
|
||||
for i=1:length(n1), n2(i+1)=n2(i)+n1(i); end
|
||||
n2=n2(end:-1:1);
|
||||
end
|
||||
for i=1:n, for j=1:m, g=G0(i,j);
|
||||
[num,den]=tfdata(g,'v');
|
||||
if key==0, n2=((length(den)-1):-1:0)*G.alpha; end
|
||||
h=fotf(den,n2,num,n2,T(i,j)); h=simplify(h); G1(i,j)=h;
|
||||
end, end, end
|
|
@ -0,0 +1,15 @@
|
|||
function Y=impulse(G,varargin)
|
||||
% impulse - impulse response evaluation of an FOSS object
|
||||
%
|
||||
% impulse(G,t)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% t - the time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, impulse(fotf(G),varargin{:});
|
||||
else, Y=impulse(fotf(G),varargin{:});
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function G1=inv(G)
|
||||
% inv - inverse of a multivariable FOSS system
|
||||
%
|
||||
% G1=inv(G)
|
||||
%
|
||||
% G, G1 - an FOSS object and its inverse system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
H=inv(ss_extract(G)); G1=foss(H); G1.alpha=G.alpha;
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function key=isfoss(G)
|
||||
% isfoss - check whether input is an FOSS object
|
||||
%
|
||||
% key=isfoss(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
key=strcmp(class(G),'foss');
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
function [K,alpha,apol]=isstable(G)
|
||||
% isstable - check whether an FOSS object is stable or not
|
||||
%
|
||||
% [K,alpha,apol]=isstable(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% K- identifier to indicate the stability of G, returns 0, and 1
|
||||
% alpha - the common order
|
||||
% apol - all the pseudo poles of the system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
p=eig(G); alpha=G.alpha;
|
||||
plot(real(p),imag(p),'x',0,0,'o')
|
||||
apol=min(abs(angle(p))); K=apol>alpha*pi/2;
|
||||
xm=xlim; if alpha<1, xm(1)=0; else, xm(2)=0; end
|
||||
a1=tan(alpha*pi/2)*xm; a2=tan(alpha*pi)*xm;
|
||||
line(xm,a1), line(xm,-a1), line(xm,a2), line(xm,-a2)
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function Y=lsim(G,varargin)
|
||||
% lsim - simulation of an FOSS object driven by given inputs
|
||||
%
|
||||
% lsim(G,u,t)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% u, t- input samples and time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, lsim(fotf(G),varargin{:});
|
||||
else, Y=lsim(fotf(G),varargin{:});
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function [Gm,Pm,Wcg,Wcp]=margin(G)
|
||||
% margin - gain and phase margins of an FOSS object
|
||||
%
|
||||
% [Gm,Pm,Wcg,Wcp]=margin(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% Gm, Wcg - gain margin in dBs and the corresponding frequency
|
||||
% Pm, Wcp - phase margin in degrees and the crossover frequency
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[Gm,Pm,Wcg,Wcp]=margin(fotf(G));
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function H=mfrd(G,varargin)
|
||||
% mfrd - evaluation of frequency responses of an FOSS object
|
||||
%
|
||||
% H=mfrd(G,w)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% w - frequency vector
|
||||
% H - frequency response of G in MFD format
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
H=mfrd(fotf(G),varargin{:});
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function G=minreal(G1)
|
||||
% minreal - minimum realisation of an FOSS object
|
||||
%
|
||||
% G=minreal(G1)
|
||||
%
|
||||
% G1 - an FOSS object
|
||||
% G - minimum realisation of G1 as an FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
alpha=G1.alpha; G2=ss_extract(G1); G2=minreal(G2);
|
||||
G=foss(G2); G.alpha=alpha;
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
function G=minus(G1,G2)
|
||||
% minus - minus operation of two FOSS objects
|
||||
%
|
||||
% G=G1-G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G=G1+(-G2);
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
function G1=mpower(G,n)
|
||||
% mpower - power of an FOSS object
|
||||
%
|
||||
% G1=G^n
|
||||
%
|
||||
% G - an FOSS object
|
||||
% n - power. If G is s or constant, n can be any real number,
|
||||
% If G is an FOSS, n should be integers
|
||||
% G1 - returns G^n, and an FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if n==fix(n), [n1,m1]=size(G); if n<0, G=inv(G); end
|
||||
if n1==m1
|
||||
G1=foss(eye(n1)); for i=1:abs(n), G1=G1*G; end
|
||||
else, error('matrix must be square'); end
|
||||
else, error('mpower: power must be an integer.');
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
function G=mtimes(G1,G2)
|
||||
% mpower - product of two FOSS objects, series connection
|
||||
%
|
||||
% G=G1*G2
|
||||
%
|
||||
% G1, G2 - FOSS objects
|
||||
% G - returns the product of the two FOSS objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=foss(G1); G2=foss(G2);
|
||||
if length(G1.alpha)>1 || length(G2.alpha)>1, a=0.0001;
|
||||
else, a=common_order(G1.alpha,G2.alpha); end
|
||||
if a==0, G=foss([],[],[],G1.d*G2.d,0);
|
||||
elseif a<0.001, G1=fotf(G1); G2=fotf(G2); G=foss(G1*G2);
|
||||
else
|
||||
G1=coss_aug(G1,round(G1.alpha/a));
|
||||
G2=coss_aug(G2,round(G2.alpha/a));
|
||||
G=foss(ss_extract(G1)*ss_extract(G2)); G.alpha=a;
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function H=nichols(G,varargin)
|
||||
% nichols - draw the Nichols chart of an FOSS object
|
||||
%
|
||||
% nichols(G,w)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% w - the frequency vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, nichols(fotf(G),varargin{:});
|
||||
else, H=nichols(fotf(G),varargin{:});
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function n=norm(G,varargin)
|
||||
% norm -= norms of an FOSS object
|
||||
%
|
||||
% norm(G), norm(G,inf)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% The 2-norm and infinity-norm of G can be evaluated, respectively
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
n=norm(fotf(G),varargin{:});
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function H=nyquist(G,varargin)
|
||||
% nyquist - draw the Nyquist plot of an FOSS object
|
||||
%
|
||||
% nyquist(G,w)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% w - the frequency vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, nyquist(fotf(G),varargin{:});
|
||||
else, H=nyquist(fotf(G),varargin{:});
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function To=obsv(G)
|
||||
% obsv - create an observability test matrix for an FOSS
|
||||
%
|
||||
% To=obsv(G)
|
||||
%
|
||||
% G - the FOSS object
|
||||
% To - the observability test matrix
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
To=obsv(G.a,G.c);
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function n=order(G)
|
||||
% order - extract the order of an FOSS object
|
||||
%
|
||||
% n=order(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% n - the order
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
n=length(G.a)*G.alpha;
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
function G=plus(G1,G2)
|
||||
% plus - evaluate the sum of two FOSS objects, parallel connection
|
||||
%
|
||||
% G=G1+G2
|
||||
%
|
||||
% G1, G2 - the two FOSS objects in parallel connection
|
||||
% G - the sum of G1 and G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=foss(G1); G2=foss(G2);
|
||||
if length(G1.alpha)>1 || length(G2.alpha)>1, a=0.0001;
|
||||
else, a=common_order(G1.alpha,G2.alpha); end
|
||||
if a==0, G=foss([],[],[],G1.d+G2.d,0);
|
||||
elseif a<0.001, G1=fotf(G1); G2=fotf(G2); G=foss(G1+G2);
|
||||
else
|
||||
G1=coss_aug(G1,round(G1.alpha/a));
|
||||
G2=coss_aug(G2,round(G2.alpha/a));
|
||||
G=foss(ss_extract(G1)+ss_extract(G2)); G.alpha=a;
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function rlocus(G)
|
||||
% rlocus - draw the root locus of a SISO FOSS object
|
||||
%
|
||||
% rlocus(G)
|
||||
%
|
||||
% G - a SISO FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
rlocus(fotf(G))
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function [p,q,n]=size(G)
|
||||
% size - extract the numbers of inputs, outputs and states of an FOSS object
|
||||
%
|
||||
% [p,q,n]=size(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% n, m - the numbers of the inputs and outputs
|
||||
% n - the number of states
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
q=size(G.c,1); p=size(G.b,2); n=length(G.a);
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function G1=ss_extract(G)
|
||||
% ss_extract - extract the SS object from an FOSS object
|
||||
%
|
||||
% G1=ss_extract(G)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% G1 - the extracted integer-order state space model
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
G1=ss(G.a,G.b,G.c,G.d); G1.E=G.E;
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function Y=step(G,varargin)
|
||||
% step - simulation of an FOSS object driven by step inputs
|
||||
%
|
||||
% step(G,t)
|
||||
%
|
||||
% G - an FOSS object
|
||||
% t- the time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargout==0, step(fotf(G),varargin{:});
|
||||
else, Y=step(fotf(G),varargin{:});
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function G=uminus(G1)
|
||||
% uminus - unary minus of an FOSS object
|
||||
%
|
||||
% G1=-G
|
||||
%
|
||||
% G - an FOSS object
|
||||
% G1- the unary minus of G, i.e., -G
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G=G1; G.c=-G1.c; G.d=-G1.d;
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function alpha=base_order(G)
|
||||
% base_order - find the base order of an FOTF object
|
||||
%
|
||||
% alpha=base_order(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% alpha - the base order of the system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); a=[];
|
||||
for i=1:n, for j=1:m, g=G(i,j); a=[a,g.num.na,g.den.na]; end, end
|
||||
alpha=double(gcd(sym(a)));
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
function H=bode(G,w)
|
||||
% bode - draw Bode diagram for an FOTF object
|
||||
%
|
||||
% bode(G,w)
|
||||
% H=bode(G,w)
|
||||
%
|
||||
% G - the FOTF object
|
||||
% w - the frequency vector
|
||||
% H - the frequency response data in FRD format
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
arguments, G, w=logspace(-4,4); end
|
||||
H1=freqresp(1j*w,G); H1=frd(H1,w);
|
||||
if nargout==0, subplot(111), bode(H1); else, H=H1; end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
function G=diag(G1)
|
||||
% diag - diagonal matrix manipulation of an FOTF object
|
||||
%
|
||||
% G=diag(G1)
|
||||
%
|
||||
% G - the FOTF object
|
||||
% G1 - if G is a vector, configurate a matrix G1, otherwise extract its
|
||||
% diagonal elements to form G1
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G1); nm=max(n,m); nm1=min(n,m);
|
||||
if m==1 || n==1
|
||||
G=fotf(zeros(nm,nm)); for i=1:nm, G(i,i)=G1(i); end
|
||||
else
|
||||
G=fotf(zeros(nm1,1)); for i=1:nm1, G(i)=G1(i,i); end
|
||||
end, end
|
|
@ -0,0 +1,25 @@
|
|||
function str=disp(G)
|
||||
% display - display an FOTF. This function will be called automatically
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); key=0; if nargout==1, key=1; end
|
||||
for i=1:m, if m>1, disp([' From input ' int2str(i) ' to output...']), end
|
||||
for j=1:n, if n>1, disp([' ' int2str(j) ':']), end
|
||||
str=fotfdisp(G(j,i),key); if nargout==0, disp(' '); end
|
||||
end, end, end
|
||||
% display a SISO FOTF object
|
||||
function str=fotfdisp(G,key)
|
||||
strN=disp(G.num); str=strN;
|
||||
strD=disp(G.den); nn=length(strN);
|
||||
if nn==1 && strN=='0', if key==0, disp(strN), end
|
||||
else, nd=length(strD); nm=max([nn,nd]);
|
||||
if key==0, disp([char(' '*ones(1,floor((nm-nn)/2))) strN]), end
|
||||
ss=[]; T=G.ioDelay; if T>0, ss=['exp(-' num2str(T) '*s)']; end
|
||||
if T>0, str=['(' str ')*' ss '/(' strD ')'];
|
||||
else, str=['(' str ')/(' strD ')']; end
|
||||
str=strrep(strrep(str,'{',''),'}','');
|
||||
if key==0, disp([char('-'*ones(1,nm)), ss]);
|
||||
disp([char(' '*ones(1,floor((nm-nd)/2))) strD])
|
||||
end, end, end
|
|
@ -0,0 +1,10 @@
|
|||
function a=double(G)
|
||||
%double - convert FOTF to double, if possible
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 May, 2022
|
||||
if G.num.na==0 && G.den.na==0
|
||||
a=G.num.a./G.den.a;
|
||||
else, error('G contains dynamic terms, cannot be converted into double')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function p=eig(G)
|
||||
% eig - finding all the pseudo poles of an FOTF object
|
||||
%
|
||||
% p=eig(G)
|
||||
%
|
||||
% G - the FOTF object
|
||||
% p - all the pseudo-poles of G
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
p=eig(foss(G));
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
function key=eq(G1,G2)
|
||||
% eq - test whether two FOTF objects are equal or not
|
||||
%
|
||||
% key=G1==G2
|
||||
%
|
||||
% G1, G2 - the two FOTF objects
|
||||
% key = 1 for equal, otherwise key = 0
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n1,m1]=size(G1); [n2,m2]=size(G2);
|
||||
if n1~=n2 || m1~=m2, key=0;
|
||||
else
|
||||
G=G1-G2; [n,m]=size(G); key=0; kk=0;
|
||||
for i=1:n, for j=1:m, kk=kk+(G(i,j).num==0);
|
||||
end, end, end
|
||||
key=(kk==n1*m1);
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function G=exp(del)
|
||||
% exp - express delay term exp(-tau*s)
|
||||
%only works for SISO FOTF model
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 May, 2022
|
||||
try
|
||||
T=double(del/fotf('s'));
|
||||
if T>0, error('Delay must be negative'), else, T=-T; end
|
||||
G=fotf(1); G.ioDelay=T;
|
||||
catch, error('Error in extracting delay constant');
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
function G=feedback(F,H)
|
||||
% feedback - find the overall model of two FOTF objects in feedback connection
|
||||
%
|
||||
% G=feedback(G1,G2)
|
||||
%
|
||||
% G1, G2 - the FOTF objects in the forward and backward paths
|
||||
% G - the overall model of the closed-loop system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
F=fotf(F); H=fotf(H); [n1,m1]=size(F); [n2,m2]=size(H);
|
||||
if n1*m1==1 && n2*m2==1
|
||||
if F.ioDelay==H.ioDelay
|
||||
G=fotf(F.den*H.den+F.num*H.num,F.num*H.den);
|
||||
G=simplify(G); G.ioDelay=F.ioDelay;
|
||||
else, error('delay in incompatible'), end
|
||||
elseif n1==m1 && n1==n2 && n2==m2
|
||||
if maxdelay(F)==0 && maxdelay(H)==0
|
||||
G=inv(fotf(eye(size(F*H)))+F*H)*F; G=simplify(G);
|
||||
else, error('cannot handle blocks with delays'); end
|
||||
else, error('not equal sized square matrices'), end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
function G1=foss_a(G)
|
||||
% foss_a - convert an FOTF object into an extended FOSS object
|
||||
%
|
||||
% G1=foss_a(G)
|
||||
%
|
||||
% G - the FOTF object
|
||||
% G1 - the equivalent extended FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); n0=[];
|
||||
for i=1:n, for j=1:m, g=G(i,j); n0=[n0, g.nn g.nd]; end, end
|
||||
n0=unique(n0); n1=n0(end:-1:1);
|
||||
for i=1:n, for j=1:m, g=G(i,j);
|
||||
num=[]; den=[]; nn=g.nn; nd=g.nd; b=g.num; a=g.den;
|
||||
for k=1:length(nn), t=find(nn(k)==n1); num(t)=b(k); end
|
||||
for k=1:length(nd), t=find(nd(k)==n1); den(t)=a(k); end
|
||||
Gt(i,j)=tf(num,den); T(i,j)=g.ioDelay;
|
||||
end, end
|
||||
Gf=ss(Gt); E=Gf.e; [a,b,c,d]=dssdata(Gf);
|
||||
alpha=-diff(n1); G1=foss(a,b,c,d,alpha,T,E);
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
% foss - class constructor for an FOTF class
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
%Note that, the low-level support of FOTF object is changed to
|
||||
%ppoly object, pseudo-polynomials
|
||||
classdef fotf
|
||||
properties
|
||||
num, den, ioDelay
|
||||
end
|
||||
methods
|
||||
function G=fotf(a,na,b,nb,T)
|
||||
if isa(a,'fotf'), G=a;
|
||||
elseif strcmp(class(a),'sym'), G=sym2fotf(a);
|
||||
elseif isa(a,'foss'), G=foss2fotf(a);
|
||||
elseif nargin==1 && (isa(a,'tf') || isa(a,'ss') || isa(a,'double'))
|
||||
a=tf(a); [n1,m1]=size(a); G=[]; D=a.ioDelay;
|
||||
for i=1:n1, g=[]; for j=1:m1
|
||||
[n,d]=tfdata(tf(a(i,j)),'v'); nn=length(n)-1:-1:0;
|
||||
nd=length(d)-1:-1:0; g=[g fotf(d,nd,n,nn,D(i,j))];
|
||||
end, G=[G; g]; end
|
||||
elseif nargin==1 && a=='s', G=fotf(1,0,1,1,0);
|
||||
elseif isa(a,'ppoly'), G.num=na; G.den=a; G.ioDelay=0;
|
||||
else, ii=find(abs(a)<eps); a(ii)=[]; na(ii)=[];
|
||||
ii=find(abs(b)<eps); b(ii)=[]; nb(ii)=[];
|
||||
if isempty(b), b=0; nb=0; end
|
||||
if nargin==4, T=0; end
|
||||
num=ppoly(b,nb); den=ppoly(a,na); G.num=num; G.den=den; G.ioDelay=T;
|
||||
end, end, end, end
|
|
@ -0,0 +1,25 @@
|
|||
function [G1,alpha]=fotf2cotf(G)
|
||||
% fotf2cotf - convert an FOTF object into a commensurate-order one
|
||||
%
|
||||
% [G1,alpha]=fotf2cotf(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% G1 - an equivalent commensurate-order FOTF
|
||||
% alpha - the base order
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); alpha=base_order(G);
|
||||
if alpha==0
|
||||
for i=1:n, for j=1:m
|
||||
g=G(i,j); a=g.den.a; b=g.num.a; D(i,j)=b(1)/a(1); T(i,j)=g.ioDelay;
|
||||
end, end, G1=tf(D);
|
||||
else
|
||||
for i=1:n, for j=1:m, g=G(i,j); a=[]; b=[];
|
||||
n0=round(g.den.na/alpha); a(n0+1)=g.den.a; a=a(end:-1:1);
|
||||
m0=round(g.num.na/alpha); b(m0+1)=g.num.a; b=b(end:-1:1);
|
||||
g1=tf(b,a); G1(i,j)=g1; T(i,j)=g.ioDelay;
|
||||
end, end, end
|
||||
G1.ioDelay=T;
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
function G1=fotf2foss(G)
|
||||
% fotf2foss - convert an FOTF object to FOSS one
|
||||
%
|
||||
% G1=fotf2foss(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% G1 - an equivalent FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G);
|
||||
[G2,alpha]=fotf2cotf(G); G2=minreal(G2); G2=ss(G2);
|
||||
for i=1:n, for j=1:m, g=G(i,j); T(i,j)=g.ioDelay; end, end
|
||||
G1=foss(G2.a,G2.b,G2.c,G2.d,alpha,T,G2.E);
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
function [a,na,b,nb,L]=fotfdata(G)
|
||||
% fotfdata - extract data from an FOTF object
|
||||
%
|
||||
% [a,na,b,nb,L]=fotfdata(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% [a,na,b,nb] - the coefficients and orders of denominator and numerator
|
||||
% L - the delay constant
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G);
|
||||
if n*m==1, b=G.num.a; a=G.den.a; nb=G.num.na; na=G.den.na; L=G.ioDelay;
|
||||
else
|
||||
for i=1:n, for j=1:m
|
||||
[a0,na0,b0,nb0,L0]=fotfdata(G(i,j));
|
||||
a{i,j}=a0; b{i,j}=b0; na{i,j}=na0; nb{i,j}=nb0; L(i,j)=L0;
|
||||
end, end, end, end
|
|
@ -0,0 +1,23 @@
|
|||
function H=freqresp(s,G1)
|
||||
% freqresp - low-level function to evaluate the frequency response of
|
||||
% an FOTF object
|
||||
%
|
||||
% H=freqresp(s,G)
|
||||
%
|
||||
% s - the frequency vector or a vector for s
|
||||
% G - the FOTF object
|
||||
% H - frequency response, i.e., G(s) vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G1);
|
||||
for i=1:n, for j=1:m
|
||||
[a,na,b,nb,L]=fotfdata(G1(i,j));
|
||||
for k=1:length(s)
|
||||
P=b*(s(k).^nb.'); Q=a*(s(k).^na.'); H1(k)=P/Q;
|
||||
end
|
||||
if L>0, H1=H1.*exp(-L*s); end, H(i,j,:)=H1;
|
||||
end, end
|
||||
if n*m==1, H=H(:).'; end
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
function Ga=high_order(G0,filter,wb,wh,N,key)
|
||||
% high_order - approximate an FOTF object with high-order TFs
|
||||
%
|
||||
% Ga=high_order(G0,filter,wb,wh,N)
|
||||
%
|
||||
% G0 - an FOTF object
|
||||
% filter - can be 'ousta_fod', 'new_fod' and 'matsuda_fod'
|
||||
% wb, wh, N - the interested frequency interval and order of the filter
|
||||
% Ga - an equivalent TF object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
arguments
|
||||
G0, filter='ousta_fod', wb(1,1){mustBeNumeric}=1e-3
|
||||
wh(1,1) {mustBeNumeric, mustBeGreaterThan(wh,wb)}=1e3
|
||||
N(1,1) {mustBeInteger, mustBePositive}=5, key=0
|
||||
end
|
||||
[n,m]=size(G0); F=filter;
|
||||
for i=1:n, for j=1:m
|
||||
if G0(i,j)==fotf(0), Ga(i,j)=tf(0);
|
||||
else, G=simplify(G0(i,j)); [a,na,b,nb]=fotfdata(G);
|
||||
G1=pseudo_poly(b,nb,F,wb,wh,N,key)/pseudo_poly(a,na,F,wb,wh,N,key);
|
||||
Ga(i,j)=minreal(G1);
|
||||
end, end, end, end
|
||||
% 伪多项式的近似
|
||||
function p=pseudo_poly(a,na,filter,wb,wh,N,key)
|
||||
p=0; s=tf('s');
|
||||
for i=1:length(a), na0=na(i); n1=floor(na0); gam=na0-n1;
|
||||
if key==1
|
||||
g1=eval([filter '(gam,N,wb,wh)']); p=p+a(i)*g1;
|
||||
else
|
||||
if gam~=0, g1=eval([filter '(gam,N,wb,wh)']);
|
||||
else, g1=1; end
|
||||
p=p+a(i)*s^n1*g1;
|
||||
end, end, end
|
|
@ -0,0 +1,15 @@
|
|||
function y=impulse(G,t)
|
||||
% impulse - impulse response evaluation of an FOTF object
|
||||
%
|
||||
% impulse(G,t)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% t - the time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=G*fotf('s');
|
||||
if nargout==0, step(G1,t,1); title('Impulse Response')
|
||||
else, y=step(G1,t,1); end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
function G1=inv(G)
|
||||
% inv - inverse of a multivariable FOTF system
|
||||
%
|
||||
% G1=inv(G)
|
||||
%
|
||||
% G, G1 - an FOTF object and its inverse system
|
||||
% not recommended for MIMO FOTFs, use fotf2sym and work the
|
||||
% model G under symbolic framework
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G);
|
||||
if n*m==1
|
||||
if G.ioDelay>0, error('Delay terms are not allowed');
|
||||
else, G1=fotf(G.num,G.den); end
|
||||
elseif n~=m
|
||||
error('Error: non-square matrix, not invertible')
|
||||
else, G1=fotfinv(G); end
|
||||
end
|
||||
function G1=fotfinv(G)
|
||||
[n,~]=size(G); A1=G; E0=fotf(eye(n)); A3=E0;
|
||||
for i=1:n, ij=1:n; ij=ij(ij~=i);
|
||||
E=fotf(eye(n)); a0=inv(A1(i,i));
|
||||
for k=ij, E(k,i)=-A1(k,i)*a0; end
|
||||
E0=E*E0; A1=E*A1; A3(i,i)=a0;
|
||||
end, G1=A3*E0;
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
function key=isfotf(p)
|
||||
%isfotf check input is an FOTF object or not
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
key=isa(p,'fotf');
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
function [K,alpha0,apol,p]=isstable(G,a0)
|
||||
% isstable - check whether an FOTF object is stable or not
|
||||
%
|
||||
% [K,alpha,apol]=isstable(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% K- identifier to indicate the stability of G, returns 0, and 1
|
||||
% alpha - the common order
|
||||
% apol - all the pseudo poles of the system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n0,m0]=size(G); K=1; if nargin==1, a0=0.001; end
|
||||
for i=1:n0, for j=1:m0
|
||||
g=G(i,j); a=g.den.na; a1=fix(a/a0);
|
||||
if length(a1)==1 && a1==0
|
||||
else
|
||||
[g1,alpha]=fotf2cotf(g); c=g1.den{1};
|
||||
alpha0(i,j)=alpha; p0=roots(c); kk=[];
|
||||
for k=1:length(p0)
|
||||
a=g.den.a; na=g.den.na; pa=p0(k)^(1/alpha);
|
||||
if norm(a*[pa.^na'])<1e-6, kk=[kk,k]; end
|
||||
end
|
||||
p=p0(kk); subplot(n0,m0,(i-1)*m0+j),
|
||||
plot(real(p),imag(p),'x',0,0), xm=xlim;
|
||||
if alpha<1, xm(1)=0; else, xm(2)=0; end
|
||||
apol=min(abs(angle(p))); K=K*(apol>alpha*pi/2);
|
||||
a1=tan(alpha*pi/2)*xm; a2=tan(alpha*pi)*xm;
|
||||
line(xm,a1), line(xm,-a1), line(xm,a2), line(xm,-a2)
|
||||
xlabel('Real Axis'), ylabel('Imaginary Axis')
|
||||
end, end, end
|
||||
title('Pole Map')
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function key=iszero(g)
|
||||
% iszero - check whether a SISO FOTF object is zero or not
|
||||
%
|
||||
% key=iszero(G)
|
||||
%
|
||||
% G - a SISO FOTF object
|
||||
% key - identifier, if G is zero, then key = 1.
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
key=0; [~,~,b,nb]=fotfdata(g);
|
||||
if isempty(b) || (length(nb)==1 && abs(b(1))<eps), key=1; end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
function str=latex(G)
|
||||
% latex - convert an FOTF object into its LaTeX string
|
||||
%
|
||||
% str=latex(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% str - LaTeX string
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G);
|
||||
if n*m==1
|
||||
str=['\frac{' latex(G.num) '}{' latex(G.den) '}']; T= G.ioDelay;
|
||||
if T~=0, ss=[]; if T~=1, ss=num2str(T); end
|
||||
str=[str '\mathrm{e}^{-' ss 's}'];
|
||||
end
|
||||
else
|
||||
str='\begin{bmatrix}';
|
||||
for i=1:n
|
||||
for j=1:m
|
||||
str=[str, '\displaystyle ' latex(G(i,j)) '&'];
|
||||
end, str=[str(1:end-1) '\cr'];
|
||||
end, str=[str(1:end-3),'\end{bmatrix}'];
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
function y=lsim(G,u,t)
|
||||
% lsim - simulation of an FOTFS object driven by given inputs
|
||||
%
|
||||
% lsim(G,u,t)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% u, t- input samples and time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); t0=t(1); t1=t(end); [nu,mu]=size(u);
|
||||
if nu==m && mu==length(t), u=u.'; end
|
||||
if nargout==0, lsim(tf(zeros(n,m)),'w',zeros(size(u)),t); end
|
||||
for i=1:n, y1=0;
|
||||
for j=1:m, g=G(i,j); uu=u(:,j);
|
||||
y2=fode_sol9(g.den.a,g.den.na,g.num.a,g.num.na,uu,t,3);
|
||||
ii=find(t>=g.ioDelay); lz=zeros(1,ii(1)-1);
|
||||
y2=[lz, y2(1:end-length(lz))]; y(:,i)=y1+y2;
|
||||
end, end
|
||||
if nargout==0, khold=ishold; hold on
|
||||
h=get(gcf,'child'); h0=h(end:-1:2);
|
||||
for i=1:n, axes(h0(i));
|
||||
plot(t,y(:,i),t,u,'--'), xlim([t0,t1])
|
||||
end, if khold==0, hold off, end, end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function [Gm,Pm,Wcg,Wcp]=margin(G)
|
||||
% margin - gain and phase margins of an FOTF object
|
||||
%
|
||||
% [Gm,Pm,Wcg,Wcp]=margin(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% Gm, Wcg - gain margin in dBs and the corresponding frequency
|
||||
% Pm, Wcp - phase margin in degrees and the crossover frequency
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
H=bode(G,logspace(-4,4,1000)); [Gm,Pm,Wcg,Wcp]=margin(H);
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function T=maxdelay(G)
|
||||
% maxdelay - extract the maximum delay from an FOTF object
|
||||
%
|
||||
% T=maxdelay(G)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% T - the maximum delay of the system
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
T=0; [n,m]=size(G);
|
||||
for i=1:n, for j=1:m, T=max(T,G(i,j).ioDelay); end, end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function H1=mfrd(G,w)
|
||||
% mfrd - evaluation of frequency responses of an FOTF object
|
||||
%
|
||||
% H=mfrd(G,w)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% w - frequency vector
|
||||
% H - frequency response of G in MFD format
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
H=bode(G,w); h=H.ResponseData; H1=[];
|
||||
for i=1:length(w); H1=[H1; h(:,:,i)]; end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
function G=minus(G1,G2)
|
||||
% minus - minus operation of two FOTF objects
|
||||
%
|
||||
% G=G1-G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G=G1+(-G2);
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
function G=mldivide(G1,G2)
|
||||
% mldivide - left division of two FOTF objects
|
||||
%
|
||||
% G=G1\G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
G1=fotf(G1); G2=fotf(G2);
|
||||
if maxdelay(G)==0 && maxdelay(G2)==0, G=inv(G1)*G2;
|
||||
else, warning('block with positive delay'); end
|
|
@ -0,0 +1,30 @@
|
|||
function G1=mpower(G,n)
|
||||
% mpower - power of an FOTF object
|
||||
%
|
||||
% G1=G^n
|
||||
%
|
||||
% G - an FOTF object
|
||||
% n - power. If G is s or constant, n can be any real number,
|
||||
% If G is an FOSS, n should be integers
|
||||
% G1 - returns G^n, and an FOSS object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n1,m1]=size(G);
|
||||
if n==fix(n)
|
||||
if n1==m1
|
||||
if n>=0, G1=fotf(eye(n1)); for i=1:n, G1=G1*G; end
|
||||
else, G1=inv(G)^(-n); end
|
||||
elseif n==1, G1=G;
|
||||
else, error('G must be a square matrix');
|
||||
end
|
||||
elseif n1==1 && m1==1
|
||||
if length(G.num)==1 && length(G.den)==1
|
||||
[a,na,b,nb,L]=fotfdata(G);
|
||||
G1=fotf(a^n,na*n,b^n,nb*n,L*n);
|
||||
else, error('mpower: power must be an integer.');
|
||||
end
|
||||
else, error('mpower: power must be an integer.');
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function G=mrdivide(G1,G2)
|
||||
% mldivide - right division of two FOTF objects
|
||||
%
|
||||
% G=G1/G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=fotf(G1); G2=fotf(G2);
|
||||
if maxdelay(G1)==0 && maxdelay(G2)==0, G=G1*inv(G2);
|
||||
else, error('block with positive delay'); end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
function G=mtimes(G1,G2)
|
||||
% mpower - product of two FOTF objects, series connection
|
||||
%
|
||||
% G=G1*G2
|
||||
%
|
||||
% G1, G2 - FOTF objects
|
||||
% G - returns the product of the two FOTF objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=fotf(G1); G2=fotf(G2);
|
||||
if numel(G1)==1 && numel(G2)==1, G=sisofotftimes(G1,G2);
|
||||
else, [n1,m1]=size(G1); [n2,m2]=size(G2);
|
||||
if m1==n2, G=fotf(zeros(n1,m2));
|
||||
for i=1:n1, for j=1:m2
|
||||
for k=1:m1, G(i,j)=G(i,j)+sisofotftimes(G1(i,k),G2(k,j));
|
||||
end, end, end
|
||||
elseif n1*m1==1, G=fotf(zeros(n2,m2)); % if G1 is scalar
|
||||
for i=1:n2, for j=1:m2, G(i,j)=G1*G2(i,j); end, end
|
||||
elseif n2*m2==1, G=fotf(zeros(n1,m1)); % if G2 is scalar
|
||||
for i=1:n1, for j=1:m1, G(i,j)=G2*G1(i,j); end, end
|
||||
else
|
||||
error('The two matrices are incompatible for multiplication')
|
||||
end, end, end
|
||||
% product of two SISO FOTF objects
|
||||
function G=sisofotftimes(G1,G2)
|
||||
G=fotf(G1.den*G2.den,G1.num*G2.num); G=simplify(G);
|
||||
G.ioDelay=G1.ioDelay+G2.ioDelay;
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function nichols(G,w)
|
||||
% nichols - draw the Nichols chart of an FOTF object
|
||||
%
|
||||
% nichols(G,w)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% w - the frequency vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
arguments, G, w=logspace(-4,4); end
|
||||
H=bode(G,w); nichols(H);
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
function n=norm(G,eps0)
|
||||
% norm -= norms of an FOTF object
|
||||
%
|
||||
% norm(G), norm(G,inf)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% The 2-norm and infinity-norm of G can be evaluated, respectively
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); if nargin==1, eps0=1e-6; end
|
||||
for i=1:n, for j=1:m, A(i,j)=snorm(G(i,j),eps0); end, end
|
||||
n=norm(A);
|
||||
end
|
||||
% norm of a SISO FOTF object
|
||||
function n=snorm(G,eps0)
|
||||
j=sqrt(-1);
|
||||
if nargin==2 && ~isfinite(eps0) % H infinity norm, find the maximum value
|
||||
f=@(w)-abs(freqresp(j*w,G));
|
||||
w=fminsearch(f,0); n=abs(freqresp(j*w,G));
|
||||
else % H2 norm, numerical integration
|
||||
f=@(s)freqresp(s,G).*freqresp(-s,G);
|
||||
n=integral(f,-inf,inf)/(2*pi*j);
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function n=numel(G)
|
||||
% numel - the number of FOTF objects in G
|
||||
%
|
||||
% n=numel(G)
|
||||
%
|
||||
% G - FOTF object
|
||||
% n - returns the number of FOTF objects in G
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); n=n*m;
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function nyquist(G,w)
|
||||
% nyquist - draw the Nyquist plot of an FOTF object
|
||||
%
|
||||
% nyquist(G,w)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% w - the frequency vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
arguments, G, w=logspace(-4,4); end
|
||||
H=bode(G,w); nyquist(H);
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
function G=plus(G1,G2)
|
||||
% plus - evaluate the sum of two FOTF objects, parallel connection
|
||||
%
|
||||
% G=G1+G2
|
||||
%
|
||||
% G1, G2 - the two FOTF objects in parallel connection
|
||||
% G - the sum of G1 and G2
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
G1=fotf(G1); G2=fotf(G2);
|
||||
[n1,m1]=size(G1); [n2,m2]=size(G2);
|
||||
if n1==n2 && m1==m2, G=G1;
|
||||
for i=1:n1, for j=1:m1
|
||||
G(i,j)=sisofotfplus(G1(i,j),G2(i,j));
|
||||
end, end
|
||||
elseif n1*m1==1, G1=G1*fotf(ones(n2,m2)); G=G1+G2;
|
||||
elseif n2*m2==1, G2=G2*fotf(ones(n1,m1)); G=G1+G2;
|
||||
else
|
||||
error('Error: the sizes of the two FOTF matrices mismatch');
|
||||
end
|
||||
% sum of two SISO FOTF objects
|
||||
function G=sisofotfplus(G1,G2)
|
||||
if G1.ioDelay==G2.ioDelay
|
||||
G=fotf(G1.den*G2.den,G1.num*G2.den+G2.num*G1.den);
|
||||
G=simplify(G); G.ioDelay=G1.ioDelay;
|
||||
else, error('Error: cannot handle different delays');
|
||||
end, end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function [alpha,r,p,K]=residue(G)
|
||||
% residue - partial fraction expansion of a SISO FOTF object
|
||||
%
|
||||
% [alpha,r,p,K]=residue(G)
|
||||
%
|
||||
% G - a SISO commensurate-order FOTF object
|
||||
% alpha - base order
|
||||
% r, p, K - the definitions are the same as the conventional residue function
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[H,alpha]=fotf2cotf(G); [r,p,K]=residue(H.num{1},H.den{1});
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
function rlocus(G)
|
||||
% rlocus - draw the root locus of a SISO FOTF object
|
||||
%
|
||||
% rlocus(G)
|
||||
%
|
||||
% G - a SISO FOTF object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if numel(G)==1
|
||||
[G1,alpha]=fotf2cotf(G); rlocus(G1), xm=xlim;
|
||||
if alpha<1, xm(1)=0; else, xm(2)=0; end
|
||||
line(xm,tan(alpha*pi/2)*xm), line(xm,-tan(alpha*pi/2)*xm)
|
||||
line(xm,tan(alpha*pi)*xm), line(xm,-tan(alpha*pi)*xm)
|
||||
else
|
||||
error('Root locus only applies to SISO systems');
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
function sigma(G,w)
|
||||
% sigma - singular value plots of a MIMO FOTF object
|
||||
%
|
||||
% sigma(G,w)
|
||||
%
|
||||
% G - a MIMO FOTF object
|
||||
% w - a frequency vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
if nargin==1, w=logspace(-4,4); end
|
||||
H=bode(G,w); subplot(111); h1=[]; H1=H;
|
||||
h=H.ResponseData; [n,m,k]=size(h);
|
||||
for i=1:k, h1=[h1, svd(h(:,:,i))]; end
|
||||
for i=1:min([n,m])
|
||||
h2(1,1,:)=h1(i,:).'; H1.ResponseData=h2; bodemag(H1), hold on
|
||||
end
|
||||
hold off
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
function G=simplify(G,eps1)
|
||||
% simplify - simplification of an FOTF object
|
||||
%
|
||||
% G=simplify(G1,eps1)
|
||||
%
|
||||
% G1 - a FOTF object
|
||||
% eps1 - error tolerance
|
||||
% G - simplified FOTF object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); if nargin==1, eps1=eps; end
|
||||
for i=1:n, for j=1:m
|
||||
g=G(i,j); num=g.num.a; den=g.den.a; nn=g.num.na; nd=g.den.na;
|
||||
i1=abs(num)>eps1; i2=abs(den)>eps1; num=num(i1); den=den(i2);
|
||||
nn=nn(i1); nd=nd(i2); n0=min(nn); d0=min(nd);
|
||||
na=min(n0,d0); if isempty(na), na=0; end
|
||||
G(i,j)=fotf(den,nd-na,num,nn-na,g.ioDelay);
|
||||
end, end, end
|
|
@ -0,0 +1,33 @@
|
|||
function Y=step(G,t,key)
|
||||
% step - simulation of an FOTF object driven by step inputs
|
||||
%
|
||||
% step(G,t)
|
||||
%
|
||||
% G - an FOTF object
|
||||
% t- the time vector
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G); M=tf(zeros(n,m));
|
||||
if nargin==1, t=(0:0.2:10)'; elseif length(t)==1, t=0:t/100:t; end
|
||||
if nargout==0, t0=t(1); t1=t(end);
|
||||
if nargin<=2, step(M,'w'); else, impulse(M,'w');
|
||||
end, end
|
||||
for i=1:n, for j=1:m
|
||||
g=G(i,j); y1=g_step(g,t); y(i,j,:)=y1';
|
||||
end, end
|
||||
if nargout==0, khold=ishold; hold on
|
||||
h=get(gcf,'child'); h0=h(end:-1:2);
|
||||
for i=1:n, for j=1:m, axes(h0((i-1)*n+j));
|
||||
yy=y(i,j,:); plot(t,yy(:)), xlim([t0,t1])
|
||||
end, end
|
||||
if khold==0, hold off, end
|
||||
elseif n*m==1, Y=y1; else, Y=y; end
|
||||
end
|
||||
%subfunction to evaluate step response of SISO model
|
||||
function y=g_step(g,t,key)
|
||||
u=ones(size(t));
|
||||
[a,na,b,nb,T]=fotfdata(g); y1=fode_sol(a,na,b,nb,u,t);
|
||||
ii=find(t>=T); lz=zeros(1,ii(1)-1); y=[lz, y1(1:end-length(lz))];
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
function G=uminus(G)
|
||||
% uminus - unary minus of an FOTFS object
|
||||
%
|
||||
% G1=-G
|
||||
%
|
||||
% G - an FOT object
|
||||
% G1- the unary minus of G, i.e., -G
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
[n,m]=size(G);
|
||||
for i=1:n, for j=1:m, G(i,j).num=-G(i,j).num; end, end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
function p=collect(p)
|
||||
% collect - collect like terms in ppoly objects
|
||||
%
|
||||
% p=collect(p)
|
||||
%
|
||||
% p - a ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
a=p.a; na=p.na;
|
||||
[na,ii]=sort(na,'descend'); a=a(ii); ax=diff(na); key=1;
|
||||
for i=1:length(ax)
|
||||
if abs(ax(i))<=1e-10
|
||||
a(key)=a(key)+a(key+1); a(key+1)=[]; na(key+1)=[];
|
||||
else, key=key+1; end
|
||||
end
|
||||
ii=find(abs(a)~=0); a=a(ii); na=na(ii); p=ppoly(a,na);
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
function str=disp(p)
|
||||
% collect - collect like terms in ppoly objects
|
||||
%
|
||||
% p=collect(p)
|
||||
%
|
||||
% p - a ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
np=p.na; p=p.a;
|
||||
if isempty(np), p=0; np=0; end
|
||||
P=''; [np,ii]=sort(np,'descend'); p=p(ii);
|
||||
for i=1:length(p)
|
||||
P=[P,'+',num2str(p(i)),'*s^{',num2str(np(i)),'}'];
|
||||
end
|
||||
P=P(2:end); P=strrep(P,'s^{0}',''); P=strrep(P,'+-','-');
|
||||
P=strrep(P,'^{1}',''); P=strrep(P,'+1*s','+s');
|
||||
P=strrep(P,'*+','+'); P=strrep(P,'*-','-');
|
||||
P=strrep(P,'-1*s','-s'); nP=length(P);
|
||||
if nP>=3 && isequal(P(1:3),'1*s'), P=P(3:end); end
|
||||
if P(end)=='*', P(end)=''; end
|
||||
if nargout==0, disp(P), else, str=P; end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function key=eq(p1,p2)
|
||||
% eq - test whether two PPOLY objects are equal or not
|
||||
%
|
||||
% key=p1==p2
|
||||
%
|
||||
% p1, p2 - the two PPOLY objects
|
||||
% key = 1 for equal, otherwise key = 0
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
g=collect(p1-p2); key=isempty(g.a);
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
function H=freqw(p,w)
|
||||
% freqw - get frequency response of ppoly object
|
||||
%
|
||||
% H=freqw(p,w)
|
||||
%
|
||||
% p - a ppoly object
|
||||
% w - frequency vector
|
||||
% H - frequency response data
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
for i=1:length(w), H(i)=p.a(:).'*(1i*w(i)).^p.na(:); end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
function p1=get(varargin)
|
||||
% get - get fields from ppoly object
|
||||
%
|
||||
% a=get(p,'a') or na=get(p,'na')
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p=varargin{1};
|
||||
if nargin==1
|
||||
s=sprintf('%f ,',p.a); disp([' a: [' s(1:end-1) ']'])
|
||||
s=sprintf('%f ,',p.na); disp([' na: [' s(1:end-1) ']'])
|
||||
elseif nargin==2, key=varargin{2};
|
||||
switch key
|
||||
case 'a', p1=p.a; case 'na', p1=p.na;
|
||||
otherwise, error('Wrong field name used'),
|
||||
end
|
||||
else, error('Wrong number of input argumants');
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
function key=isppoly(p)
|
||||
% isppoly - check whether input is an ppoly object
|
||||
%
|
||||
% key=isppoly(p)
|
||||
%
|
||||
% key returns 1 or 0
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
key=strcmp(class(p),'ppoly');
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function strA=latex(p)
|
||||
% latex - convert ppoly object into LaTeX string
|
||||
%
|
||||
% str=latex(p)
|
||||
%
|
||||
% p - a ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
str=disp(p); str=strrep(str,'*s','s');
|
||||
if nargout==0, disp(str), else, strA=str; end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
function p=minus(p1,p2)
|
||||
% minus - find the differences in two ppoly objects
|
||||
%
|
||||
% p=p1-p2
|
||||
%
|
||||
% p, p1, p2 - ppoly objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p=p1+(-p2);
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
function p1=mpower(p,n)
|
||||
% mpower - power of a ppoly object
|
||||
%
|
||||
% p1=p^n
|
||||
%
|
||||
% p - a ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
if length(p.a)==1, p1=ppoly(p.a^n,p.na*n);
|
||||
elseif n==floor(n)
|
||||
if n<0, p.na=-p.na; n=-n; end
|
||||
p1=ppoly(1); for i=1:n, p1=p1*p; end
|
||||
else, error('n must be an integer'), end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
function p=mrdivide(p1,p2)
|
||||
% mrdivide - right divide ppoly objects
|
||||
%
|
||||
% p=p1/p2
|
||||
%
|
||||
% p, p1, p2 - ppoly objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p1=collect(ppoly(p1)); p2=collect(ppoly(p2)); p=fotf(p2,p1);
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function p=mtimes(p1,p2)
|
||||
% mtimes - product of two ppoly objects
|
||||
%
|
||||
% p=p1*p2
|
||||
%
|
||||
% p, p1, p2 - ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p1=ppoly(p1); p2=ppoly(p2); a=kron(p1.a,p2.a);
|
||||
na=kronsum(p1.na,p2.na); p=collect(ppoly(a,na));
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
function p=plus(p1,p2)
|
||||
% plus - sum of twp ppoly objects
|
||||
%
|
||||
% p=p1+p2
|
||||
%
|
||||
% p, p1, p2 - ppoly objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p1=ppoly(p1); p2=ppoly(p2);
|
||||
a=[p1.a,p2.a]; na=[p1.na,p2.na]; p=collect(ppoly(a,na));
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
% ppoly - class definition of a ppoly object
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
classdef ppoly
|
||||
properties, a, na, end
|
||||
methods
|
||||
function p=ppoly(a,na)
|
||||
if nargin==1
|
||||
if isa(a,'double'), p=ppoly(a,length(a)-1:-1:0);
|
||||
elseif isa(a,'ppoly'), p=a;
|
||||
elseif a=='s', p=ppoly(1,1); end
|
||||
elseif length(a)==length(na), p.a=a; p.na=na;
|
||||
else, error('Error: miss matching in a and na'); end
|
||||
end, end, end
|
|
@ -0,0 +1,11 @@
|
|||
function p1=uminus(p)
|
||||
% uminus - find -p
|
||||
%
|
||||
% p1=-p
|
||||
%
|
||||
% p, p1 - ppoly objects
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 18 May, 2022
|
||||
p1=ppoly(-p.a,p.na);
|
||||
end
|
|
@ -0,0 +1,197 @@
|
|||
%FOTF Toolbox - A MATLAB Toolbox for the modeling, analysis and design of fractional-order systems
|
||||
%
|
||||
% (c) Professor Dingy\"u Xue, Northeastern University, Shenyang, China
|
||||
% Email: xuedingyu@mail.neu.edu.cn
|
||||
% Date of last modification, 23 December, 2016
|
||||
%
|
||||
% This newly modified toolbox is written for the monograph,
|
||||
%
|
||||
% @BOOK{bkXueDFOCS,
|
||||
% Author = {Xue Dingy\"u},
|
||||
% Address = {Berlin},
|
||||
% Publisher = {de Gruyter Press},
|
||||
% Title = {Fractional-order Control Systems - Fundamentals and Numerical Implementations},
|
||||
% Year = {2017}
|
||||
% }
|
||||
%
|
||||
% Multivariable fractional-order systems are fully supported in the classes FOTF and FOSS
|
||||
% and low-level numerical algorithms are replaced by $O(h^p)$ precision ones.
|
||||
% For details in theory and programming, please refer to the monograph.
|
||||
|
||||
% (I) Special functions and fundamentals in numerical computation
|
||||
% beta_c - beta function evaluation for complex arguments
|
||||
% common_order - compute the common order
|
||||
% fence_shadow - draw the shawdows on the walls
|
||||
% fmincon_global - a global constrained optimisation problem solver
|
||||
% funmsym - evaluate symbolic matrix functions
|
||||
% gamma_c - Gamma function evaluation for complex arguments
|
||||
% kronsum - compute Kronecker sum
|
||||
% mittag_leffler - symbolic evaluation of Mittag-Leffler functions
|
||||
% ml_func - numerical evaluation of Mittag-Leffler functions and derivatives
|
||||
% more_sols - find possible all solutions of nonlinear matrix equations
|
||||
% more_vpasols - symbolic version of more_sols, high precision solutions
|
||||
% new_inv - simple matrix inverse function, not recommended in applications
|
||||
%
|
||||
%(II) Numerical evaluations of fractional-order derivatives and integrals
|
||||
% caputo - computation of Caputo derivatives with interpolation, not recommended
|
||||
% caputo9 - evaluation of Caputo derivatives with $O(h^p)$, recommended
|
||||
% genfunc - computation of generating function coefficients symbolically
|
||||
% get_vecw - computation of $O(h^p)$ weighting coefficients
|
||||
% glfdiff0 - evaluation of GL derivatives, not recommended
|
||||
% glfdiff - standard evaluation of GL derivatives, with $O(h)$
|
||||
% glfdiff2 - evaluation of $O(h^p)$ GL derivatives, not recommended
|
||||
% glfdiff9 - evaluation of $O(h^p)$ GL derivatives, recommended
|
||||
% glfdiff_fft - evaluation of $O(h^p)$ GL derivatives with FFT, not recommended
|
||||
% glfdiff_mat - matrix version of glfdiff, not recommended for large samples
|
||||
% glfdiff_mem - GL derivative evaluation with short-memory effect
|
||||
% rlfdiff evaluation of RL derivatives, not recommended, use glfdiff9 instead
|
||||
%
|
||||
%(III) Numerical evaluations of linear fractional-order differential equations
|
||||
% caputo_ics - equivalent initial condition reconstruction, called by fode_caputo9
|
||||
% fode_caputo0 - simple Caputo FODE solver with nonzero initial conditions
|
||||
% fode_caputo9 - $O(h^p)$ solution of Caputo equations with nonzero ICs
|
||||
% fode_sol - closed-form solution of FODE with zero initial conditions
|
||||
% fode_solm - matrix version of fode_sol, not recommended for large samples
|
||||
% fode_sol9 - $O(h^p)$ version of fode_sol
|
||||
% ml_step3 - numerical solution of step response of 3-term models
|
||||
%
|
||||
%(IV) Numerical evaluations of nonlinear fractional-order differential equations
|
||||
% INVLAP_new - closed-loop response evaluation with inverse Laplace transform
|
||||
% nlfode_mat - matrix-based solutions of implicit nonlinear FODEs
|
||||
% nlfode_vec - nonlinear fractional-order extended state space equation solver
|
||||
% nlfode_vec1 - a different version of nlfode_vec, not recommended
|
||||
% nlfec - $O(h^p)$ corrector solution of nonlinear multi-term FODEs
|
||||
% nlfep - $O(h^p)$ predictor solution of nonlinear multi-term fractional-order ODEs
|
||||
% pepc_nlfode - numerical solutions of single-term nonlinear FODE with PCPE algorithm
|
||||
%
|
||||
%(V) Filter design for fractional-order derivatives and systems
|
||||
% carlson_fod - design of a Carlson filter
|
||||
% charef_fod - design of a Charef filter
|
||||
% charef_opt - design of an optimal Charef filter
|
||||
% cont_frac0 - continued-fraction interface to irrational functions
|
||||
% matsuda_fod - design of Matsuda-Fujii filter
|
||||
% new_fod - design of a modified Oustaloup filter
|
||||
% opt_app - optimal IO transfer approximation of high-order models
|
||||
% ousta_fod - design of a standard Oustaloup filter
|
||||
%
|
||||
%(VI) FOTF object design and overload functions
|
||||
% base_order - find the base order from an FOTF object
|
||||
% bode - Bode diagram analysis
|
||||
% diag - diagonal FOTF matrix creation and extraction
|
||||
% display - overload function to display a MIMO FOTF object
|
||||
% eig - find all the poles, including extraneous roots
|
||||
% eq - checks whether two FOTF blocks equal or not
|
||||
% feedback - overload the feedback function for two FOTF blocks
|
||||
% foss_a - convert an FOTF to an extended FOSS object
|
||||
% fotf - creation of an FOTF class
|
||||
% fotf2cotf - convert an FOTF object into commensurate form
|
||||
% fotf2foss - low-level conversion function of FOTF to FOSS object
|
||||
% fotfdata - extract all the fields from an FOTF object
|
||||
% freqresp - low-level frequency response function of an FOTF object
|
||||
% high_order - high-order IO transfer function approximation of FOTF objects
|
||||
% impulse - evaluation of impulse response of an FOTF object
|
||||
% inv - inverse FOTF matrix
|
||||
% isstable - check whether an FOTF object stable or not
|
||||
% iszero - check whether an FOTF object is zero or not
|
||||
% lsim - time response evaluation to arbitrary input signals
|
||||
% margin - compute the gain and phase margins
|
||||
% maxdelay - extract maximum delay from an FOTF object
|
||||
% mfrd - frequency response evaluation
|
||||
% minus - minus operation of two FOTF objects
|
||||
% mldivide - left-division function
|
||||
% mpower - power of an FOTF object
|
||||
% mrdivide - right-division function
|
||||
% mtimes - overload function of * operation of two blocks
|
||||
% nichols - Nichols chart
|
||||
% norm - H2 and Hinf evaluation
|
||||
% nyquist - Nyquist plot
|
||||
% plus - overload function of + operation of two blocks
|
||||
% residue - partial fraction expansion
|
||||
% rlocus - root locus analysis
|
||||
% sigma - singular value plots
|
||||
% simplify - simplification of an FOTF object
|
||||
% step - step response
|
||||
% uminus - unary minus of an FOTF object
|
||||
%
|
||||
%(VII) FOSS object design and overload functions
|
||||
% bode - Bode diagram analysis
|
||||
% coss_aug - FOSS augmentation
|
||||
% ctrb - controllability test matrix creation
|
||||
% display - overload function to display a MIMO FOSS object
|
||||
% eig - compute the poles of a FOSS object
|
||||
% eq - checks two FOSS blocks equal or not
|
||||
% feedback - overload the feedback function for two FOSS blocks
|
||||
% foss - FOSS class creation
|
||||
% foss2fotf - low-level conversion from FOSS to FOTF object
|
||||
% impulse - evaluation of impulse response of an FOSS object
|
||||
% inv - inverse of an FOSS object
|
||||
% isstable - check an FOSS object stable or not
|
||||
% lsim - time response evaluation to arbitrary input signals
|
||||
% margin - compute the gain and phase margins
|
||||
% mfrd - frequency response evaluation
|
||||
% minreal - minimum realisation of a FOSS object
|
||||
% minus - minus operation of two FOTF objects
|
||||
% mpower - power of an FOSS object
|
||||
% mtimes - overload function of * operation of two blocks
|
||||
% nichols - Nichols chart
|
||||
% norm - H2 and Hinf evaluation
|
||||
% nyquist - Nyquist plot
|
||||
% obsv - construct observability test matrix
|
||||
% order - find the orders of an FOSS object
|
||||
% plus - overload function of + operation of two blocks
|
||||
% rlocus - root locus analysis
|
||||
% size - find the numbers of inputs, outputs and states
|
||||
% ss_extract - extract integer-order state space object from FOSS
|
||||
% step - step response
|
||||
% uminus - unary minus of an FOSS object
|
||||
%
|
||||
%(VIII) Simulink models
|
||||
% fotflib - Simulink blockset for FOTF Toolbox
|
||||
% fotf2sl - multivariable FOTF to Simulink block convertor
|
||||
% sfun_mls - S-function version of Mittag-Leffler function
|
||||
% slblocks - default Simulink description file
|
||||
% c9mvofuz - Simulink model for variable-order fuzzy PID control systems
|
||||
% c9mvofuz2 - Simulink model for variable-order fuzzy PID systems with variable delays
|
||||
% c10mpdm2 - Simulink model for multivariable PID control system
|
||||
% c10mpopt - Simulink model for multivariable parameter optimisation control systems
|
||||
% fPID_simu - Simulink model fractional-order PID controller for single-variable system
|
||||
%
|
||||
%(IX) Fractional-order and other controller design
|
||||
% c9mfpid - fractional-order PID controller design with equation solution techniques
|
||||
% c9mfpid_con - constraints in optimum FOPID design of FOPDT plants
|
||||
% c9mfpid_con1 - constraints in optimum FOPID design of FOIPDT plants
|
||||
% c9mfpid_con2 - constraints in optimum FOPID design of FO-FOPDT plants
|
||||
% c9mfpid_opt - objective function in optimum FOPID design of FOPDT plants
|
||||
% c9mfpid_opt1 - objective function in optimum FOPID design of FOIPDT plants
|
||||
% c9mfpid_opt2 - objective function in optimum FOPID design of FO-FOPDT plants
|
||||
% ffuz_param - S-function for parameter setting of fuzzy fractional-order PIDs
|
||||
% fopid - construct a \fPID{} controller from parameters
|
||||
% fpidfun - an example of objective function for optimum fractional-order PIDs
|
||||
% fpidfuns - objective function for fractional-order PID controller design
|
||||
% fpidtune - design of optimum fractional-order PID controllers
|
||||
% gershgorin - draw Nyquist plots with Gershgorin bands
|
||||
% get_fpidf - build string expression of the open-loop model
|
||||
% mfd2frd - convert MFD data into FRD data
|
||||
% optimfopid - GUI for optimum fractional-order PID design
|
||||
% optimpid - GUI for optimum integer-order PID design
|
||||
% pseuduag - pseudodiagonalisation of multivariable systems
|
||||
%
|
||||
%(X) Dedicated functions and models for the examples
|
||||
% c2exnls - constraint function of an example
|
||||
% c8mstep - Simulink model of a multivariable fractional-order system
|
||||
% c8mfpid1 - Simulink model of a fractional-order PID control system
|
||||
% c8mchaos - vectorised Simulink model for fractional-order Chua system
|
||||
% c8mchaosd - data input file for c8mchaos
|
||||
% c8mchua - MATLAB description of fractional-order Chua equations
|
||||
% c8mchuasim - Simulink model for fractional-order Chua circuit
|
||||
% c8mblk2,3,5 - three Simulink models of a linear fractional-order equation
|
||||
% c8mcaputo - complicated Simulink model for nonlinear FODE
|
||||
% c8mexp2 - simpler Simulink model for nonlinear Caputo equations
|
||||
% c8mexp2m - MATLAB description of nonlinear Caputo equation
|
||||
% c8mnlf1, c8mnlf2 - two different Simulink models of a nonlinear FODE
|
||||
% c8mexp1x - MATLAB function for describing nonlinear Caputo equations
|
||||
% c8nleq - MATLAB description of a nonlinear single-term Caputo equation
|
||||
% c8mlinc1 - Simulink model of a linear fractional-order Caputo equation
|
||||
% c9ef1-c9ef3 - criteria for optimum fractional-order PID controllers
|
||||
% c9mplant - Simulink model used for optimpid design
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
function [t,y]=INVLAP_new(G,t0,tn,N,H,tx,ux)
|
||||
% INVLAP_new - updated version of INVLAP for closed-loop system with any inputs
|
||||
%
|
||||
% [t,y]=INVLAP_new(G,t0,tn,N)
|
||||
% [t,y]=INVLAP_new(G,t0,tn,N,H)
|
||||
% [t,y]=INVLAP_new(G,t0,tn,N,H,u)
|
||||
% [t,y]=INVLAP_new(G,t0,tn,N,H,tx,ux)
|
||||
%
|
||||
% G - the string representation of the open-loop model
|
||||
% t0, tn, N - the time interval and number of points in the interval
|
||||
% H - the string representation of the feedback model
|
||||
% u - the function handle of the input signal
|
||||
% tx, ux - the samples of time and input signal
|
||||
% y, t - the output and time vectors
|
||||
|
||||
% Copyright (c) Dingyu Xue, Northeastern University, China
|
||||
% Last modified 28 March, 2017
|
||||
% Last modified 18 May, 2022
|
||||
arguments
|
||||
G, t0(1,1), tn(1,1) {mustBeGreaterThan(tn,t0)}
|
||||
N(1,1){mustBePositiveInteger}=100;
|
||||
H(1,1)=0; tx='1'; ux(1,:) {mustBeNumeric}=0;
|
||||
end
|
||||
G=add_dots(G); if ischar(H), H=add_dots(H); end
|
||||
if ischar(tx), tx=add_dots(tx); end
|
||||
a=6; ns=20; nd=19; t=linspace(t0,tn,N);
|
||||
if t0==0, t=[1e-6 t(2:N)]; end
|
||||
n=1:ns+1+nd; alfa=a+(n-1)*pi*1j; bet=-exp(a)*(-1).^n;
|
||||
n=1:nd; bet(1)=bet(1)/2;
|
||||
bdif=fliplr(cumsum(gamma(nd+1)./gamma(nd+2-n)./gamma(n)))./2^nd;
|
||||
bet(ns+2:ns+1+nd)=bet(ns+2:ns+1+nd).*bdif;
|
||||
if isnumeric(H), H=num2str(H); end
|
||||
for i=1:N
|
||||
tt=t(i); s=alfa/tt; bt=bet/tt; sG=eval(G); sH=eval(H);
|
||||
if ischar(tx), sU=eval(tx);
|
||||
else
|
||||
if isnumeric(tx)
|
||||
f=@(x)interp1(tx,ux,x,'spline').*exp(-s.*x);
|
||||
else, f=@(x)tx(x).*exp(-s.*x); end
|
||||
sU=integral(f,t0,tn,'ArrayValued',true);
|
||||
end
|
||||
btF=bt.*sG./(1+sG.*sH).*sU; y(i)=sum(real(btF));
|
||||
end, t=t(:); y=y(:);
|
||||
end
|
||||
% remove and add back dots uniformly
|
||||
function F=add_dots(F)
|
||||
F=strrep(strrep(strrep(F,'.*','*'),'./','/'),'.^','^');
|
||||
F=strrep(strrep(strrep(F,'*','.*'),'/','./'),'^','.^');
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
About FOTF Toolbox
|
||||
|
||||
(c) Professor Dingy\"u Xue, Northeastern University, Shenyang, China
|
||||
Email: xuedingyu@mail.neu.edu.cn
|
||||
Date of last modification, 09 May, 2022
|
||||
|
||||
This newly modified toolbox is written for the monograph, for details, please cite
|
||||
|
||||
@BOOK{bkXueDFOCS,
|
||||
Author = {Xue Dingy\"u},
|
||||
Address = {Berlin},
|
||||
Publisher = {de Gruyter Press},
|
||||
Title = {Fractional-order Control Systems - Fundamentals and Numerical Implementations},
|
||||
Year = {2017}
|
||||
}
|
||||
|
||||
For the new version, please cite
|
||||
|
||||
@BOOK{bkXueNew,
|
||||
Author = {Xue Dingy\"u, Bai Lu},
|
||||
Address = {Beijing},
|
||||
Publisher = {Tsinghua University Press},
|
||||
Title = {Fractional Calculus - Numerical Algorithms and Implementations},
|
||||
Year = {2022}
|
||||
}
|
||||
|
||||
For the full list of the toolbox, please check Contents.m
|
||||
|
||||
Please Note that
|
||||
If you are using MATLAB 2022a or newer, please disable the simulink2019 subfolders in your MATLAB path,
|
||||
while if you are using old versions, disable the subfolder Simulink in your MATLAB path.
|
||||
---------------------------------
|
||||
FOTF Toolbox, Release 2.0, 9 May, 2022
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
function y=bp3_fcn(u)
|
||||
y=u^(1.5-sqrt(2))*exp(u)*...
|
||||
ml_func([1,3-sqrt(2)],-u)./ml_func([1,1.5],-u);
|
||||
end
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue