You are on page 1of 30

# Chapter 13 m-files

function m = oe(varargin) %OE Computes the prediction error estimate of an Output Error model. % M = OE(Z,[nb nf nk]) or M = OE(Z,'nb',nb,'nf',nf,'nk',nk) % M : returns the estimated model in an IDPOLY object format % along with estimated covariances and structure information. % For the exact format of M see also help IDPOLY. % Z : The estimation data in IDDATA object format. See help IDDATA % [nb nf nk] are the orders and delays of the Output Error model % y(t) = [B(q)/F(q)] u(t-nk) + e(t) % For multi-input data, nb, nf and nk are row vectors with length equal to the number of input channels. % An alternative syntax is M = OE(Z,Mi), where Mi is an estimated model or created by IDPOLY. % The minimization is then initialized at the parameters given in Mi. % By M = OE(Z,nn,Property_1,Value_1, ...., Property_n,Value_n) % all properties associated with the model structure and the algorithm can be affected. See help IDPOLY for a list % of Property/Value pairs. % Copyright 1986-2001 The MathWorks, Inc. % $Revision: 1.13$ $Date: 2001/04/06 14:22:28$ try [mdum,z] = pemdecod('oe',varargin{:}); catch error(lasterr) end err = 0; if isempty(pvget(z,'Name')) z=pvset(z,'Name',inputname(1)); end if isa(mdum,'idpoly') nd = pvget(mdum,'nd'); nc = pvget(mdum,'nc'); na = pvget(mdum,'na'); if sum([nd na nc])~=0 err = 1; end else err = 1; end if err error('This is not an OE model.') end % $$fixp = pvget(mdum,'FixedParameter');$$$if ~isempty(fixp) $$% warning(sprintf(['To fix a parameter, first define a nominal % model.',...$$$ '\nNote that mnemonic Parameter Names can be set by % SETPNAME.'])) $$end try m = pem(z,mdum); catch error(lasterr) end es = pvget(m,'EstimationInfo'); es.Method = 'OE'; m = pvset(m,'EstimationInfo',es); function m = bj(varargin) %BJ Computes the prediction error estimate of a Box-Jenkins model. % M = BJ(Z,[nb nc nd nf nk]) or % M = BJ(Z,'nb',nb,'nc',nc,'nd',nd,'nf',nf,'nk',nk) % (Omitted orders are taken as zero, and the argument order is arbitrary) % M : returns the estimated model in an IDPOLY object format % along with estimated covariances and structure information. % For the exact format of M see also help IDPOLY. % Z : The estimation data in IDDATA object format. See help IDDATA % [nb nc nd nf nk] are the orders and delays of the Box-Jenkins model % y(t) = [B(q)/F(q)] u(t-nk) + [C(q)/D(q)]e(t) % An alternative is M = BJ(Z,Mi), where % Mi is an estimated model or created by IDPOLY. % The minimization is then initialized at the parameters given in Mi. % By M = BJ(Z,nn,Property_1,Value_1, ...., Property_n,Value_n) % all properties associated with the model structure and the algorithm % can be affected. See HELP IDPOLY and IDPROPS ALGORITHM for a list of % Property/Value pairs. % Copyright 1986-2001 The MathWorks, Inc. % Revision: 1.11  Date: 2001/04/06 14:22:25  try [mdum,z] = pemdecod('bj',varargin{:}); catch error(lasterr) end err = 0; if isempty(pvget(z,'Name')) z=pvset(z,'Name',inputname(1)); end if isa(mdum,'idpoly') if pvget(mdum,'na')~=0 error('This is not a BJ model.') end end %$$$fixp = pvget(mdum,'FixedParameter'); % $$if ~isempty(fixp) %$$$ warning(sprintf(['To fix a parameter, first define a nominal model.',... % $$'\nNote that mnemonic Parameter Names can be set by SETPNAME.'])) %$$$end try m = pem(z,mdum); catch error(lasterr) end es = pvget(m,'EstimationInfo'); es.Method = 'BJ'; m = pvset(m,'EstimationInfo',es); % function G=pfract(Num,Den) % The command pfract(Num,Den)generates the partial fractions % of a ratio of polynomials with numerator Num and denominator Den. % The poles cannot be repeated but may be real or complex. % The output will be the partial fractions of Num/Den plus any nonzero % remainder if the numerator order is equal to the denominator order. % Note, the partial fraction outputs erroneously refer to input 1, % input 2, etc; ignore these comments. function G=pfract(Num,Den) n=length(Den)-1; [RR,PP,K]=residue(Num,Den); if K~=0 % Check to see if there is a remainder. 'Remainder', K end m=1; q=1; P(n)=PP(n); R(n)=RR(n); while m<=n P(q)=PP(m); R(q)=RR(m); q=q+1; if imag(PP(m))~= 0 % Check to see if this pole is complex. m=m+2; else m=m+1; end end qn=q-1; I=1; while I<=qn if imag(P(I))==0 % Check to see if this pole is real. G(I)=tf(R(I),[1 -P(I)]); % Use this for the partial fraction if the pole is real. I=I+1; else % Use this for the partial fraction if the pole is complex. G(I)=tf([2*real(R(I)) -2*(real(R(I))*real(P(I))+imag(R(I))*imag(P(I)))],[1 -2*real(P(I)) abs(P(I))^2]); I=I+1; end end function [f,t] = PulseSeries(T,m,F,N,NumPPP) % T=pulse width, sec. % m is an integer % mT=time between pulses, sec. (period of function) % N=number of pulses % NumPPP=number of points per pulse dt=T/NumPPP;% time increment, sec. t=0:dt:T*m*N-2*dt;% time value for L=1:NumPPP f(L)=F; end for L=NumPPP+1:m*NumPPP-1 f(L)=0; end for k=1:N-1 for L=(m*k)*NumPPP:(m*k+1)*NumPPP f(L)=F; end for L=(m*k+1)*NumPPP+1:(m*(k+1))*NumPPP-1 f(L)=0; end end %length(t) %length(f) plot(t,f,'r','Linewidth',4) xlabel('time, sec.') ylabel('pulse function amplitude') axis([0 N*m*T+T/2 0 1.1*F]) end % Obtaining lower order transfer function approximations %Transfer approximation program %[numa,dena]=tfapprox(num,den,dorder,wmin,wmax) %Generates a transfer function approximation with numerator "numa" and %denominator "dena" of desired order "dorder" %over the frequency range of wmin rad/sec to wmax rad/sec starting with %a transfer function with numerator "num" and denominator "den". %The approximation is achieved by curve fitting the original transfer %function frequency response over the specified frequency range. %file name "tfapprox.m" %num=numerator polynomial of original transfer function %den=denominator polynomial of original transfer function %wmin=minimum frequency (rad/sec) for a good approximation %wmax=maximum frequency (rad/sec) for a good approximation %numa=numerator polynomial of the transfer function approximation %dena=denominator polynomial of the transfer function approximation %dorder=desired order of the transfer function approximation function [numa,dena]=tfapprox(num,den,dorder,wmin,wmax) warning off norder=dorder-1; Gorig=tf(num,den); ## [mag,phase,w]=bode(Gorig,{wmin,wmax}); H=freqs(num,den,w); [numa,dena]=invfreqs(H,w,norder,dorder); Gapprox=tf(numa,dena) wm=2*wmax; bode(Gorig,b,Gapprox,r --,{wmin,wm}) % function [w,wc]=genfreqs(Wmin,Wmax,n) % This m-file generates n frequency values per decade w % over the frequency range of Wmin to Wmax rad/sec. % Also produced is an expanded set of frequencies wc % for purposes of comparison plotting. function [w,wc]=genfreqs(Wmin,Wmax,n) a=log10(Wmin); if a<0 wmin=10^(fix(a)-0.9999999); else wmin=10^(fix(a)); end b=log10(Wmax); wmax=10^fix(b+.99999999); nd=fix(log10(wmax)-log10(wmin)+0.9999999); for J=1:nd w1=wmin*10^(J-1); for I=1:n w(I+(J-1)*n)=w1+10*w1*(I-1)/(n+1); if w(I+(J-1)*n)>=Wmax break else end end end for J=1:nd w1=wmin*10^(J-1); for I=1:n wc(I+(J-1)*n)=w1+10*w1*(I-1)/(n+1); end end % [NGCoshOverZSinh,GCoshOverZSinh] = CoshOverZSinh(Den,Beta,Mu,d,L ); % Generates the normaolize and un-normalized coefficients of Cosh/ZSinh % Nu, absolute viscosity, Ns/m^2 % Den, density, kg/m^3 % Beta, bulk modulus, N/m^2 % Mu, kinematic viscosity, m^2/s % d, line diameter, m % L, line length, m function [NGCoshOverZSinh,GCoshOverZSinh] = CoshOverZSinh( Den,Beta,Mu,d,L ) r=d/2; Nu=Mu/Den; Dn=Nu*L*sqrt(Den/Beta)/r^2; if Dn>0.5 Dn 'Dn is greater than 0.5 which is outside the range for the computed coefficients' else if Dn<0.001 Dn 'Dn is less than 0.001 which is outside the range for the computed coefficients' else RL=128*Mu*L/(pi*d^4); Wv=Nu/r^2 ; x=log10(Dn); if Dn<=0.2 a4=10^(4.1973*x-1.2769); a3=10^(-0.6668*x^4-4.6577*x^3-10.748*x^2-5.9087*x-3.502); a2=10^(0.0512*x^2+2.2694*x+0.0196); a1=10^(-0.4491*x^4-3.1287*x^3-6.9656*x^2-4.1552*x-1.3524); b5=10^(-0.2055*x^3-1.2543*x^2+1.6673*x-4.5988); b4=10^(0.0245*x^3+0.2859*x^2+4.5619*x-1.2772); b3=10^(0.0044*x^2+2.0614*x-1.5418); b2=10^(0.0003*x^3+0.0947*x^2+2.0924*x-0.3044); b1=10^(0.0239*x-0.7318); else a4=10^(-185.48*x^4-373.61*x^3-265.3*x^2-73.758*x-9.4321); a3=10^(-27.067*x^3-32.913*x^2-7.6768*x-1.7184); a2=10^(-7.688*x^3-5.1228*x^2+3.1851*x+0.5424); a1=10^(-16.951*x^3-21.961*x^2-6.4264*x-0.4755); b5=10^(-695.57*x^3-891.59*x^2-369.41*x-67.279); b4=10^(-110.54*x^4-225.98*x^3-161.15*x^2-43.489*x-6.8694); b3=10^(-130.36*x^4-298.6*x^3-234.22*x^2-71.612*x-9.5037); b2=10^(-39.378*x^4-85.215*x^3-62.461*x^2-16.246*x-2.3073); b1=10^(-30.848*x^3-37.671*x^2-12.493*x-1.6223); end fprintf('Normalized Transfer Function, RLCosh/[ZSinh]') NGCoshOverZSinh=tf([a4 a3 a2 a1 1],[b5 b4 b3 b2 b1 1]) NGCoshOverZSinhzpk=zpk(NGCoshOverZSinh) [Normalized_poles]=roots([b5 b4 b3 b2 b1 1]) [y,t]=step(NGCoshOverZSinh); plot(t,y,'r','LineWidth',2) xlabel('Normalized Time, \omega_v t') ylabel('R_LCosh\Gamma/(Zsinh\Gamma)') title('Normalized Step Response') figure fprintf('Un-normalized transfer function, cosh/Zsinh') GCoshOverZSinh=tf([a4/Wv^4 a3/Wv^3 a2/Wv^2 a1/Wv 1]/RL, [b5/Wv^5 b4/Wv^4 b3/Wv^3 b2/Wv^2 b1/Wv 1]) GCoshOverZSinhzpk=zpk(GCoshOverZSinh) [Poles]=roots([b5/Wv^5 b4/Wv^4 b3/Wv^3 b2/Wv^2 b1/Wv 1]) [Y,T]=step(GCoshOverZSinh); plot(T,Y,'k','Linewidth',2) xlabel(' Time, seconds') ylabel('cosh\Gamma/Zsinh\Gamma, (m^3/s)/(N/m^2)') title('Step Response, \Delta Q_a/(\Delta P_a) or -\Delta Q_b/(\Delta P_b) ') end end end % [NGZCoshOverSinh,GZCoshOverSinh] = ZCoshOverSinh(Den,Beta,Mu,d,L ); % Generates the normaolize and un-normalized coefficients of ZCosh/Sinh % Nu, absolute viscosity, Ns/m^2 % Den, density, kg/m^3 % Beta, bulk modulus, N/m^2 % Mu, kinematic viscosity, m^2/s % d, line diameter, m % L, line length, m function [NGZCoshOverSinh,GZCoshOverSinh] = ZCoshOverSinh(Den,Beta,Mu,d,L ) format shortg r=d/2 Nu=Mu/Den; Dn=Nu*L*sqrt(Den/Beta)/r^2 RL=128*Mu*L/(pi*d^4) Wv=Nu/r^2 a4=0.0891*Dn^4.2889 a3=0.4371*Dn^3.8444 a2=1.2967*Dn^2.1956 a1=2.5051*Dn^1.7908 b5=3e-18*Dn^4.0929 b4=0.0035*Dn^4.038 b3=0.1064*Dn^3.8022 b2=0.2497*Dn^2.1196 b1=1.2308*Dn^1.7072 fprintf('Normalized Transfer Function, 8Dn^2ZCosh/[RLSinh]') NGZCoshOverSinh=tf([a4 a3 a2 a1 1],[b5 b4 b3 b2 b1 1 0]) NGZCoshOverSinhzpk=zpk(NGZCoshOverSinh) [y,t]=impulse(NGZCoshOverSinh); plot(t,y,'r','LineWidth',2) xlabel('Normalized Time, \omega_v t') ylabel('8D_n^2Zcosh\Gamma/(R_Lsinh\Gamma)') title('Normalized Impulse Response') [normalized_poles]=roots([b5 b4 b3 b2 b1 1 0]) figure fprintf('Un-Normalized Transfer Function, ZCosh/Sinh') GZCoshOverSinh=tf([a4/Wv^4 a3/Wv^3 a2/Wv^2 a1/Wv 1]*RL/(8*Dn^2), [b5/Wv^5 b4/Wv^5 b3/Wv^4 b2/Wv^3 b1/Wv^2 1/Wv 0]) GZCoshOverSinhzpk=zpk(GZCoshOverSinh) [Poles]=roots([b5/Wv^5 b4/Wv^5 b3/Wv^4 b2/Wv^3 b1/Wv^2 1/Wv 0]) [Y,T]=impulse(GZCoshOverSinh); plot(T,Y,'k','Linewidth',2) xlabel(' Time, seconds') ylabel('Zcosh\Gamma/(sinh\Gamma), (N/m^2)/(m^3/s)') title('Impulse Response, \Delta P_a/(\Delta Q_a) or -\Delta P_b/(\Delta Q_b)') % [NGOneOverZSinh,GOneOverZSinh] = OneOverZSinh(Den,Beta,Mu,d,L ); % Generates the normaolize and un-normalized coefficients of 1/ZSinh % Nu, absolute viscosity, Ns/m^2 % Den, density, kg/m^3 % Beta, bulk modulus, N/m^2 % Mu, kinematic viscosity, m^2/s % d, line diameter, m % L, line length, m function [NGOneOverZSinh,GOneOverZSinh] = OneOverZSinh(Den,Beta,Mu,d,L ) r=d/2; Nu=Mu/Den; Dn=Nu*L*sqrt(Den/Beta)/r^2; if Dn>0.5 Dn 'Dn is greater than 0.5 which is outside the range for the computed coefficients' else if Dn<0.001 Dn 'Dn is less than 0.001 which is outside the range for the computed coefficients' else RL=128*Mu*L/(pi*d^4); Wv=Nu/r^2; if Dn<.01 a2=-0.2188*Dn^2+0.0002*Dn-3e-7; else a2=94.422*Dn^6-130.8*Dn^5+64.269*Dn^4-13.173*Dn^3+1.1493*Dn^2-0.0516*Dn+0.0005; end if Dn<=0.0025 a1=33333*Dn^3-243.67*Dn^2+0.6888*Dn-0.0001; else if Dn<=0.006 a1=20483*Dn^3-246.2*Dn^2+1.0478*Dn-0.0013; else if Dn<=0.01 a1=-38967*Dn^3+1105.4*Dn^2-10.241*Dn+0.0316; else if Dn<=0.1 a1=-703.44*Dn^4+154.26*Dn^3-11.214*Dn^2+0.2657*Dn-0.0009; else a1=-222.79*Dn^5+303.34*Dn^4-146.95*Dn^3+29.884*Dn^2-2.8801*Dn+0.1064; end end end end if Dn<0.25 b3=0.0222*Dn^2.0397; else b3=0.0474*Dn^2-0.0306*Dn+0.0057; end b2=0.1293*Dn^1.6414; if Dn <=0.01 b1=0.164; else if Dn<=0.1 b1=0.4857*Dn^2+0.1019*Dn+0.1641; else b1=-337.64*Dn^5+460.64*Dn^4-225.52*Dn^3+48.908*Dn^2-4.7147*Dn+0.3459 ; end end fprintf('Normalized Transfer Function, RL/[ZSinh]') NGOneOverZSinh=tf([a2 a1 1],[b3 b2 b1 1]) NGOneOverZSinhzpk=zpk(NGOneOverZSinh) [Normalized_poles]=roots([b3 b2 b1 1]) [y,t]=step(NGOneOverZSinh); plot(t,y,'r','LineWidth',2) xlabel('Normalized Time, \omega_v t') ylabel('R_L/(Zsinh\Gamma)') title('Normalized Step Response') figure fprintf('Un-normalized transfer function, 1/Zsinh') GOneOverZSinh=tf([a2/Wv^2 a1/Wv 1]/RL,[b3/Wv^3 b2/Wv^2 b1/Wv 1]) GOneOverZSinhzpk=zpk(GOneOverZSinh) [Poles]=roots([b3/Wv^3 b2/Wv^2 b1/Wv 1]) [Y,T]=step(GOneOverZSinh); plot(T,Y,'k','Linewidth',2) xlabel(' Time, seconds') ylabel('1/Zsinh\Gamma, (m^3/s)/(N/m^2)') title('Step Response, \Delta Q_b/(\Delta P_a) or -\Delta Q_a/(\Delta P_b) ') end end end % [NGZoverSinh,GZoverSinh] = ZoverSinh(Den,Beta,Mu,d,L ); % Generates the normaolize and un-normalized coefficients of Z/sinh(Gamma) % Nu, absolute viscosity, Ns/m^2 % Den, density, kg/m^3 % Beta, bulk modulus, N/m^2 % Mu, kinematic viscosity, m^2/s % d, line diameter, m % L, line length, m function [NGZoverSinh,GZoverSinh] = ZoverSinh(Den,Beta,Mu,d,L ) format shortg r=d/2; Nu=Mu/Den; Dn=Nu*L*sqrt(Den/Beta)/r^2% Dissipation number RL=128*Mu*L/(pi*d^4)% Steady state flow resistance Wv=Nu/r^2% Normalizing frequency, rad/sec if Dn>0.5 Dn 'Dn is greater than 0.5 which is outside the range for the computed coefficients' else if Dn<0.001 Dn 'Dn is less than 0.001 which is outside the range for the computed coefficients' else if Dn<=0.2 a3=0.0454*Dn^3.5523; a2=-0.1012*Dn^2.0585; else a3=-0.2167*Dn^4+0.2569*Dn^3-0.1077*Dn^2+0.0225*Dn; a2=-0.8047*Dn^4+1.7023*Dn^3-1.005*Dn^2+0.2079*Dn-0.0173; end if Dn<=0.1 a1=-5436.6*Dn^5+1213.3*Dn^4-91.209*Dn^3+2.9331*Dn^2-.0036*Dn+3e-5; else a1=1.1585*Dn^4-1.8786*Dn^3+0.0199*Dn^2+0.1218*Dn-0.0067; end b4=0.0047*Dn^4.0812; b3=0.035*Dn^3.6798; b2=0.1912*Dn^2.0661; b1=0.6685*Dn^1.6288; fprintf('Normalized Transfer Function, 8Dn^2Z/[RLSinh]') NGZoverSinh=tf([a3 a2 a1 1],[b4 b3 b2 b1 1 0]) NGZoverSinhzpk=zpk(NGZoverSinh) [Normalized_poles]=roots([b4 b3 b2 b1 1 0]) [y,t]=impulse(NGZoverSinh); plot(t,y,'r','LineWidth',2) xlabel('Normalized Time, \omega_v t') ylabel('8D_n^2Z/(R_Lsinh\Gamma)') title('Normalized Impulse Response') figure fprintf('Un-normalized transfer function, Z/Sinh') GZoverSinh=tf([a3/Wv^3 a2/Wv^2 a1/Wv 1]*RL/(8*Dn^2),[b4/Wv^5 b3/Wv^4 b2/Wv^3 b1/Wv^2 1/Wv 0]) GZoverSinhzpk=zpk(GZoverSinh) [Poles]=roots([b4/Wv^5 b3/Wv^4 b2/Wv^3 b1/Wv^2 1/Wv 0]) [Y,T]=impulse(GZoverSinh); plot(T,Y,'k','Linewidth',2) xlabel(' Time, seconds') ylabel('Z/sinh\Gamma, (N/m^2)/(m^3/s)') title('Impulse Response, \Delta P_b/(\Delta Q_a) or -\Delta P_a/(\Delta Q_b)') end end % function[PSD,f]=comppsd(Y,N,H) % This function generates N/2 unique values for the % PSD of Y(t) at a frequency resolution of 1/NH.The % zero frequency value represents the mean value % squared times 2NH. Note, the PSD is plotted for % all values of frequency. After generating the % plot, for better resolution, you can change % the scales of the plot using the command % axis([XMIN XMAX YMIN YMAX]). function[PSD,f]=comppsd(Y,N,H) [Y]=fft(Y); NO2=N/2; for m=1:NO2 PSD(m)=2*H*abs(Y(m))^2/N; end f=0:1/(N*H):(N-2)/(2*N*H); plot(f,PSD) xlabel('Frequency (Hertz)') ylabel('PSD (units of y^2)/(cycles/sec)') return 10 % function[Y,t]=rinput(N,H) % Generates N points in time Y(t) at a time interval of H with zero mean. % N must be a power of 2! The N points will be generated % so as to have a desired one-sided PSD defined in the function % dpsd(f). f is the frequency in Hertz. The frequency resolution % will be 1/NH. The smallest frequency will be 0 Hz and the % largest frequency will be 1/2H Hz. Note, the frequency 1/2H % is referred to as the folding frequency. % If you want this m-file to automatically plot y(t) and the desired PSD, % you need to remove the % signs on the comments at the end of this m-file. function[Y,t]=rinput(N,H) no2=N/2; % Step 1: Generate frequencies and PSD values at each frequency f=0:1/(N*H):1/(2*H);%Note, the first frequency is zero but we don't %compute GY at f=0 to avoid potential computational problems. GY at f=0 %should be zero for a zero mean process. GY(1)=0; for m1=2:no2+1; GY(m1)=dpsd(f(m1)); end % Step 1: Generate N/2 random phase angles with uniform density % between 0 and 2pi TH=random('unif',0,2*pi,no2,1); % Step 2: Generate the appropriate amplitude at each frequency using % the random phase angles. for m=2:no2; C=sqrt(GY(m)*N*H/2); CTH=cos(TH(m-1))*C; STH=sin(TH(m-1))*C; Y(m)=CTH+j*STH; k=N+2-m; Y(k)=CTH-j*STH; end % Step 3: Make sure the N/2+1 value is real so that the negative frequency % values will equal the positive frequency values. no2p1=no2+1; C=sqrt(GY(no2p1)*N*H/2); CTH=cos(TH(no2))*C; Y(no2p1)=CTH+j*0.e0; % Make sure the zero freq. value is zero to achieve a zero mean time series. Y(1)=0.e0+j*0.e0; % Generate Y(t), the inverse trans. of the N Fourier Transform values Y(f). [Y]=ifft(Y) % Rescale to get the correct time series corresponding to this desired PSD. for m=1:N; Y(m)=real(Y(m)/H); end % Plot the PSD and time series t=0:H:(N-1)*H; plot(t,Y) xlabel('Time (sec)') ylabel('Output Variable Corresponding to Desired PSD') figure plot(f,GY) xlabel('Frequency (Hertz)') ylabel('Desired PSD') 11 % function [GYT,f]=TheorPSD(G,N,H,M) % Given a symbolic transfer function G in terms of the % symbolic variable s, the number of data points N (power of 2) % and the time incriment H. M is the magnitude of the white noise % PSD corresponding to the input to the transfer function. % To automatically get the plot of the PSD, remove "%" in the % comment statements at the end of this m-file. function [GYT,f]=TheorPSD(G,N,H,M) syms s %G=(2.4*s+9)/(s^2+2.4*s+9); for m=1:N/2 Z(m)=subs(G,s,j*2*pi*(m-1)/(N*H)); GYT(m)=M*abs(Z(m))^2; f=0:1/(N*H):(N-2)/(2*N*H); end plot(f,GYT) xlabel('Frequency (Hertz)') ylabel('Theroetical PSD') % function [GYS]=psdsmooth(N,H,gd,GYT,f,m) % psdsmooth generates a smoothed plot of the PSD, GYS, at % the frequencies f in Hertz, of the output from the % discrete system gd. N is the number of simulation points % which must be a power of 2. H is the time step in seconds. % GYT is the theoretical PSD that hopefully the smoothed PSD % will converge to as the number, m, of terms averaged, increases. function [GYS]=psdsmooth(N,H,gd,GYT,f,m) [u]=rinput(N,H); [y]=lsim(gd,u); [GY,f]=comppsd(y,N,H); GYS=GY/m; for n=2:m [u]=rinput(N,H); [y]=lsim(gd,u); [GY,f]=comppsd(y,N,H); GYS=GYS+GY/m; end plot(f,GYS,f,GYT,'r--') xlabel('Frequency (Hertz)') ylabel('Power Spectral Density') legend('Smoothed PSD','Theoretical PSD') 12 %function [Gxx,Gyy,Gxy,Mag,Phase,CohF,FRF,f]=csdf(N,x,y,H,Ns) %For N data points of x(kH) and y(kH), csdf computes smoothed %estimates of the magnitude (Mag), of the frequency response %function relating output y to input x, the angle (Phase) of the %frequency response function, FRF(f), and the coherence function (CohF) %representing the correlation between x and y. The frequency f %is in cycles/sec. %Note, the data points should be zero mean to avoid Delta functions %at zero frequency. Thus, the spectral density functions should be %zero at zero frequency which will cause problems with computing %the zero frequency transfer function data. To avoid these computation %problems, as shown below, the zero frequency transfer function %values are artifically set equal to the values at the first non%zero frequency value. %The results are smoothed by averaging Ns neighboring values. function [Gxx,Gyy,Gxy,Mag,Phase,CohF,FRF,f]=csdf(N,x,y,H,Ns) N2=N/2;X=fft(x);Y=fft(y); if Ns==1 f=0:1/(N*H):(N-2)/(2*N*H); for m=2:N2 Gxy(m)=2*H*conj(X(m))*Y(m)/N; Gxx(m)=2*H*abs(X(m))^2/N; Gyy(m)=2*H*abs(Y(m))^2/N; FRF(m)=Gxy(m)/Gxx(m); Mag(m)=abs(Gxy(m))/Gxx(m); Phase(m)=atan2(imag(Gxy(m)),real(Gxy(m)))*180/pi; CohF(m)=abs(Gxy(m))^2/(Gxx(m)*Gyy(m)); end Gxy(1)=2*H*conj(X(1))*Y(1)/N; Gxx(1)=2*H*abs(X(1))^2/N; Gyy(1)=2*H*abs(Y(1))^2/N; FRF(1)=FRF(2); Mag(1)=Mag(2); Phase(1)=Phase(2); CohF(1)=CohF(2); else %compute the PSD estimates and smooth Ns neighboring values NQ=fix((N2-1)/Ns)*Ns+1; NR=N2-NQ; m=1; for I=2:Ns:NQ m=m+1; IQ1=I+Ns-1; gxy=complex(0,0); gxx=0; gyy=0; for K=I:IQ1 gxy=2*H*conj(X(K))*Y(K)/(N*Ns)+gxy; gxx=2*H*abs(X(K))^2/(Ns*N)+gxx; gyy=2*H*abs(Y(K))^2/(Ns*N)+gyy; end Gxx(m)=gxx; Gyy(m)=gyy; Gxy(m)=gxy; f(m)=(I+fix(Ns/2)-1)/(N*H);%compute the frequencies FRF(m)=gxy/gxx;%compute the frequency response function Mag(m)=abs(gxy)/gxx;%compute magnitude of freq. response function Phase(m)=atan2(imag(gxy),real(gxy))*180/pi;%phase of freq. resp. fun. CohF(m)=abs(gxy)^2/(gxx*gyy);%compute coherance function end %Compute the zero frequency values. Gxy(1)=2*H*conj(X(1))*Y(1)/N;Gxx(1)=2*H*abs(X(1))^2/N;Gyy(1)=2*H*abs(Y(1))^2/N; FRF(1)=FRF(2);Mag(1)=Mag(2);Phase(1)=Phase(2);CohF(1)=CohF(2); end 13 function [Num,Den]=frfcfit(frf,f,fmax,n) % function [num,den]=frfcfit(frf,f,fmax,n) % This program takes frequency response function complex values frf % at frequencies f (cycles/unit time) and curve fits this input data % out to maximum frequency fmax to get a transfer function of order n. % The output is the numerator and denominator polynomials Num and Den. warning off nn=n-1; Lf=length(f); for k=1:Lf-1 if f(k+1)<fmax w(k)=2*pi*f(k+1); FRF(k)=frf(k+1); else k=Lf; end end [Num,Den]=invfreqs(FRF,w,nn,n); H=freqs(Num,Den,w); MH=abs(H);Mfrf=abs(FRF); PH=phase(H)*180/pi;Pfrf=phase(FRF)*180/pi; ff=w/(2*pi); plot(ff,MH,ff,Mfrf) figure plot(ff,PH,ff,Pfrf) % function [MSV]=msv(G,f1,f2) % Generates the mean square value, MSV, of a variable with symbolic % transfer function G assuming the input to this transfer function % is a one sided unity band limited white noise from f1 hertz to f2 hertz. % A typical value of f1 is zero and a typical value for f2 is 1/2h where % h is the sampling interval in seconds. function [MSV]=msv(G,f1,f2) syms s f Gms=subs(G,s,-s); GGms=G*Gms; GGmsf=subs(GGms,s,j*2*pi*f); MSV=double(int(GGmsf,f,f1,f2)); 14 function r = random(name,a,b,c,d,e) %RANDOM Generates random numbers from a named distribution. % The appropriate syntax depends on the number of parameters in % the distribution you are using: % % R = RANDOM(NAME,A,M,N) returns an M-by-N array of random % numbers from the named distribution with parameter A. % R = RANDOM(NAME,A,B,M,N) returns an M-by-N array of random % numbers from the named distribution with parameters A, and B. % R = RANDOM(NAME,A,B,C,M,N) returns an M-by-N array of random % numbers from the named distribution with parameters A, B, and C. % % The name can be: 'beta' or 'Beta', 'bino' or 'Binomial', % 'chi2' or 'Chisquare', 'exp' or 'Exponential', 'f' or 'F', % 'gam' or 'Gamma', 'geo' or 'Geometric', % 'hyge' or 'Hypergeometric', 'logn' or 'Lognormal', % 'nbin' or 'Negative Binomial', 'ncf' or 'Noncentral F', % 'nct' or 'Noncentral t', 'ncx2' or 'Noncentral Chi-square', % 'norm' or 'Normal', 'poiss' or 'Poisson', 'rayl' or 'Rayleigh', % 't' or 'T', 'unif' or 'Uniform', 'unid' or 'Discrete Uniform', % 'weib' or 'Weibull'. % % Both M and N are integers. Alternatively you can omit N and % specify M as a vector of two integers. If you omit both M and % N, then R is a 1-by-1 array. % RANDOM calls many specialized routines that do the calculations. % D. Zwillinger 5-91, B. Jones 10-92 % Copyright 1993-2000 The MathWorks, Inc. %$Revision: 2.11 Date: 2000/05/26 18:53:31 $if ~isstr(name), error('The first argument must be the name of a probability distribution.'); end % define the default parameter values (i.e., array dimensions) % Determine, and call, the appropriate subroutine if strcmp(deblank(name),'beta') | strcmp(deblank(name),'Beta') if nargin == 3 r = betarnd(a,b); elseif nargin == 4 & (length(c)>1) r = betarnd(a,b,c); elseif nargin == 5 r = betarnd(a,b,c,d); else error('BETARND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'bino') | strcmp(deblank(name),'Binomial') if nargin == 3 r = binornd(a,b); elseif nargin == 4 & (length(c)>1) r = binornd(a,b,c); elseif nargin == 5 r = binornd(a,b,c,d); else error('BINORND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'chi2') | strcmp(deblank(name),'Chisquare') if nargin == 2 r = chi2rnd(a); elseif nargin == 3 & (length(b)>1) r = chi2rnd(a,b); elseif nargin == 4 15 r = chi2rnd(a,b,c); else error('CHI2RND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'exp') | strcmp(deblank(name),'Exponential') if nargin == 2 r = exprnd(a); elseif nargin == 3 & (length(b)>1) r = exprnd(a,b); elseif nargin == 4 r = exprnd(a,b,c); else error('EXPRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'f') | strcmp(deblank(name),'F') if nargin == 3 r = frnd(a,b); elseif nargin == 4 & (length(c)>1) r = frnd(a,b,c); elseif nargin == 5 r = frnd(a,b,c,d); else error('FRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'gam') | strcmp(deblank(name),'Gamma') if nargin == 3 r = gamrnd(a,b); elseif nargin == 4 & (length(c)>1) r = gamrnd(a,b,c); elseif nargin == 5 r = gamrnd(a,b,c,d); else error('GAMRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'geo') | strcmp(deblank(name),'Geometric') if nargin == 2 r = geornd(a); elseif nargin == 3 & (length(b)>1) r = geornd(a,b); elseif nargin == 4 r = geornd(a,b,c); else error('GEORND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'hyge') | strcmp(deblank(name),'Hypergeometric') if nargin == 4 r = hygernd(a,b,c); elseif nargin == 5 & (length(d)>1) r = hygernd(a,b,c,d); elseif nargin == 6 r = hygernd(a,b,c,d,e); else error('HYGERND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'logn') | strcmp(deblank(name),'Lognormal'), if nargin == 3 r = lognrnd(a,b); elseif nargin == 4 & (length(c)>1) r = lognrnd(a,b,c); elseif nargin == 5 r = lognrnd(a,b,c,d); else error('LOGNRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'nbin') | strcmp(deblank(name),'Negative Binomial'), 16 if nargin == 3 r = nbinrnd(a,b); elseif nargin == 4 & (length(c)>1) r = nbinrnd(a,b,c); elseif nargin == 5 r = nbinrnd(a,b,c,d); else error('NBINRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'ncf') | strcmp(deblank(name),'Noncentral F'), if nargin == 4 r = ncfrnd(a,b,c); elseif nargin == 5 & (length(d)>1) r = ncfrnd(a,b,c,d); elseif nargin == 6 r = ncfrnd(a,b,c,d,e); else error('NCFRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'nct') | strcmp(deblank(name),'Noncentral T'), if nargin == 3 r = nctrnd(a,b); elseif nargin == 4 & (length(c)>1) r = nctrnd(a,b,c); elseif nargin == 5 r = nctrnd(a,b,c,d); else error('NCTRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'ncx2')| strcmp(deblank(name),'Noncentral Chi-square'), if nargin == 3 r = ncx2rnd(a,b); elseif nargin == 4 & (length(c)>1) r = ncx2rnd(a,b,c); elseif nargin == 5 r = ncx2rnd(a,b,c,d); else error('NCX2RND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'norm') | strcmp(deblank(name),'Normal'), if nargin == 3 r = normrnd(a,b); elseif nargin == 4 & (length(c)>1) r = normrnd(a,b,c); elseif nargin == 5 r = normrnd(a,b,c,d); else error('NORMRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'poiss') | strcmp(deblank(name),'Poisson'), if nargin == 2 r = poissrnd(a); elseif nargin == 3 & (length(b)>1) r = poissrnd(a,b); elseif nargin == 4 r = poissrnd(a,b,c); else error('POISSRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'rayl') | strcmp(deblank(name),'Rayleigh'), if nargin == 2 r = raylrnd(a); elseif nargin == 3 & (length(b)>1) r = raylrnd(a,b); elseif nargin == 4 r = raylrnd(a,b,c); 17 else error('RAYLRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'t') | strcmp(deblank(name),'T') if nargin == 2 r = trnd(a); elseif nargin == 3 & (length(b)>1) r = trnd(a,b); elseif nargin == 4 r = trnd(a,b,c); else error('TRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'unid') | strcmp(deblank(name),'Discrete Uniform') if nargin == 2 r = unidrnd(a); elseif nargin == 3 & (length(b)>1) r = unidrnd(a,b); elseif nargin == 4 r = unidrnd(a,b,c); else error('UNIDRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'unif') | strcmp(deblank(name),'Uniform'), if nargin == 3 r = unifrnd(a,b); elseif nargin == 4 & (length(c)>1) r = unifrnd(a,b,c); elseif nargin == 5 r = unifrnd(a,b,c,d); else error('UNIFRND called with incorrect number of inputs.'); end elseif strcmp(deblank(name),'weib') | strcmp(deblank(name),'Weibull') if nargin == 3 r = weibrnd(a,b); elseif nargin == 4 & (length(c)>1) r = weibrnd(a,b,c); elseif nargin == 5 r = weibrnd(a,b,c,d); else error('WEIBRND called with incorrect number of inputs.'); end else error('Sorry, the Statistics Toolbox does not support this distribution.'); end 18 ## function [errorcode, rows, columns] = rndcheck(nargs,nparms,arg1,arg2,arg3,arg4,arg5) %RNDCHECK error checks the argument list for the random number generators. % % % B.A. Jones 1-22-93 Copyright 1993-2000 The MathWorks, Inc.$Revision: 2.7 Date: 2000/05/26 18:53:39 $sizeinfo = nargs - nparms; errorcode = 0; if nparms == 3 [r1 c1] = size(arg1); [r2 c2] = size(arg2); [r3 c3] = size(arg3); end if nparms == 2 [r1 c1] = size(arg1); [r2 c2] = size(arg2); end if sizeinfo == 0 if nparms == 1 [rows columns] = size(arg1); end if nparms == 2 scalararg1 = (prod(size(arg1)) == 1); scalararg2 = (prod(size(arg2)) == 1); if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if ~scalararg1 [rows columns] = size(arg1); elseif ~scalararg2 [rows columns] = size(arg2); else [rows columns] = size(arg1); end end if nparms == 3 scalararg1 = (prod(size(arg1)) == 1); scalararg2 = (prod(size(arg2)) == 1); scalararg3 = (prod(size(arg3)) == 1); if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if ~scalararg1 & ~scalararg3 if r1 ~= r3 | c1 ~= c3 errorcode = 1; return; end end if ~scalararg3 & ~scalararg2 if r3 ~= r2 | c3 ~= c2 errorcode = 1; 19 return; end end if ~scalararg1 [rows columns] = size(arg1); elseif ~scalararg2 [rows columns] = size(arg2); else [rows columns] = size(arg3); end end end if sizeinfo == 1 scalararg1 = (prod(size(arg1)) == 1); if nparms == 1 if prod(size(arg2)) ~= 2 errorcode = 2; return; end if ~scalararg1 & arg2 ~= size(arg1) errorcode = 3; return; end if (arg2(1) < 0 | arg2(2) < 0 | arg2(1) ~= round(arg2(1)) | arg2(2) ~= round(arg2(2))), errorcode = 4; return; end rows = arg2(1); columns = arg2(2); end if nparms == 2 if prod(size(arg3)) ~= 2 errorcode = 2; return; end scalararg2 = (prod(size(arg2)) == 1); if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if (arg3(1) < 0 | arg3(2) < 0 | arg3(1) ~= round(arg3(1)) | arg3(2) ~= round(arg3(2))), errorcode = 4; return; end if ~scalararg1 if any(arg3 ~= size(arg1)) errorcode = 3; return; end [rows columns] = size(arg1); elseif ~scalararg2 if any(arg3 ~= size(arg2)) errorcode = 3; return; end [rows columns] = size(arg2); else rows = arg3(1); columns = arg3(2); end end 20 if nparms == 3 if prod(size(arg4)) ~= 2 errorcode = 2; return; end scalararg1 = (prod(size(arg1)) == 1); scalararg2 = (prod(size(arg2)) == 1); scalararg3 = (prod(size(arg3)) == 1); if (arg4(1) < 0 | arg4(2) < 0 | arg4(1) ~= round(arg4(1)) | arg4(2) ~= round(arg4(2))), errorcode = 4; return; end if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if ~scalararg1 & ~scalararg3 if r1 ~= r3 | c1 ~= c3 errorcode = 1; return; end end if ~scalararg3 & ~scalararg2 if r3 ~= r2 | c3 ~= c2 errorcode = 1; return; end end if ~scalararg1 if any(arg4 ~= size(arg1)) errorcode = 3; return; end [rows columns] = size(arg1); elseif ~scalararg2 if any(arg4 ~= size(arg2)) errorcode = 3; return; end [rows columns] = size(arg2); elseif ~scalararg3 if any(arg4 ~= size(arg3)) errorcode = 3; return; end [rows columns] = size(arg3); else rows = arg4(1); columns = arg4(2); end end end if sizeinfo == 2 if nparms == 1 scalararg1 = (prod(size(arg1)) == 1); if ~scalararg1 [rows columns] = size(arg1); if rows ~= arg2 | columns ~= arg3 errorcode = 3; 21 return; end end if (arg2 < 0 | arg3 < 0 | arg2 ~= round(arg2) | arg3 ~= round(arg3)), errorcode = 4; return; end rows = arg2; columns = arg3; end if nparms == 2 scalararg1 = (prod(size(arg1)) == 1); scalararg2 = (prod(size(arg2)) == 1); if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if ~scalararg1 [rows columns] = size(arg1); if rows ~= arg3 | columns ~= arg4 errorcode = 3; return; end elseif ~scalararg2 [rows columns] = size(arg2); if rows ~= arg3 | columns ~= arg4 errorcode = 3; return; end else if (arg3 < 0 | arg4 < 0 | arg3 ~= round(arg3) | arg4 ~= round(arg4)), errorcode = 4; return; end rows = arg3; columns = arg4; end end if nparms == 3 scalararg1 = (prod(size(arg1)) == 1); scalararg2 = (prod(size(arg2)) == 1); scalararg3 = (prod(size(arg3)) == 1); if ~scalararg1 & ~scalararg2 if r1 ~= r2 | c1 ~= c2 errorcode = 1; return; end end if ~scalararg1 & ~scalararg3 if r1 ~= r3 | c1 ~= c3 errorcode = 1; return; end end if ~scalararg3 & ~scalararg2 if r3 ~= r2 | c3 ~= c2 errorcode = 1; return; end end if ~scalararg1 [rows columns] = size(arg1); 22 if rows ~= arg4 | columns ~= arg5 errorcode = 3; return; end elseif ~scalararg2 [rows columns] = size(arg2); if rows ~= arg4 | columns ~= arg5 errorcode = 3; return; end elseif ~scalararg3 [rows columns] = size(arg3); if rows ~= arg4 | columns ~= arg5 errorcode = 3; return; end else if (arg4 < 0 | arg5 < 0 | arg4 ~= round(arg4) | arg5 ~= round(arg5)), errorcode = 4; return; end rows = arg4; columns = arg5; end end end function [y]=unifnums(N,a,b) for I=1:N y(I)=unifrnd(a,b); end function r = unifrnd(a,b,m,n) %UNIFRND Random matrices from continuous uniform distribution. % R = UNIFRND(A,B) returns a matrix of random numbers chosen % from the continuous uniform distribution on the interval from A to B. % The size of R is the common size of A and B if both are matrices. % If either parameter is a scalar, the size of R is the size of the other % parameter. Alternatively, R = UNIFRND(A,B,M,N) returns an M by N matrix. % Copyright 1993-2000 The MathWorks, Inc. %$Revision: 2.8 Date: 2000/05/26 18:53:55 $if nargin < 2, error('Requires at least two input arguments.'); end if nargin == 2 [errorcode rows columns] = rndcheck(2,2,a,b); end if nargin == 3 [errorcode rows columns] = rndcheck(3,2,a,b,m); end if nargin == 4 [errorcode rows columns] = rndcheck(4,2,a,b,m,n); end if errorcode > 0 error('Size information is inconsistent.'); end % Initialize R to zero. r = zeros(rows,columns); r = a + (b-a) .* rand(rows,columns); % A is the lower limit, so it must be less than B. k = find(a >= b); if any(k) tmp = NaN; r(k) = tmp(ones(size(k))); end 23 function [h,ww] = freqs(b,a,w) %FREQS Laplace-transform (s-domain) frequency response. % H = FREQS(B,A,W) returns the complex frequency response vector H % of the filter B/A: % nb-1 nb-2 % B(s) b(1)s + b(2)s + ... + b(nb) % H(s) = ---- = ------------------------------------% na-1 na-2 % A(s) a(1)s + a(2)s + ... + a(na) % % given the numerator and denominator coefficients in vectors B and A. % The frequency response is evaluated at the points specified in % vector W (in rad/s). The magnitude and phase can be graphed by % calling FREQS(B,A,W) with no output arguments. % % [H,W] = FREQS(B,A) automatically picks a set of 200 frequencies W on % which the frequency response is computed. FREQS(B,A,N) picks N % frequencies. % % See also LOGSPACE, POLYVAL, INVFREQS, and FREQZ. % Author(s): J.N. Little, 6-26-86 % T. Krauss, 3-19-93, default plots and frequency vector % Copyright 1988-2000 The MathWorks, Inc. %$Revision: 1.9 Date: 2000/06/09 22:04:39 $error(nargchk(2,3,nargin)); error(nargoutchk(0,2,nargout)); if ~any(size(b)<=1) | ~any(size(a)<=1), error('The numerator and denominator must be vectors.'); end [b,a] = tfchk(b,a); if nargin == 2, w = 200; end if length(w) == 1, wlen = w; w_long = freqint(b,a,wlen); % need to interpolate long frequency vector: xi = linspace(1,length(w_long),wlen).'; w = 10.^interp1(1:length(w_long),log10(w_long),xi,'linear'); end s = j*w; hh = polyval(b,s) ./ polyval(a,s); if nargout == 0, newplot; mag = abs(hh); phase = angle(hh)*180/pi; subplot(211),loglog(w,mag),set(gca,'xgrid','on','ygrid','on') set(gca,'xlim',[w(1) w(length(w))]) xlabel('Frequency (rad/s)') ylabel('Magnitude') 24 ax = gca; subplot(212), semilogx(w,phase),set(gca,'xgrid','on','ygrid','on') set(gca,'xlim',[w(1) w(length(w))]) xlabel('Frequency (rad/s)') ylabel('Phase (degrees)') axes(ax) elseif nargout == 1, h = hh; elseif nargout == 2, h = hh; ww = w; end % end freqs function w=freqint(a,b,c,d,npts) %FREQINT Auto-ranging algorithm for Bode frequency response % W=FREQINT(A,B,C,D,Npts) % W=FREQINT(NUM,DEN,Npts) % Andy Grace 7-6-90 % Was Revision: 1.9, Date: 1996/07/25 16:43:37 % Generate more points where graph is changing rapidly. % Calculate points based on eigenvalues and transmission zeros. [na,ma] = size(a); if (nargin==3)&(na==1), % Transfer function form. npts=c; ep=roots(b); tz=roots(a); else % State space form if nargin==3, npts=c; [a,b,c,d] = tf2ss(a,b); end ep=[eig(a)]; tz=tzero(a,b,c,d); end if isempty(ep), ep=-1000; end % Note: this algorithm does not handle zeros greater than 1e5 ez=[ep(find(imag(ep)>=0));tz(find(abs(tz)<1e5&imag(tz)>=0))]; % Round first and last frequencies to nearest decade integ = abs(ez)<1e-10; % Cater for systems with pure integrators highfreq=round(log10(max(3*abs(real(ez)+integ)+1.5*imag(ez)))+0.5); lowfreq=round(log10(0.1*min(abs(real(ez+integ))+2*imag(ez)))-0.5); % Define a base range of frequencies diffzp=length(ep)-length(tz); w=logspace(lowfreq,highfreq,npts+diffzp+10*(sum(abs(imag(tz))<abs(real(tz)))>0)); ez=ez(find(imag(ez)>abs(real(ez)))); % Oscillatory poles and zeros if ~isempty(ez) f=w; npts2=2+8/ceil((diffzp+eps)/10); 25 [dum,ind]=sort(-abs(real(ez))); z=[]; for i=ind' r1=max([0.8*imag(ez(i))-3*abs(real(ez(i))),10^lowfreq]); r2=1.2*imag(ez(i))+4*abs(real(ez(i))); z=z(find(z>r2|z<r1)); indr=find(w<=r2&w>=r1); f=f(find(f>r2|f<r1)); z=[z,logspace(log10(r1),log10(r2),sum(w<=r2&w>=r1)+npts2)]; end w=sort([f,z]); end w = w(:); % end freqint function [b,a]=invfreqs(g,w,varargin) %INVFREQS Analog filter least squares fit to frequency response data. % [B,A] = INVFREQS(H,W,nb,na) gives real numerator and denominator % coefficients B and A of orders nb and na respectively, where % H is the desired complex frequency response of the system at frequency % points W, and W contains the frequency values in radians/s. % INVFREQS yields a filter with real coefficients. This means that it is % sufficient to specify positive frequencies only; the filter fits the data % conj(H) at -W, ensuring the proper frequency domain symmetry for a real % filter. % % [B,A]=INVFREQS(H,W,nb,na,Wt) allows the fit-errors to the weighted % versus frequency. LENGTH(Wt)=LENGTH(W)=LENGTH(H). % Determined by minimization of sum |B-H*A|^2*Wt over the freqs in W. % % [B,A] = INVFREQS(H,W,nb,na,Wt,ITER) does another type of fit: % Sum |B/A-H|^2*Wt is minimized with respect to the coefficients in B and % A by numerical search in at most ITER iterations. The A-polynomial is % then constrained to be stable. [B,A]=INVFREQS(H,W,nb,na,Wt,ITER,TOL) % stops the iterations when the norm of the gradient is less than TOL. % The default value of TOL is 0.01. The default value of Wt is all ones. % This default value is also obtained by Wt=[]. % % [B,A]=INVFREQS(H,W,nb,na,Wt,ITER,TOL,'trace') provides a textual % progress report of the iteration. % % [B,A] = INVFREQS(H,W,'complex',NB,NA,...) creates a complex filter. In % this case, no symmetry is enforced. % % See also FREQZ, FREQS, INVFREQZ. % Author(s): J.O. Smith and J.N. Little, 4-23-86 % J.N. Little, 4-27-88, revised % Lennart Ljung, 9-21-92, rewritten % T. Krauss, 10-22-92, trace mode made optional % Copyright 1988-2000 The MathWorks, Inc. %$Revision: 1.5 Date: 2000/06/09 22:04:58 \$ % calling sequence is %function [b,a]=invfreqs(g,w,nb,na,wf,maxiter,tol,pf)

26

% OR %function [b,a]=invfreqs(g,w,'complex',nb,na,wf,maxiter,tol,pf) error(nargchk(4,9,nargin)) if isstr(varargin{1}) realStr = lower(varargin{1}); varargin(1) = []; else realStr = 'real'; end gaussFlag = length(varargin)>3; % run Gauss-Newton algorithm or not? if length(varargin)<6 varargin{6} = []; % pad varargin with []'s end [nb,na,wf,maxiter,tol,pf] = deal(varargin{:}); switch realStr case 'real' realFlag = 1; case 'complex' realFlag = 0; otherwise warning(... sprintf('String ''%s'' not recognized. I assume you meant ''complex''.',... realStr)) realFlag = 0; end nk=0; % The code is prepared for constraining the numerator to % begin with nk zeros. nb=nb+nk+1; if isempty(pf) verb=0; elseif (strcmp(pf,'trace')), verb=1; else error(['Trace flag ''' pf ''' not recognizable']); end if isempty(wf),wf=ones(length(w),1);end wf=sqrt(wf); if length(g)~=length(w),error('The lengths of H and W must coincide'),end if length(wf)~=length(w),error('The lengths of Wt and W must coincide'),end if any( w<0 ) & realFlag warnStr = sprintf(... ['W has values which are negative. INVFREQS aliases such\n' ... 'values into positive ones and designs a real filter.\n' ... 'To design a complex filter, use the ''complex'' flag.']); warning(warnStr) end [rw,cw]=size(w);if rw>cw w=w';end [rg,cg]=size(g);if cg>rg g=g.';end [rwf,cwf]=size(wf);if cwf>rwf wf=wf';end nm=max(na+1,nb+nk);

27

indb=nb:-1:1; indg=na+1:-1:1; inda=na:-1:1; OM=ones(1,length(w)); for kom=1:nm-1 OM=[OM;(i*w).^kom]; end % % Estimation in the least squares case: % Dva=(OM(inda,:).').*(g*ones(1,na)); Dvb=-(OM(indb,:).'); D=[Dva Dvb].*(wf*ones(1,na+nb)); R=D'*D; Vd=D'*((-g.*OM(na+1,:).').*wf); if realFlag R=real(R); Vd=real(Vd); end th=R\Vd; a=[1 th(1:na).'];b=[zeros(1,nk) th(na+1:na+nb).']; if ~gaussFlag,return,end % Now for the iterative minimization if isempty(maxiter), maxiter = 30; end if isempty(tol) tol=0.01; end % Stabilizing the denominator: a=apolystab(a,realFlag); % The initial estimate: GC=((b*OM(indb,:))./(a*OM(indg,:))).'; e=(GC-g).*wf; Vcap=e'*e; t=[a(2:na+1) b(nk+1:nk+nb)].'; if (verb), clc, disp([' INITIAL ESTIMATE']) disp(['Current fit: ' num2str(Vcap)]) disp(['par-vector']) disp(t) end % % ** the minimization loop ** % gndir=2*tol+1;l=0;st=0; while [norm(gndir)>tol l<maxiter st~=1] l=l+1; % * compute gradient * D31=(OM(inda,:).').*(-GC./((a*OM(indg,:)).')*ones(1,na)); D32=(OM(indb,:).')./((a*OM(indg,:)).'*ones(1,nb)); D3=[D31 D32].*(wf*ones(1,na+nb));

28

% * compute Gauss-Newton search direction e=(GC-g).*wf; R=D3'*D3; Vd=D3'*e; if realFlag R=real(R); Vd=real(Vd); end gndir=R\Vd; % * search along the gndir-direction * ll=0;,k=1;V1=Vcap+1; while [V1 > Vcap ll<20], t1=t-k*gndir; if ll==19,t1=t;end a=[1 t1(1:na).']; b=[zeros(1,nk) t1(na+1:na+nb).']; a=apolystab(a,realFlag); % Stabilizing the denominator t1(1:na)=a(2:na+1).'; GC=((b*OM(indb,:))./(a*OM(indg,:))).'; V1=((GC-g).*wf)'*((GC-g).*wf); if (verb), home, disp(int2str(ll)) end; k=k/2; ll=ll+1; if ll==10, gndir=Vd/norm(R)*length(R);k=1;end if ll==20,st=1;end end if (verb), home disp([' ITERATION # ' int2str(l)]) disp(['Current fit: ' num2str(V1) ' Previous fit: ' num2str(Vcap)]) disp(['Current par prev.par GN-dir']) disp([t1 t gndir]) disp(['Norm of GN-vector: ' num2str(norm(gndir))]) if st==1, disp(['No improvement of the criterion possible along the '... 'search ''direction''']), disp('Iterations therefore terminated'), end end t=t1; Vcap=V1; end function a = apolystab(a,realFlag) %APOLYSTAB Stabilize filter, analog % inputs: a - denominator polynomial % realFlag - 1 for real, 0 for complex % returns stabilized denoninator polynomial if length(a)>0 v=roots(a); vind=find(real(v)>0); v(vind)=-v(vind); a=poly(v); if realFlag a=real(a); end end

29

% HydBrkSys.m % Simulation example in ASME paper of a hydraulic % brake line and brake cylinder with input pressure % step input % Nu=7.6179e-6;Den=855.24;Beta=1.8246e9;Mu=Den*Nu; L=20;d=0.003175;RL=128*Mu*L/(pi*d^4);Vc=L*pi*d^2/4; [NGOneOverZSinh,GOneOverZSinh] = OneOverZSinh(Den,Beta,Mu,d,L ); [NGCoshOverZSinh,GCoshOverZSinh] = CoshOverZSinh(Den,Beta,Mu,d,L ); G1=feedback(tf([Beta/Vc],[1 0]),GCoshOverZSinh); G=series(GOneOverZSinh,G1); G=zpk(G); G=minreal(G) damp(G) [P,t]=step(G); figure plot(t,P,'r','LineWidth',2) xlabel('Time, sec.') ylabel('Brake Cylinder Pressure \DeltaP_b per unit \DeltaP_a')

% HydFract.m % Simulation example in ASME paper of hydraulic fracturing % The input to the line is a series of flow pulses % Of interest is the corresponding flow rate at the output % end of the line; the output flow amplitude will be % very dependent on the input pulse frequency Nu=1.5e-6;Den=1000;Beta=350000*6895;Mu=Den*Nu; L=5000;d=0.1;RL=128*Mu*L/(pi*d^4); [NGZOverSinh,GZOverSinh] = ZoverSinh(Den,Beta,Mu,d,L ); [NGZCoshOverSinh,GZCoshOverSinh] = ZCoshOverSinh(Den,Beta,Mu,d,L ); G1=feedback(tf([1/(6*RL)],[1]),GZCoshOverSinh); G=series(GZOverSinh,G1); G=zpk(G); G=minreal(G) damp(G) figure [Mag,Ph,w]=bode(G,{0.2 3}); plot(w(:),Mag(:),'r','LineWidth',2) xlabel('frequency, rad/sec') ylabel('magnitude of transfer function') T=1;F=1;m=12;N=10;NumPPP=100; [f,t] = PulseSeries(T,m,F,N,NumPPP); [Y,t]=lsim(G,f,t); figure plot(t,f,'r',t,Y,'k:','LineWidth',2) ylabel('pipe input and output flow rates per unit input of m^3/s') xlabel('time, sec.') legend('\DeltaQ_a','\DeltaQ_b','Location','SouthWest')

30