├── .DS_Store ├── .gitignore ├── Modal_Analysis ├── Uscript.m ├── Vscript.m ├── cferror.m ├── cfitex.m ├── cmif.m ├── cmifts.m ├── comac.m ├── femgui.m ├── frfgen2.m ├── mac.m ├── makehelp.m ├── mdofcf.m ├── mdofcftry.m ├── mdofcfuse.m ├── mmcf.m ├── mmcfnr.m ├── mmcftry.m ├── modefit.m ├── polyref.m ├── polyref2.m ├── repmodestest.m ├── sdof.m ├── sdofcf.m ├── sdofcf2.m ├── sdofcf2a.m ├── sdofcfold.m ├── sdofcvscript.m ├── sdtest.m ├── sec8p1.m ├── single_thesis_modes_simple.m ├── vtb74test.m └── vtb7_4_1.m ├── README.md ├── asd.m ├── asdtest.m ├── blackwin.m ├── boxwin.m ├── coh.m ├── crcor.m ├── crsd.m ├── expwin.m ├── freqdemo.mat ├── guyanold.m ├── hammwin.m ├── hannwin.m ├── hkdat1.mat ├── household.m ├── irf.m ├── loadfile.m ├── mckiddat.mat ├── mdofcf.m ├── parzen.m ├── sdofcf.m ├── so2ss.m ├── soeig.m ├── sostf.m ├── ssim.m ├── ssit.m ├── templogo.m ├── testdata.mat ├── tfest.m ├── tfplot.m ├── tfplot2.m ├── triwin.m ├── vonhann.m ├── vtbfrdem.m ├── vtblogo.m ├── vtdem1.mat └── vtestingdata1.mat /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | Untitled.ipynb 28 | .ipynb_checkpoints/* 29 | 30 | # Sphinx 31 | _build* 32 | latex* 33 | html* 34 | *~ 35 | *.html 36 | 37 | # PyInstaller 38 | # Usually these files are written by a python script from a template 39 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 40 | *.manifest 41 | *.spec 42 | 43 | # Installer logs 44 | pip-log.txt 45 | pip-delete-this-directory.txt 46 | 47 | # Unit test / coverage reports 48 | htmlcov/ 49 | .tox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *,cover 56 | .hypothesis/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | .DS_Store 71 | -------------------------------------------------------------------------------- /Modal_Analysis/Uscript.m: -------------------------------------------------------------------------------- 1 | function U=Uscript(o,omega,plist) 2 | 3 | % U=Uscript(o, omega, plist) 4 | % o is number of inputs 5 | % omega is frequency vector in radians per second 6 | % plist is a vector of powers of omega in adjacent columns 7 | global freqdebug 8 | if freqdebug==1, disp('Making Vscript'),end 9 | U=zeros(o*length(omega),o*length(plist)); 10 | Ip=eye(o); 11 | no=length(omega); 12 | onev=ones(o,1); 13 | for ii=1:length(omega) 14 | for jj=1:length(plist) 15 | U(((ii-1)*o+1):ii*o,((jj-1)*o+1):jj*o)=eye(o)*(sqrt(-1)*omega(ii))^plist(jj); 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /Modal_Analysis/Vscript.m: -------------------------------------------------------------------------------- 1 | function V=Vscript(H,omega,plist) 2 | 3 | % V=Vscript(H, omega, plist) 4 | % 5 | % Returns the variable script V defined by Slater in "Vibration Testing". 6 | % 7 | % H is the matrix of FRFs, in blocks of p outputs by o inputs, stacked 8 | % vertically by increasing frequency for each block. 9 | % omega is the list of frequencies (real) in radians per second 10 | % plist are the powers of the blocks output. 11 | % 0 would return H with the blocks each transposed 12 | % 2 would return H with each transposed block multiplied by jw^2 13 | % [0 2] would return the two block columns of the preceeding examples 14 | % combined in one matrix. 15 | % 16 | % 17 | 18 | global freqdebug 19 | if freqdebug==1, disp('Making Vscript'),end 20 | p=size(H,1)/length(omega); 21 | o=size(H,2); 22 | if floor(p)~=p 23 | disp(['On cannot have ' num2str(size(H,1)/length(omega)) ' outputs']) 24 | return 25 | else 26 | H2=zeros(o*length(omega),p); 27 | if freqdebug==1, disp('Regigering H'),end 28 | for ii=1:length(omega) 29 | H2(((ii-1)*o+1):ii*o,:)=transpose(H(((ii-1)*p+1):ii*p,:)); 30 | end 31 | if freqdebug==1, disp('Clearing H'),end 32 | 33 | clear('H') 34 | if freqdebug==1, disp('Making empty V'),end 35 | 36 | V=zeros(size(H2,1),size(H2,2)*length(plist)); 37 | 38 | % Diagonal matrix of proper size to do multiplications in one fell swoop 39 | % for each block column. 40 | if freqdebug==1, disp('Making ODV'),end 41 | ODV=sparse(zeros(size(H2,1),1)); 42 | no=length(omega); 43 | onev=ones(o,1); 44 | if freqdebug==1, disp('Putting values into ODV'),tic,end 45 | 46 | for ii=1:no 47 | ODV(((ii-1)*o+1):(ii*o),1)=omega(ii)*sqrt(-1)*onev; 48 | end 49 | if freqdebug==1, disp('Putting values into ODV'),toc,end 50 | 51 | 52 | 53 | if freqdebug==1, disp('Make OD from sparse ODV'),end 54 | OD=(diag(ODV)); 55 | if freqdebug==1, disp('Finish making V'),end 56 | for ii=1:length(plist) 57 | V(:,((ii-1)*p+1):(ii*p))=(OD^plist(ii))*H2; 58 | end 59 | 60 | 61 | end -------------------------------------------------------------------------------- /Modal_Analysis/cferror.m: -------------------------------------------------------------------------------- 1 | function cferror=cferror(x) 2 | global w2 R2 XoF 3 | 4 | lx=length(x); 5 | 6 | XoF=x(lx-2)+x(lx-1)*i*w2-x(lx)*w2.^2; 7 | for j=1:(lx/3)-1 8 | XoF=XoF+x(3*j-2)./(-w2.^2+2*x(3*j-1)*w2*i*x(3*j)+x(3*j)^2);%+x(4)+x(5)*i*w2-x(6)*w2.^2; 9 | end 10 | 11 | cferror=norm(XoF-R2); 12 | %pause 13 | -------------------------------------------------------------------------------- /Modal_Analysis/cfitex.m: -------------------------------------------------------------------------------- 1 | global w2 R2 XoF 2 | M=eye(2);K=[2 -1;-1 2];C=.01*K; 3 | [Freq,Recep,Mobil,Inert]=sostf(M,C,K,1,1,linspace(0,.5,1024)); 4 | figure(1) 5 | tfplot(Freq,Recep) 6 | n=350*2 7 | f2=Freq(1:n); 8 | R2=Recep(1:n); 9 | R2=R2+.1*randn(n,1)+.1*randn(n,1)*i; 10 | figure(2) 11 | tfplot(f2,R2) 12 | w2=2*pi*f2; 13 | format long 14 | 15 | x0=[.5;.005;1;-1;.01;1.6;0;0;0];x=x0; 16 | %x0=[.5;.005;1;0;0;0];x=x0; 17 | %plot(f2,20*log10(abs(x(1)./(-w2.^2+2*x(2)*w2*i*x(3)+x(3)^2)+x(4)+x(5)*i*w2-x(6)*w2.^2)),'g',f2,20*log10(abs(R2))) 18 | x0 19 | 20 | clear i 21 | for j=1:100 22 | 23 | x=fmins('cferror',x0) 24 | 25 | figure(3) 26 | plot(f2,20*log10(abs(XoF)),'g',f2,20*log10(abs(R2))) 27 | zoom on 28 | % x(1)./(-w2.^2+2*x(2)*w2*i*x(3)+x(3)^2)+x(4)+x(5)*i*w2-x(6)*w2.^2; 29 | grid on 30 | %hold on 31 | %figure(3) 32 | %plot(f2,20*log10(abs(R2))) 33 | %hold off 34 | x0=x; 35 | pause 36 | end 37 | -------------------------------------------------------------------------------- /Modal_Analysis/cmif.m: -------------------------------------------------------------------------------- 1 | function CMIF(w,H) 2 | % CMIF(w,H) calculates and plots the complex mode indicator function 3 | % For the FRFs, H, rows and columns reference degrees of freedom, and 4 | % the third dimension is wrt omega. 5 | 6 | % Copyright Joseph C. Slater, 2001 7 | % Version 1.0 8 | 9 | s=size(H); 10 | if min(s(1:2))==1 11 | warndlg('Without MIMO data, this function means little','Huh?') 12 | end 13 | l=s(3); 14 | w=w(:); 15 | if s(2)>s(1) 16 | a=H(:,:,1)*H(:,:,1)'; 17 | [v(:,:,1),lam(:,:,1)]=eig(real(a)); 18 | for i=1:l 19 | H(:,:,i); 20 | a=H(:,:,i)*H(:,:,i)'; 21 | a=v(:,:,i-1)\a*v(:,:,i-1) 22 | pause 23 | [v(:,:,i),lam(:,:,i)]=eig(real(a)); 24 | %v(:,:,i); 25 | end 26 | else 27 | a=H(:,:,1)'*H(:,:,1); 28 | [v(:,:,1),lam(:,:,1)]=eig(real(a)); 29 | for i=2:l 30 | a=real(H(:,:,i)'*H(:,:,i)); 31 | %a=v(:,:,i-1)\real(a)*v(:,:,i-1); 32 | %pause 33 | [v(:,:,i),lam(:,:,i)]=eig(a); 34 | %v(:,:,i)\real(a)*v(:,:,i); 35 | %v(:,:,i); 36 | end 37 | end 38 | size(lam); 39 | s; 40 | for i=1:min(s(1:2)) 41 | size(lam(i,i,:)); 42 | d=lam(i,i,:); 43 | size(d); 44 | d=d(:); 45 | size(d); 46 | % disp('size d'); 47 | y(:,i)=d; 48 | end 49 | y; 50 | size(y) 51 | %y(20,:) 52 | y=-(sort(-y'))'; 53 | %semilogy(w,y(:,1),'>',w,y(:,2),'+',w,y(:,3),'o') 54 | %axes 55 | 56 | %set(0,...%'DefaultAxesColorOrder',[0 0 1],... 57 | % 'DefaultAxesLineStyleOrder','o|x|+|*|S|D|v|^|<|>|p|h') 58 | %set(0,'DefaultAxesLineStyleOrder','o|x|+|*|S|D|v|^|<|>|p|h') 59 | %'yo|mx|c+|r*|gS|bD|wv|k^|k<|k>|kp|kh') 60 | ls=['bo';'gx';'r+';'c*';'mS';'kD';'bv';'g^';'r<';'c>';'mp';'kh']; 61 | semilogy(w,y(:,1),ls(1,:)) 62 | hold on 63 | for i=1:size(y,2) 64 | semilogy(w,y(:,i),ls(i,:)) 65 | end 66 | hold off 67 | grid on 68 | zoom on 69 | -------------------------------------------------------------------------------- /Modal_Analysis/cmifts.m: -------------------------------------------------------------------------------- 1 | %complex mode indicator test script 2 | clear 3 | 4 | k=[2 -1;-1 2]; 5 | m=eye(size(k)); 6 | c=.01*k; 7 | 8 | for i=1:2 9 | for j=1:2 10 | [w,R,M,I]=vtb7_5(m,c,k,i,j,linspace(0,.5,1024)); 11 | H(i,j,:)=R; 12 | end 13 | end 14 | 15 | %cmif(w,H) 16 | clear 17 | %pause 18 | k=[3 -1 -1;-1 3 -1;-1 -1 3]; 19 | m=eye(size(k)); 20 | sqrt(eig(m\k)) 21 | c=.01*k; 22 | hold off 23 | for i=1:3 24 | for j=1:3 25 | [f,R,M,I]=vtb7_5(m,c,k,i,j,linspace(0,2/pi,1024)); 26 | H(i,j,:)=R+.0*randn(size(R)); 27 | %tfplot(f,R) 28 | %pause 29 | end 30 | end 31 | size(H); 32 | cmif(f*2*pi,H) 33 | 34 | -------------------------------------------------------------------------------- /Modal_Analysis/comac.m: -------------------------------------------------------------------------------- 1 | function comac=comac(u1,u2) 2 | % MAC=MAC(u1,u2) 3 | % Calculate the Coordinate Modal Assurance Criterion for 2 sets of modes 4 | % 5 | % See Harris pp. 21.72 6 | 7 | if size(u1)~=size(u2) 8 | disp('Either the number of modes doesn''t match or the length of the model vectors doesn''t match. Cannot compute.') 9 | return 10 | 11 | else 12 | mc=mac(u1,u2,1); 13 | [y,i]=max(abs(mc)+abs(mc')); 14 | r=1:size(u1,2); 15 | comac=zeros(size(u1,1),1); 16 | %Resort modes to correlate. 17 | u2p=u2(:,i); 18 | mc=mc(:,i); 19 | u2p=u2p*diag(sign(diag(mc))); 20 | %[u1 u2p]; 21 | for p=1:size(u1,1) 22 | comac(p)=sum(u1(p,r).*u2p(p,r))^2/(sum(u1(p,r).*u1(p,r))*sum(u2p(p,r).*u2p(p,r))); 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /Modal_Analysis/femgui.m: -------------------------------------------------------------------------------- 1 | function femgui(mode) 2 | % femgui [node,ncon,zero,force]=femgui 3 | % Makes input file for VTB8_2 4 | % I suggest you print the file vtb8read. 5 | 6 | % Joseph C. Slater, 6-17-90 7 | % Copyright (c) 1990-94 by Joseph C. Slater 8 | 9 | % 21 Dec 00 -- Major revision of GUI. 10 | % 11 Nov 94 -- fixed graphics to work with Matlab 4.0 11 | 12 | % What we need to do is instead of having matrices of locations... 13 | % is have matrices of handles for objects whose properties are available 14 | % in the userdata. This way they can each be selected and edited one at a time. 15 | % Only when writing the data file or reading it to we actually transfer between the two. 16 | % We could actually set a flag that tells the callback for a node whther to 17 | % choose that node for deleting, editing, connecting with an element, adding bc, or other... 18 | % In the file menu, we can have an open for edit, or a regular open command. 19 | % The first would simply cause a text edit of the datafile. If no data existed, one would have 20 | % to be written first. Otherwise, one could be selected. However, this option would only be available 21 | % after selection of the new or open commands. 22 | % Callback functions of all object must be turned on and off depending on what objects are currently 23 | % being edited. 24 | 25 | 26 | if nargin==0 27 | clear 28 | global node 29 | h=findobj('tag','femgui'); 30 | if isempty(h) 31 | fn=figure('Name', 'Engineering Vibration Toolbox FEM', ... 32 | 'NumberTitle', 'off', ... 33 | 'MenuBar', 'none', ... 34 | 'Units', 'normalized', ... 35 | 'PaperOrientation', 'Landscape', ... 36 | 'PaperUnits', 'Normalized', ... 37 | 'tag','femgui',... 38 | 'ShareColors', 'No'); 39 | drawnow 40 | 41 | file_opt = uimenu(fn,'Label', 'File '); 42 | label = str2mat(...%label,... 43 | 'New',... 44 | 'Open',... 45 | 'Save',... 46 | 'Analyze',... 47 | 'Quit'); 48 | file_new_m = uimenu(file_opt, ... 49 | 'Label', deblank(label(1,:)), ... 50 | 'Accelerator','n',... 51 | 'CallBack', 'femgui(''new'');'); 52 | file_open_m = uimenu(file_opt, ... 53 | 'Label', deblank(label(2,:)), ... 54 | 'Accelerator','o',... 55 | 'CallBack', 'femgui(''open'');'); 56 | file_save_m = uimenu(file_opt, ... 57 | 'Label', deblank(label(3,:)), ... 58 | 'Accelerator','s',... 59 | 'enable','off',... 60 | 'CallBack', 'femgui(''save'');'); 61 | file_analyze_m = uimenu(file_opt, ... 62 | 'Label', deblank(label(4,:)), ... 63 | 'Accelerator','a',... 64 | 'enable','off',... 65 | 'CallBack', 'femgui(''analyze'');'); 66 | file_quit_m = uimenu(file_opt, ... 67 | 'Label', deblank(label(5,:)), ... 68 | 'Accelerator','w',... 69 | 'CallBack', 'femgui(''quit'');'); 70 | 71 | file_opt = uimenu(fn,'Label', 'Edit'); 72 | label = str2mat(...%label,... 73 | 'Nodes',... 74 | 'Elements',... 75 | 'Point Masses/Inertias',... 76 | 'Boundary Conditions'); 77 | file_open_m = uimenu(file_opt, ... 78 | 'Label', deblank(label(1,:)), ... 79 | 'enable','off',... 80 | 'CallBack', ['global node;femgui(''nodes'');']); 81 | file_open_m = uimenu(file_opt, ... 82 | 'Label', deblank(label(2,:)), ... 83 | 'enable','off',... 84 | 'CallBack', 'femgui(''elements'');'); 85 | %get(file_open_m) 86 | file_open_m = uimenu(file_opt, ... 87 | 'Label', deblank(label(3,:)), ... 88 | 'enable','off',... 89 | 'CallBack', 'femgui(''masses'');'); 90 | file_open_m = uimenu(file_opt, ... 91 | 'Label', deblank(label(4,:)), ... 92 | 'enable','off',... 93 | 'CallBack', 'femgui(''bcs'');'); 94 | %openvar 95 | %disp('lkhlhl') 96 | mode='a'; 97 | else 98 | figure(h) 99 | fn=h; 100 | end 101 | 102 | else 103 | userdata=get(gcf,'Userdata'); 104 | if ~isempty(userdata) 105 | global node 106 | node=userdata{1} 107 | ncon=userdata{2}; 108 | conm=userdata{3}; 109 | zero=userdata{4}; 110 | force=userdata{5}; 111 | end 112 | disp('Command') 113 | if strcmp(mode,'nodes') 114 | gcbo 115 | disp('nodes') 116 | size(node) 117 | openvar('node') 118 | disp('get rid of openvar and replace with edit') 119 | pause(.01),drawnow 120 | h=questdlg('accept changes?','yes','now') 121 | node(1:10,1:2) 122 | elseif strcmp(mode,'quit') 123 | disp('quit') 124 | delete(gcf) 125 | elseif strcmp(mode,'nodes') 126 | disp('Edit Nodes') 127 | for i=1:1000 128 | loc=input('Enter x and y location of node (ie. [x y]), 0 to end, or 1 to edit nodes. '); 129 | if loc==0 & length(loc)==1 ,break,end 130 | node(i,:)=loc; 131 | length=max([max(node(:,1))-min(node(:,1)) max(node(:,2))-min(node(:,2))]); 132 | d=node; 133 | xlo=min([node(:,1);d(:,1)]); 134 | xho=max([node(:,1);d(:,1)]); 135 | ylo=min([node(:,2);d(:,2)]); 136 | yho=max([node(:,2);d(:,2)]); 137 | xsp=xho-xlo; 138 | ysp=yho-ylo; 139 | if .618*xsp > ysp 140 | xh=xho+.1*xsp; 141 | xl=xlo-.1*xsp; 142 | yh=(yho+ylo)/2+(xh-xl)*.618/2; 143 | yl=(yho+ylo)/2-(xh-xl)*.618/2; 144 | else 145 | yh=yho+.1*ysp; 146 | yl=ylo-.1*ysp; 147 | xh=(xho+xlo)/2+.5*(yh-yl)/.618; 148 | xl=(xho+xlo)/2-.5*(yh-yl)/.618; 149 | end 150 | %%% 151 | dx=.01*(xh-xl); 152 | dy=.035*(yh-yl); 153 | plot(node(:,1),node(:,2),'*b') 154 | j=1:i; 155 | if i < 10 156 | istr=[num2str(i) ' ']; 157 | elseif i < 100 158 | istr=[num2str(i) ' ']; 159 | else 160 | istr=[num2str(i)]; 161 | end 162 | nnum=[nnum;istr]; 163 | text(node(j,1)'+dx,node(j,2)'+dy,nnum) 164 | % axis([xl xh yl yh]) 165 | axis('equal'),grid on 166 | al=axis;alx=al(2)-al(1);aly=al(4)-al(3); 167 | axis([al(1)-alx/10 al(2)+alx/10 al(3)-aly/10 al(4)+aly/10]) 168 | clc 169 | end 170 | elseif strcmp(mode,'ed') 171 | 172 | elseif strcmp(mode,'el') 173 | hold on 174 | clc 175 | %disp('Do you have a pointing device such as a mouse or trackball? (y/n)') 176 | %disp('(Arrow keys may be sufficient)') 177 | %point=input(' ','s'); 178 | point='y'; 179 | %connecting nodes section 180 | clc 181 | home 182 | disp(' Pick nodes to connect with elements.') 183 | if point=='y' 184 | disp(' (Use pointing device or arrow keys and return)') 185 | else 186 | disp(' (Enter node numbers one at a time)') 187 | end 188 | pause(1) 189 | answer2='n'; 190 | for i=1:1000 191 | % clc 192 | % home 193 | if i~=1 194 | disp(' Pick nodes to connect with elements.') 195 | end 196 | if point=='y' 197 | [x1 y1]=ginput(1); 198 | dis=(node(:,1)-x1).^2+(node(:,2)-y1).^2; 199 | [dsq,nodenum1]=min(dis); 200 | else 201 | clc,home 202 | nodenum1=input(' Enter node number 1: '); 203 | end 204 | plot(node(nodenum1,1),node(nodenum1,2),'*w') 205 | plot(node(nodenum1,1),node(nodenum1,2),'or') 206 | if point=='y' 207 | [x2 y2]=ginput(1); 208 | dis=(node(:,1)-x2).^2+(node(:,2)-y2).^2; 209 | [dsq,nodenum2]=min(dis); 210 | else 211 | clc,home 212 | nodenum2=input(' Enter node number 2: '); 213 | end 214 | plot(node(nodenum2,1),node(nodenum2,2),'*w') 215 | plot(node(nodenum2,1),node(nodenum2,2),'or') 216 | pause(.04) 217 | plot([node(nodenum1,1) node(nodenum2,1)],[node(nodenum1,2) node(nodenum2,2)],'-b') 218 | plot(node(nodenum1,1),node(nodenum1,2),'ow') 219 | plot(node(nodenum1,1),node(nodenum1,2),'*b') 220 | plot(node(nodenum2,1),node(nodenum2,2),'ow') 221 | plot(node(nodenum2,1),node(nodenum2,2),'*b') 222 | clc 223 | home 224 | 225 | if i>1 226 | answer2=input(' Same properties as previous element? (y/n) ','s'); 227 | end 228 | if answer2=='n' 229 | clc 230 | E=input(' Enter the modulus of elasticity of the member. '); 231 | G=input(' Enter the shear modulus of the member (zero for EB beam). '); 232 | I=input(' Enter the moment of area of the member. '); 233 | A=input(' Enter the cross sectional area of the member. '); 234 | Rho=input(' Enter the density per unit length of the member. '); 235 | end 236 | ncon(i,:)=[nodenum1 nodenum2 E A I G Rho]; 237 | answer=input(' Enter another element? (y/n) ','s'); 238 | if answer~='y',break,end 239 | end 240 | elseif strcmp(mode,'am') 241 | % adding concentrated masses and inertias 242 | conm=[]; 243 | for i=1:1000 244 | clc 245 | home 246 | if i==1 247 | answer=input(' Add concentrated masses and rotational inertias? (y/n) ','s'); 248 | end 249 | if i>1 250 | answer=input(' Add more concentrated masses and rotational inertias? (y/n) ','s'); 251 | end 252 | if answer~='y',break,end 253 | disp(' ') 254 | disp(' Pick node to add mass/rotational inertia to.') 255 | pause(.5) 256 | if point=='y' 257 | [x1 y1]=ginput(1); 258 | dis=(node(:,1)-x1).^2+(node(:,2)-y1).^2; 259 | [dsq,nodenum]=min(dis); 260 | else 261 | nodenum=input(' Enter node number: '); 262 | end 263 | plot(node(nodenum,1),node(nodenum,2),'*w') 264 | plot(node(nodenum,1),node(nodenum,2),'xr') 265 | answer=input(' Add mass or rotational inertia?(m,i,n(one)) ','s'); 266 | massval=input(' Enter magnitude of mass/inertia. '); 267 | conm(i,:)=[0 0 0]; 268 | conm(i,1)=nodenum; 269 | 270 | if answer=='m' 271 | conm(i,2)=massval; 272 | end 273 | if answer=='i' 274 | conm(i,3)=massval; 275 | end 276 | 277 | plot(node(nodenum,1),node(nodenum,2),'xi') 278 | plot(node(nodenum,1),node(nodenum,2),'*b') 279 | end 280 | elseif strcmp(mode,'abc') 281 | 282 | 283 | % zeroing of displacements 284 | zero=[];ij=0; 285 | for i=1:1000 286 | clc 287 | home 288 | if i==1 289 | answer=input(' Add boundary conditions? (y/n) ','s'); 290 | end 291 | if i>1 292 | answer=input(' Zero another displacement? (y/n) ','s'); 293 | end 294 | if answer~='y',break,end 295 | disp(' ') 296 | disp(' Pick node to zero') 297 | pause(1.) 298 | if point=='y' 299 | [x1 y1]=ginput(1); 300 | dis=(node(:,1)-x1).^2+(node(:,2)-y1).^2; 301 | [dsq,nodenum]=min(dis); 302 | else 303 | nodenum=input(' Enter node number: '); 304 | end 305 | plot(node(nodenum,1),node(nodenum,2),'*w') 306 | plot(node(nodenum,1),node(nodenum,2),'xr') 307 | disp(' ') 308 | disp(' ') 309 | disp(' Zero which displacement(s)?(x,y,t(heta),n(one))') 310 | disp(' (ie xt for x and theta)'); 311 | answern=input(' ','s'); 312 | sanswern=size(answern); 313 | for ii=1:sanswern(2) 314 | ij=ij+1; 315 | answer=answern(ii); 316 | if answer=='x' 317 | plot(node(nodenum,1),node(nodenum,2),'xi') 318 | plot(node(nodenum,1),node(nodenum,2),'*b') 319 | zero(ij,:)=[nodenum 1]; 320 | end 321 | if answer=='y' 322 | plot(node(nodenum,1),node(nodenum,2),'xi') 323 | plot(node(nodenum,1),node(nodenum,2),'*b') 324 | zero(ij,:)=[nodenum 2]; 325 | end 326 | if answer=='t' 327 | plot(node(nodenum,1),node(nodenum,2),'xi') 328 | plot(node(nodenum,1),node(nodenum,2),'*b') 329 | zero(ij,:)=[nodenum 3]; 330 | end 331 | if answer=='n' 332 | plot(node(nodenum,1),node(nodenum,2),'xi') 333 | plot(node(nodenum,1),node(nodenum,2),'*b') 334 | end 335 | end 336 | end 337 | elseif strcmp(mode,'af') 338 | force=[]; 339 | % adding loads 340 | for i=1:1000 341 | clc 342 | home 343 | answer=input(' Add loads? (y/n) ','s'); 344 | if answer~='y',break,end 345 | disp(' ') 346 | disp(' Pick node to load') 347 | pause(1.5) 348 | if point=='y' 349 | [x1 y1]=ginput(1); 350 | dis=(node(:,1)-x1).^2+(node(:,2)-y1).^2; 351 | [dsq,nodenum]=min(dis); 352 | else 353 | nodenum=input(' Enter node number: '); 354 | end 355 | plot(node(nodenum,1),node(nodenum,2),'*w') 356 | plot(node(nodenum,1),node(nodenum,2),'xr') 357 | answer=input('Load which displacement?(x,y,t(heta),n(one)) ','s'); 358 | 359 | if answer=='x' 360 | loadval=input(' Enter magnitude of load. '); 361 | force(i,:)=[nodenum 1 loadval]; 362 | end 363 | 364 | if answer=='y' 365 | loadval=input(' Enter magnitude of load. '); 366 | force(i,:)=[nodenum 2 loadval]; 367 | end 368 | 369 | if answer=='theta' 370 | loadval=input(' Enter magnitude of load. '); 371 | force(i,:)=[nodenum 3 loadval]; 372 | end 373 | 374 | answer=input(' Load another node? (y/n) ','s'); 375 | if answer~='y',break,end 376 | plot(node(nodenum,1),node(nodenum,2),'xi') 377 | plot(node(nodenum,1),node(nodenum,2),'*b') 378 | end 379 | node; 380 | ncon; 381 | zero; 382 | force; 383 | elseif strcmp(mode,'new') 384 | disp('new') 385 | node=zeros(1000,2); 386 | ncon=zeros(1000,7); 387 | zero=zeros(1000,2); 388 | conm=zeros(1000,2); 389 | force=zeros(1000,3); 390 | userdata{1}=node; 391 | userdata{2}=ncon; 392 | userdata{3}=conm; 393 | userdata{4}=zero; 394 | userdata{5}=force; 395 | set(gcf,'Userdata',userdata) 396 | 397 | elseif strcmp(mode,'open') 398 | [filename,pathname] = uigetfile('*_ang*','Select FEA file'); 399 | 400 | if filename==0 401 | break 402 | end 403 | 404 | delete(findobj('tag','opendlg')) 405 | 406 | Data=1:64;Data=(Data'*Data)/64; 407 | msgh=msgbox({'Initiating Load.' '' '' ''},'','custom',Data,hot(64)); 408 | set(msgh,'tag','opendlg') 409 | mschil=get(msgh,'children'); 410 | delete(findobj(mschil,'style','pushbutton')); 411 | sh=findobj(get(msgh,'children'),'type','uicontrol'); 412 | %disp('hi there') 413 | set(sh,'string',['Opening ' filename '.']) 414 | 415 | fid=fopen([pathname filename],'rt'); 416 | clear a time phi psi tht htracker7 htracker8 htracker9 417 | set(sh,'string','Clearing old data') 418 | 419 | dfile=dir([pathname filename]); 420 | set(sh,'string',{['Loading ' filename '.'] 'Please wait.'}) 421 | fprintf('File is %2.1f MB. \n',dfile.bytes/2^20) 422 | fprintf('Please wait.\n') 423 | 424 | 425 | line = fgetl(fid); 426 | 427 | a=fscanf(fid,'%g %g %g %g %g %g %g',[7 inf]); 428 | a=a'; 429 | if strcmp('T',line(1))~=1 430 | % set(sh,'string',{'First line of data file missing'... 431 | % 'Correcting'}) 432 | a=[str2num(line);a]; 433 | set(sh,'string','Data reconstructed') 434 | end 435 | a(:,1); 436 | time=a(:,1); 437 | phi=a(:,2); 438 | psi=a(:,3); 439 | tht=a(:,4); 440 | htracker7=a(:,5); 441 | htracker8=a(:,6); 442 | htracker9=a(:,7); 443 | 444 | 445 | 446 | st=fclose(fid); 447 | 448 | set(sh,'string',{[filename ' closed.'] 'Load complete.'}) 449 | %eval(['save ' filename '.mat']) 450 | %disp([filename '.mat saved.']) 451 | 452 | 453 | if gzipped==1 454 | set(sh,'string',['Gzipping ' filename ' on your ' computer... 455 | ' system in the background.']) 456 | if strcmp('MAC2',computer) 457 | gzip(pathname,filename); 458 | %figure(msgh) 459 | elseif isunix 460 | eval(['!gzip ' pathname filename ' &']) 461 | end 462 | end 463 | 464 | pause(.2) 465 | delete(msgh) 466 | 467 | 468 | 469 | 470 | elseif strcmp(mode,'save') 471 | disp('save') 472 | file_save_m 473 | %path(path,pwd) 474 | %answer=input(' Save configuration file (Else all will have been in vain)? (y/n) ','s'); 475 | %if answer=='y' 476 | % filename=input(' Enter name of configuration file. ','s'); 477 | % eval(['save ',filename,'.con',' node',' ncon',' zero',' force',' conm']); 478 | % answer=input(' Run analysis? (y/n) ','s'); 479 | % if answer=='y' 480 | % vtb8_2(filename); 481 | % vtb8_2(node,ncon,zero,force,conm); 482 | % end 483 | %end 484 | if answer=='y' 485 | [filename,pathname]=uiputfile('projectname.con','Save as:'); 486 | sfilename=size(filename); 487 | path(path,pathname) 488 | lfilename=sfilename(2); 489 | if filename(lfilename-3)=='.' 490 | filename=[filename(1:lfilename-4) '.con']; 491 | projectname=filename(1:lfilename-4); 492 | else 493 | filename=[filename '.con']; 494 | projectname=filename(1:lfilename-4); 495 | end 496 | pathname; 497 | sizepath=size(pathname); 498 | shortpathname=pathname(1:sizepath(2)-1); 499 | lsp=size(findstr(shortpathname,':')); 500 | if strcmp(computer,'MAC2') & lsp(1)==0 501 | shortpathname=[shortpathname ':']; 502 | end 503 | %path(shortpathname) 504 | cdpath=['cd ' '''' shortpathname '''' ];% Crazy quotes allow spaces 505 | % % in directory names. 506 | eval(cdpath) 507 | eval(['save ',filename,' node',' ncon',' zero',' force',' conm']); 508 | answer=input(' Run analysis? (y/n) ','s'); 509 | if answer=='y' 510 | vtb8_2(projectname); 511 | end 512 | end 513 | end 514 | end 515 | -------------------------------------------------------------------------------- /Modal_Analysis/frfgen2.m: -------------------------------------------------------------------------------- 1 | function H=frfgen2(A0,A1,B0,B1,B2,f) 2 | 3 | om=2*pi*j*f'; 4 | H=[]; 5 | I=eye(size(A0)); 6 | for i=1:length(om) 7 | Hnew=-((A0+A1*om(i)+I*om(i)^2)\(B0+B1*om(i)+B2*om(i)^2)).'; 8 | 9 | H=[H;Hnew]; 10 | end 11 | -------------------------------------------------------------------------------- /Modal_Analysis/mac.m: -------------------------------------------------------------------------------- 1 | function ModeAC=mac(u1,u2,opt) 2 | % MAC=MAC(Phi1,Phi2) 3 | % Calculate the Modal Assurance Criterion for 2 sets of modes 4 | % 5 | % Output is a matrix such that the n, m element correponds to the MAC value 6 | % between the nth mode of Phi1 and the mth mode of Phi2. 7 | 8 | ModeAC=[]; 9 | 10 | if size(u1)~=size(u2) 11 | 12 | disp('Either the number of modes doesn''t match or the length of the model vectors doesn''t match. Cannot compute.') 13 | ModeAC=0; 14 | return 15 | else 16 | if nargin==2 17 | for i=1:size(u1,2) 18 | for j=1:size(u1,2) 19 | %u1(:,i)'*u2(:,j); 20 | ModeAC(i,j)=(u1(:,i)'*u2(:,j))^2/((u1(:,i)'*u1(:,i))*(u2(:,j)'*u2(:,j)));% 21 | end 22 | end 23 | else 24 | for i=1:size(u1,2) 25 | for j=1:size(u1,2) 26 | ModeAC(i,j)=(u1(:,i)'*u2(:,j))/sqrt(((u1(:,i)'*u1(:,i))*(u2(:,j)'*u2(:,j))));% 27 | end 28 | end 29 | end 30 | end 31 | ModeAC=ModeAC'; -------------------------------------------------------------------------------- /Modal_Analysis/makehelp.m: -------------------------------------------------------------------------------- 1 | cd 'Documents:MyMath:vibrate:' 2 | pwd 3 | filename='asd.m'; 4 | 5 | dn=0; 6 | fidr=fopen(filename,'rt'); 7 | fidw=fopen(filename,'w'); 8 | l=fgets(fidr); 9 | fprintf(fidw,[ l(1:length(l)) ]); 10 | 11 | 12 | while dn~=1 13 | l=fgets(fidr); 14 | if strcmp(l(1),'%') 15 | fprintf(fidw,['%' l(1:length(l)) ]); 16 | else 17 | dn=1; 18 | end 19 | end 20 | dn=0; 21 | 22 | l=fgets(fidr); 23 | fprintf(fidw,'\n'); 24 | 25 | 26 | while dn~=1 27 | l=fgets(fidr); 28 | if strcmp(l(1),'%') 29 | fprintf(fidw,['%' l(1:length(l)) ]); 30 | else 31 | dn=1; 32 | end 33 | end 34 | 35 | 36 | fclose(fidw); 37 | fclose(fidr); 38 | pcode asd 39 | 40 | 41 | -------------------------------------------------------------------------------- /Modal_Analysis/mdofcf.m: -------------------------------------------------------------------------------- 1 | function [z,nf,u]=mdofcf(f,TF,Fmin,Fmax) 2 | %[z,nf,u]=mdofcf(f,FRF,Fmin,Fmax) Curve fit to MDOF FRF. 3 | % f is the frequency vector in Hz. 4 | % 5 | % FRF are columns comprised of the FRFs presuming single input, multiple output 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % u is the mode shape. 8 | % Only one peak may exist in the segment of the FRF passed to 9 | % sdofcf. No zeros may exist withing this segment. If so, 10 | % curve fitting becomes unreliable. 11 | % 12 | % If called without outputs, i.e. 13 | % mdofcf(f,FRF,Fmin,Fmax) 14 | % The FRFs and the fit to them will be plotted instead of output being 15 | % returned. 16 | % 17 | % If Fmin and Fmax are not entered, the min and max values in 18 | % f are used. 19 | % 20 | % If the first column of TF is a collocated (input and output location are 21 | % the same), then the mode shape returned is the mass normalized mode shape 22 | % 23 | % This can then be used to generate an identified mass, damping, and 24 | % stiffness matrix as shown in the following example. 25 | % 26 | % EXAMPLE: 27 | % M=eye(2)*2; 28 | % K=[2 -1;-1 2]; 29 | % C=.01*K; 30 | % [Freq,Recep1,Mobil1,Inert1]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); %Frequency response function between node 1 and itself 31 | % [Freq,Recep2,Mobil2,Inert2]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); %Frequency response function between node 1 and node 2 32 | % figure(1) 33 | % plot(Freq,20*log10(abs(Recep1))) 34 | % Recep=[Recep1 Recep2]; 35 | % Recep=Recep+.1*randn(size(Recep))+i*.1*randn(size(Recep)); 36 | % [z,nf,u]=mdofcf(Freq,Recep,.1,.12); 37 | % z(1,1)=z; 38 | % lambda(1,1)=(nf*2*pi)^2; 39 | % 40 | % S(:,1)=real(u);%/abs(sqrt(u(1))); 41 | % [z,nf,u]=mdofcf(Freq,Recep,.16,.25); 42 | % z(2,2)=z; 43 | % lambda(2,2)=(nf*2*pi)^2; 44 | % S(:,2)=real(u);%/abs(sqrt(u(1))); 45 | % dampingratios=diag(z) 46 | % naturalfrequencies=sqrt(diag(lambda))/2/pi 47 | % M=M 48 | % Midentified=S'\eye(2)/S%Make Mass matrix 49 | % K=K 50 | % Kidentified=S'\lambda/S%Make Stiffness Matrix 51 | % C=C 52 | % Cidentified=S'\(2*z*sqrt(lambda))/S%Make damping matrix 53 | 54 | % 55 | % Note that by changing the parts of Freq and Recep used 56 | % We can curve fit to other modes. 57 | 58 | % Copyright Joseph C. Slater, 10/8/99 59 | % Updated 11/8/99 to improve robustness 60 | % Updated 1/1/00 to improve robustness 61 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 62 | % Updated 5/1/01 to start adding MDOF. 63 | % Updated 5/15/01 to include frequency range for curve fitting 64 | % Updated 11/13/07 to mass normalize mode shapes 65 | % Updated 11/13/07 example to demonstrate ID of system matrices 66 | 67 | %disp('This is beta software written 07-May-2001') 68 | %disp('This code may not be used by anyone not authorized by J. Slater') 69 | %disp('This code will expire 15-Jun-2001') 70 | 71 | %if datenum('10-Jun-2001')1 177 | 178 | pause 179 | end 180 | clf 181 | figure(gcf) 182 | XoF=R((ll+1:2*ll),:)*a(:,mm); 183 | %plot([abs(XoF) abs(TF)]) 184 | %2*ll 185 | %plot(abs(w(ll:2*ll))) 186 | %pause 187 | %break 188 | 189 | Fmin=min(f); 190 | Fmax=max(f); 191 | phase=unwrap(angle(TF(:,mm)))*180/pi; 192 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 193 | %size(XoF) 194 | subplot(2,1,1) 195 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF(:,mm)))) 196 | 197 | as=axis; 198 | legend('Identified FRF','Experimental FRF',0) 199 | min(f); 200 | axis([Fmin Fmax as(3) as(4)]) 201 | title(['Frequency Response Function ' num2str(mm) ' Fit']) 202 | xlabel('Frequency (Hz)') 203 | ylabel('Mag (dB)') 204 | 205 | grid on 206 | zoom on 207 | 208 | drawnow 209 | 210 | % Fmin,Fmax,min(mag),max(mag) 211 | % axis([Fmin Fmax minmag maxmag]) 212 | %pause 213 | 214 | while phase2(in)>50 215 | phase2=phase2-360; 216 | end 217 | phased=phase2(in)-phase(in); 218 | phase=phase+round(phased/360)*360; 219 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 220 | subplot(2,1,2) 221 | plot(f,phase2,f,phase) 222 | xlabel('Frequency (Hz)') 223 | ylabel('Phase (deg)') 224 | legend('Identified FRF','Experimental FRF',0) 225 | 226 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 227 | gridmin_max=round(phmin_max/90)*90; 228 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 229 | grid on 230 | zoom on 231 | drawnow 232 | figure(gcf) 233 | disp(['DOF ' num2str(mm) ' of ' num2str(size(a,2)) '. Press return to plot next curve-fit FRF or end.']) 234 | end 235 | end 236 | -------------------------------------------------------------------------------- /Modal_Analysis/mdofcftry.m: -------------------------------------------------------------------------------- 1 | % Combine multiple signals into just one. Works great. 2 | 3 | M=eye(2); 4 | K=[2 -1;-1 2]; 5 | C=.01*K; 6 | [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 7 | figure(1) 8 | n=1*250; 9 | m=.5; 10 | f=Freq((1:n)+450*m); 11 | R2=Recep((1:n)+450*m); 12 | R2=R2+.1*randn(n,1)+.1*randn(n,1)*i;% Poorly Simulated Noise 13 | [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); 14 | R1=Recep((1:n)+450*m); 15 | R1=R1+.1*randn(n,1)+.1*randn(n,1)*i;% Poorly Simulated Noise 16 | [z,nf,a]=mdofcf(f,[R1 R2]) 17 | 18 | -------------------------------------------------------------------------------- /Modal_Analysis/mdofcfuse.m: -------------------------------------------------------------------------------- 1 | clf 2 | M=eye(2)*2; 3 | K=[2 -1;-1 2]; 4 | C=.01*K; 5 | [Freq,Recep1,Mobil1,Inert1]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); %Frequency response function between node 1 and itself 6 | [Freq,Recep2,Mobil2,Inert2]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); %Frequency response function between node 1 and node 2 7 | figure(1) 8 | plot(Freq,20*log10(abs(Recep1))) 9 | Recep=[Recep1 Recep2]; 10 | Recep=Recep+.1*randn(size(Recep))+i*.1*randn(size(Recep)); 11 | [z,nf,u]=mdofcf(Freq,Recep,.1,.12); 12 | z(1,1)=z; 13 | lambda(1,1)=(nf*2*pi)^2; 14 | 15 | S(:,1)=real(u);%/abs(sqrt(u(1))); 16 | [z,nf,u]=mdofcf(Freq,Recep,.16,.25); 17 | z(2,2)=z; 18 | lambda(2,2)=(nf*2*pi)^2; 19 | S(:,2)=real(u);%/abs(sqrt(u(1))); 20 | dampingratios=diag(z) 21 | naturalfrequencies=sqrt(diag(lambda))/2/pi 22 | M=M 23 | Midentified=S'\eye(2)/S%Make Mass matrix 24 | K=K 25 | Kidentified=S'\lambda/S%Make Stiffness Matrix 26 | C=C 27 | Cidentified=S'\(2*z*sqrt(lambda))/S%Make damping matrix 28 | 29 | -------------------------------------------------------------------------------- /Modal_Analysis/mmcf.m: -------------------------------------------------------------------------------- 1 | function [z,nf,u]=mmcf(f,H,Fmin,Fmax,nmodes) 2 | %[z,nf,u]=mmcf(f,TF,Fmin,Fmax,nmodes) Curve fit to MDOF FRF using polyreference. 3 | % f is the frequency vector in Hz. 4 | % 5 | % H is the complex frequency response functions, each FRF in a column. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % u is the mode shape. 8 | % 9 | % If Fmin and Fmax are not entered, the min and max values in 10 | % f are used. 11 | % 12 | % If nmodes is not included, it is estimated automatically. 13 | % 14 | % EXAMPLE: 15 | % M=eye(2); 16 | % K=[2 -1;-1 2]; 17 | % C=.01*K; 18 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 19 | % R1=Recep+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 20 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); 21 | % R2=Recep+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 22 | % [z,nf,u]=mmcf(Freq,[R1 R2]) 23 | % 24 | % Note that by changing the parts of Freq and Recep used 25 | % We can curve fit to other modes. 26 | 27 | % Copyright Joseph C. Slater, 10/8/99 28 | % Updated 11/8/99 to improve robustness 29 | % Updated 1/1/00 to improve robustness 30 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 31 | % Updated 5/1/01 to start adding MDOF. 32 | % Updated 5/15/01 to include frequency range for curve fitting 33 | % Modified from MDOFCF 7/1/01 to include multiple modes 34 | % Hacked 12/18/01 to no avail. Still doesn't work. 35 | 36 | 37 | 38 | inlow=1; 39 | inhigh=length(f); 40 | if nargin==4 |nargin==5 41 | inlow=floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1; 42 | inhigh=ceil(length(f)*(Fmax-min(f))/(max(f)-min(f)))+1; 43 | elseif nargin==3 44 | nmodes=Fmin; 45 | end 46 | 47 | if f(inlow)==0 48 | inlow=1; 49 | end 50 | size(f) 51 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 52 | % Here we make No x Ni blocks at the same frequencies when we have 53 | % MIMO data. 54 | Ni=size(H,2); 55 | No=size(H,3); 56 | if size(H,3)~=1 57 | f=f(inlow:inhigh,:); 58 | H=H(inlow:inhigh,:,:); 59 | 60 | Hold=H; 61 | fold=f; 62 | M=size(H,1); 63 | % If No>Ni, we need to fix this. This assumes reciprocity holds. 64 | if No>Ni 65 | H=zeros(Hold); 66 | for l=1:Ni 67 | H(:,:,l)=squeeze(H(:,l,:)); 68 | end 69 | end 70 | H=zeros(M*No,Ni); 71 | for l=1:No 72 | H(l:No:No*M,:)=Hold(:,:,l); 73 | f(l:No:No*M,1)=fold(:,1); 74 | end 75 | else 76 | f=f(inlow:inhigh,:); 77 | 78 | H=H(inlow:inhigh,:); 79 | end 80 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 81 | % tfplot(f(3:3:length(f),:),H(3:3:length(f),:)) 82 | % break 83 | % Reduce to nmodes FRF for finding poles: 84 | max(f),min(f) 85 | tfplot(f(3:3:2400),H(3:3:2400,1)) 86 | size(H),size(f) 87 | return 88 | R=(H'); 89 | [U,S,V]=svd(R); 90 | 91 | svals=diag(S) 92 | if nargin==2|nargin==4 93 | lenS=length(svals); 94 | countmodes=svals(2:lenS)>svals(1:lenS-1)*.05; 95 | nmodes=sum(countmodes)+1; 96 | disp([num2str(nmodes) ' modes found.']) 97 | end 98 | numfreq=nmodes; 99 | T=U(:,1:nmodes); 100 | Hp=(T')*R; 101 | R=(Hp'); 102 | H; 103 | %disp('R=H') 104 | %R=H; 105 | %tfplot(f,R) 106 | 107 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 108 | % From here on, the reduced FRFs are stored in R. 109 | 110 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 | % Now we make the negative frequency parts of the FRF (and frequency vector) 112 | % This allows us to obtain both poles in each pair. 113 | M=length(f)/No; % This change when we zoomed in frequency 114 | R=[conj(R(M*No:-1:1,:,:));R]; 115 | w=2*pi*[-f(M*No:-1:1);f]; 116 | M=length(w)/No; 117 | %tfplot(abs(w)/2/pi,R) 118 | 119 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 120 | % In order to obtain the companion matrix, we need to form the 121 | % H omega matrix. We then solve for the alpha-beta matrix, then find 122 | % eigenvalues and eigenvectors 123 | 124 | % order of the method being used 125 | % 1 is Craig (Multi Reference Frequency Domain) 126 | % % Polyreference Frequency Domain 127 | m=2; 128 | diagomega=spdiags(w*sqrt(-1),0,M*No,M*No); 129 | INo=spdiags(ones(No,M*No),[-No*(M-1):No:0],No*M,No); 130 | 131 | HO=zeros(M*No,Ni*m+No*(m+2)); 132 | %HO=sparse(HO); 133 | % Since we need one more beta column, and its power is zero, we 134 | % put it in up front. 135 | 136 | % We should fill in the one lowest H, and the 3 lowest Omegas, 137 | % since they are always there (in the generic first order case) 138 | % and loop only for the other terms. 139 | % 140 | % The higher Omega parts (beta) are not shown in Allemang's 141 | % paper, but they represent residual terms. 142 | % 143 | %tfplot(f,R) 144 | R; 145 | HO(:,1:Ni)=R; 146 | %pause 147 | HO(:,m*Ni+(1:No))=-INo; 148 | HO(:,m*Ni+No+(1:No))=-diagomega*INo; 149 | HO(:,m*Ni+2*No+(1:No))=-diagomega.^2*INo; 150 | 151 | 152 | for l=2:m 153 | HO(:,l*Ni+(1-Ni:0))=diagomega.^(l-1)*R; 154 | HO(:,m*Ni+(l+1)*No+(1:No))=-diagomega.^(l+1)*INo; 155 | end 156 | % We still need the right hand side of the equation 157 | RHS=-diagomega.^m*R; 158 | %disp('HO') 159 | %HO 160 | %RHS 161 | % Now the alpha-beta matrix comes from the least squares solution 162 | alphabeta=HO\RHS; 163 | %size(alphabeta) 164 | %(HO*alphabeta-RHS)./RHS 165 | %break 166 | % Here we need to assemble the state space (companion) matrix. 167 | if m==1 168 | C=-alphabeta(1:Ni,1:Ni); 169 | else 170 | C=spdiags(ones(Ni*(m-1),1),-Ni,Ni*m,Ni*m); 171 | % full(C) 172 | 173 | for im=1:m 174 | C(1:Ni,(m-im)*Ni+(1:Ni)); 175 | alphabeta((1:Ni)+Ni*(im-1),:); 176 | C(1:Ni,(m-im)*Ni+(1:Ni))=-alphabeta((1:Ni)+Ni*(im-1),:); 177 | end 178 | end 179 | %full(C) 180 | %%%%%%%%%%%%%(^%(&*^(^%^%*^%*^%()))*%^^)((((((((((((((((((((((((*^%&(^%*&^%&*^%&*%^*%^$ 181 | 182 | % Here we solve for eigenvalues and eigenvectors 183 | 184 | damp(full(C)) 185 | % Here we find the modal participation factors 186 | 187 | disp('What happened here?') 188 | 189 | %break 190 | % Here we translate the mode shapes and modal participation factors back into real space. 191 | 192 | % junk below here 193 | n=1; 194 | N=2*n; 195 | N=2; 196 | %[x,y]=meshgrid(0:N,R); 197 | %[x,w2d]=meshgrid(0:N,w); 198 | %disp('make c') 199 | tic 200 | %cold=diag(-w.^(N))*R; 201 | %size(c) 202 | %toc 203 | %disp('alternative make c') 204 | %numfreq= 205 | tic 206 | numfreq=1023; 207 | diagomega=spdiags(w,0,numfreq*2,numfreq*2); 208 | size(diagomega) 209 | size(R) 210 | c=-diagomega.^2*R; 211 | %size(c) 212 | %[w full(diag(diagomega))] 213 | %plot(real(diag(diagomega)),real(w)),pause,break 214 | 215 | 216 | 217 | %toc 218 | % The following line was from mdofcf 219 | %aa=[w2d(:,1+(0:N-1)).^x(:,1+(0:N-1)).*y(:,1+(0:N-1)) -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 220 | 221 | %Replacement line for previous line to handle a matrix, the columns of which are 222 | %individual FRFs. Tested first half 223 | % Right half unrewritten (from -w2d on). 224 | 225 | %The following line was an intermediate step. 226 | %aa2=[ R diag(w.^1)*R -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 227 | 228 | % Rewrite of above line. 229 | sizeR=size(R,2); 230 | %[junk,wspread]=meshgrid(size(R,2),w); 231 | tic 232 | %disp('make aa') 233 | aa=[ R diagomega*R -w.^0 -w.^1 -w.^2]; 234 | %toc 235 | %more on 236 | %aa2-aa3 237 | %aa2=aa3;toc 238 | %aa=aa2;toc 239 | %disp('get b'),tic 240 | %%%%%%%%%%%%%% junk above here 241 | b=aa\c;%toc 242 | 243 | %[1 b((N-1:-1:0)+1)']; 244 | 245 | 246 | %rs=roots([1 b((N-1:-1:0)+1)']) 247 | tic 248 | %disp('solve eigenvalue problem') 249 | b=conj(b'); 250 | [xx,ee]=polyeig(b(:,1:sizeR),b(:,sizeR+1:sizeR*2),eye(sizeR)); 251 | rs=ee; 252 | %toc 253 | % We want to sort eigenvalues in increasing order, prioritizing 254 | % the imaginary parts. Matlab sorts by magnitude. 255 | % Here we take only every other root since the other is the conjugate 256 | % and therefore redundant. 257 | rs(1:2:length(rs)); 258 | [yrs,irs]=sort(abs(imag(rs))); 259 | 260 | rs=rs(irs(1:2:sizeR*2)); 261 | 262 | omega=abs(rs); 263 | z=-real(rs)./abs(rs); 264 | nf=omega/2/pi; 265 | %toc 266 | 267 | 268 | % This section now gets repeated for each FRF. Still needs to be done for MDOF, to make a matrix a. 269 | %rs) 270 | %XoF=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w.^0) 1./w.^2];%;1./w2d(:,[1 3])]; 271 | 272 | %disp('OK, just expand this to multiple poles') 273 | [rsmesh,wmesh]=meshgrid([rs; conj(rs)],w); 274 | XoF1=1./(wmesh-rsmesh); 275 | 276 | %XoF1=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w-conj(rs(1))) 1./(w-conj(rs(2)))]; 277 | %XoF2=1./(w+rs(1)); 278 | XoF2=1./(w.^0); 279 | XoF3=1./w.^2; 280 | XoF=[XoF1 XoF2 XoF3]; 281 | 282 | %for i=1: 283 | 284 | H3=[H2;H]; 285 | 286 | %plot(unwrap(angle(H3))) 287 | a=XoF\H3; 288 | 289 | 290 | %size(w) 291 | %plot(abs(w)),pause 292 | %tfplot(f,H) 293 | %tfplot(f,[a*Rest,R]) 294 | %size(XoF) 295 | u=a(1:sizeR,:)'; 296 | 297 | %u=u/u(1); 298 | %u=u/norm(u); 299 | u=u/diag(exp(angle(u(1,:))*sqrt(-1))); 300 | R=XoF; 301 | for mm=1:size(a,2) 302 | 303 | if mm>1 304 | pause 305 | end 306 | clf 307 | figure(gcf) 308 | XoF=R((ll+1:2*ll),:)*a(:,mm); 309 | %plot([abs(XoF) abs(H)]) 310 | %2*ll 311 | %plot(abs(w(ll:2*ll))) 312 | %pause 313 | %break 314 | 315 | Fmin=min(f); 316 | Fmax=max(f); 317 | phase=unwrap(angle(H(:,mm)),pi*1.5)*180/pi; 318 | phase2=unwrap(angle(XoF),pi*1.5)*180/pi;size(phase); 319 | %size(XoF) 320 | subplot(2,1,1) 321 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(H(:,mm)))) 322 | 323 | as=axis; 324 | legend('Identified FRF','Experimental FRF',0) 325 | min(f); 326 | axis([Fmin Fmax as(3) as(4)]) 327 | title(['Frequency Response Function ' num2str(mm) ' Fit']) 328 | xlabel('Frequency (Hz)') 329 | ylabel('Mag (dB)') 330 | 331 | grid on 332 | zoom on 333 | 334 | drawnow 335 | 336 | % Fmin,Fmax,min(mag),max(mag) 337 | % axis([Fmin Fmax minmag maxmag]) 338 | %pause 339 | in=floor(length(f)/2); 340 | while phase2(in)>50 341 | phase2=phase2-360; 342 | end 343 | phased=phase2(in)-phase(in); 344 | phase=phase+round(phased/360)*360; 345 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 346 | subplot(2,1,2) 347 | plot(f,phase2,f,phase) 348 | xlabel('Frequency (Hz)') 349 | ylabel('Phase (deg)') 350 | legend('Identified FRF','Experimental FRF',0) 351 | 352 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 353 | gridmin_max=round(phmin_max/90)*90; 354 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 355 | grid on 356 | zoom on 357 | drawnow 358 | figure(gcf) 359 | end 360 | -------------------------------------------------------------------------------- /Modal_Analysis/mmcfnr.m: -------------------------------------------------------------------------------- 1 | function [z,nf,u]=mmcf(f,TF,Fmin,Fmax,nmodes) 2 | %[z,nf,u]=mmcf(f,TF,Fmin,Fmax,nmodes) Curve fit to MDOF FRF. 3 | % f is the frequency vector in Hz. 4 | % 5 | % TF is the complex transfer functions, each FRF in a column. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % u is the mode shape. 8 | % 9 | % If Fmin and Fmax are not entered, the min and max values in 10 | % f are used. 11 | % 12 | % If nmodes is not included, it is estimated automatically. 13 | % 14 | % EXAMPLE: 15 | % M=eye(2); 16 | % K=[2 -1;-1 2]; 17 | % C=.01*K; 18 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 19 | % R1=Recep+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 20 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); 21 | % R2=Recep+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 22 | % [z,nf,u]=mmcf(Freq,[R1 R2]) 23 | % 24 | % Note that by changing the parts of Freq and Recep used 25 | % We can curve fit to other modes. 26 | 27 | % Copyright Joseph C. Slater, 10/8/99 28 | % Updated 11/8/99 to improve robustness 29 | % Updated 1/1/00 to improve robustness 30 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 31 | % Updated 5/1/01 to start adding MDOF. 32 | % Updated 5/15/01 to include frequency range for curve fitting 33 | % Modified from MDOFCF 7/1/01 to include multiple modes 34 | 35 | disp('This is beta software written 02-Jun-2001') 36 | disp('This code may not be used by anyone not authorized by J. Slater') 37 | disp('This code will expire 01-Jan-2002') 38 | 39 | if datenum('10-Dec-2001')svals(1:lenS-1)*.05; 94 | nmodes=sum(countmodes)+1; 95 | disp([num2str(nmodes) ' modes found.']) 96 | end 97 | T=U(:,1:nmodes); 98 | Hp=(T')*R; 99 | R=(Hp'); 100 | tfplot(f,R) 101 | nmodes 102 | break 103 | %tfplot(f,R) 104 | %disp('This line needs to be removed or corrected') 105 | %R=(TF); 106 | 107 | % End reduction (whole thing is still stored in TF) 108 | w=f*2*pi*sqrt(-1); 109 | numfreq=length(w); 110 | %This replaces the next section, which is rather slow. 111 | %tic 112 | w3=zeros(size(w,1)*2,1); 113 | R4=zeros(size(w,1)*2,size(R,2)); 114 | TF3=zeros(size(w,1)*2,size(TF,2)); 115 | w3=[conj(w(numfreq:-1:1,:));w]; 116 | R4=[conj(R(numfreq:-1:1,:));R]; 117 | TF3=[conj(TF(numfreq:-1:1,:));TF]; 118 | %toc 119 | 120 | % Now we make the negative frequency parts of the FRF (and frequency vector) 121 | ll=length(f); 122 | tic 123 | w3=zeros(size(w,1)*2,1); 124 | w2=w*0; 125 | R3=R*0; 126 | 127 | for i=1:ll 128 | R3(i,:)=conj(R(ll+1-i,:)); 129 | w2(i,:)=conj(w(ll+1-i,:)); 130 | TF2(i,:)=conj(TF(ll+1-i,:)); 131 | end 132 | w=[w2;w]; 133 | R=[R3;R]; 134 | %toc 135 | %tfplot(imag(w)/2/pi,[R R4]); 136 | 137 | n=1; 138 | N=2*n; 139 | N=2; 140 | %[x,y]=meshgrid(0:N,R); 141 | %[x,w2d]=meshgrid(0:N,w); 142 | %disp('make c') 143 | %tic 144 | %cold=diag(-w.^(N))*R; 145 | %size(c) 146 | %toc 147 | %disp('alternative make c') 148 | %tic 149 | diagomega=spdiags(w,0,numfreq*2,numfreq*2); 150 | c=-diagomega.^2*R; 151 | %size(c) 152 | %[w full(diag(diagomega))] 153 | %plot(real(diag(diagomega)),real(w)),pause,break 154 | 155 | 156 | %toc 157 | % The following line was from mdofcf 158 | %aa=[w2d(:,1+(0:N-1)).^x(:,1+(0:N-1)).*y(:,1+(0:N-1)) -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 159 | 160 | %Replacement line for previous line to handle a matrix, the columns of which are 161 | %individual FRFs. Tested first half 162 | % Right half unrewritten (from -w2d on). 163 | 164 | %The following line was an intermediate step. 165 | %aa2=[ R diag(w.^1)*R -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 166 | 167 | % Rewrite of above line. 168 | sizeR=size(R,2); 169 | %[junk,wspread]=meshgrid(size(R,2),w); 170 | tic 171 | %disp('make aa') 172 | aa=[ R diagomega*R -w.^0 -w.^1 -w.^2]; 173 | %toc 174 | %more on 175 | %aa2-aa3 176 | %aa2=aa3;toc 177 | %aa=aa2;toc 178 | %disp('get b'),tic 179 | b=aa\c;%toc 180 | 181 | %[1 b((N-1:-1:0)+1)']; 182 | 183 | 184 | %rs=roots([1 b((N-1:-1:0)+1)']) 185 | tic 186 | %disp('solve eigenvalue problem') 187 | b=conj(b'); 188 | [xx,ee]=polyeig(b(:,1:sizeR),b(:,sizeR+1:sizeR*2),eye(sizeR)); 189 | rs=ee; 190 | %toc 191 | % We want to sort eigenvalues in increasing order, prioritizing 192 | % the imaginary parts. Matlab sorts by magnitude. 193 | % Here we take only every other root since the other is the conjugate 194 | % and therefore redundant. 195 | rs(1:2:length(rs)); 196 | [yrs,irs]=sort(abs(imag(rs))); 197 | 198 | rs=rs(irs(1:2:sizeR*2)); 199 | 200 | omega=abs(rs); 201 | z=-real(rs)./abs(rs); 202 | nf=omega/2/pi; 203 | %toc 204 | 205 | 206 | % This section now gets repeated for each FRF. Still needs to be done for MDOF, to make a matrix a. 207 | %rs) 208 | %XoF=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w.^0) 1./w.^2];%;1./w2d(:,[1 3])]; 209 | 210 | %disp('OK, just expand this to multiple poles') 211 | [rsmesh,wmesh]=meshgrid([rs; conj(rs)],w); 212 | XoF1=1./(wmesh-rsmesh); 213 | 214 | %XoF1=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w-conj(rs(1))) 1./(w-conj(rs(2)))]; 215 | %XoF2=1./(w+rs(1)); 216 | XoF2=1./(w.^0); 217 | XoF3=1./w.^2; 218 | XoF=[XoF1 XoF2 XoF3]; 219 | 220 | %for i=1: 221 | 222 | TF3=[TF2;TF]; 223 | 224 | %plot(unwrap(angle(TF3))) 225 | a=XoF\TF3; 226 | 227 | 228 | %size(w) 229 | %plot(abs(w)),pause 230 | %tfplot(f,TF) 231 | %tfplot(f,[a*Rest,R]) 232 | %size(XoF) 233 | u=a(1:sizeR,:)'; 234 | %u=u/u(1); 235 | %u=u/norm(u); 236 | u=u/diag(exp(angle(u(1,:))*sqrt(-1))); 237 | R=XoF; 238 | for mm=1:size(a,2) 239 | 240 | if mm>1 241 | pause 242 | end 243 | clf 244 | figure(gcf) 245 | XoF=R((ll+1:2*ll),:)*a(:,mm); 246 | %plot([abs(XoF) abs(TF)]) 247 | %2*ll 248 | %plot(abs(w(ll:2*ll))) 249 | %pause 250 | %break 251 | 252 | Fmin=min(f); 253 | Fmax=max(f); 254 | phase=unwrap(angle(TF(:,mm)),pi*1.5)*180/pi; 255 | phase2=unwrap(angle(XoF),pi*1.5)*180/pi;size(phase); 256 | %size(XoF) 257 | subplot(2,1,1) 258 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF(:,mm)))) 259 | 260 | as=axis; 261 | legend('Identified FRF','Experimental FRF',0) 262 | min(f); 263 | axis([Fmin Fmax as(3) as(4)]) 264 | title(['Frequency Response Function ' num2str(mm) ' Fit']) 265 | xlabel('Frequency (Hz)') 266 | ylabel('Mag (dB)') 267 | 268 | grid on 269 | zoom on 270 | 271 | drawnow 272 | 273 | % Fmin,Fmax,min(mag),max(mag) 274 | % axis([Fmin Fmax minmag maxmag]) 275 | %pause 276 | in=floor(length(f)/2); 277 | while phase2(in)>50 278 | phase2=phase2-360; 279 | end 280 | phased=phase2(in)-phase(in); 281 | phase=phase+round(phased/360)*360; 282 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 283 | subplot(2,1,2) 284 | plot(f,phase2,f,phase) 285 | xlabel('Frequency (Hz)') 286 | ylabel('Phase (deg)') 287 | legend('Identified FRF','Experimental FRF',0) 288 | 289 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 290 | gridmin_max=round(phmin_max/90)*90; 291 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 292 | grid on 293 | zoom on 294 | drawnow 295 | figure(gcf) 296 | end 297 | -------------------------------------------------------------------------------- /Modal_Analysis/mmcftry.m: -------------------------------------------------------------------------------- 1 | % Test case with repeated modes. 2 | clear all 3 | M=eye(3); 4 | K=[3 -1 -1;-1 3 -1;-1 -1 3]; 5 | C=.01*K; 6 | freqs=linspace(0,.5,800)';%+.0001; 7 | n=length(freqs); 8 | noise=0.00;%1; 9 | H=[]; 10 | for el=1:3 11 | for em=1:3 12 | [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,el,em,freqs); 13 | %figure(1) 14 | el,em 15 | R(:,el,em)=Recep+0*noise*(randn(n,1)+randn(n,1)*i); 16 | tfplot(Freq,R(:,el,em));figure(1);pause 17 | H=[H Recep]; 18 | end 19 | end 20 | %pause 21 | [z,nf,a]=mmcf(Freq,R) 22 | damp(state(M,C,K)) 23 | -------------------------------------------------------------------------------- /Modal_Analysis/modefit.m: -------------------------------------------------------------------------------- 1 | function [u]=modefit(f,H,poles) 2 | % f is in fricking Hz! 3 | %disp('Extracting modes') 4 | u=[]; 5 | if size(f,1)==1 6 | f=f'; 7 | end 8 | size(H); 9 | if size(poles,2)==1 10 | poles=poles.'; 11 | end 12 | 13 | p=size(H,1)/length(f); 14 | if length(f)~=size(H,1) 15 | if p~=floor(p) 16 | disp(['You cannot have ' num2str(size(H,2)/length(f)) ' outputs']) 17 | return 18 | end 19 | % H=Vscript(H,f*2*pi,0); 20 | % size(H); 21 | end 22 | ln=length(f)/2; 23 | %f=[-f;f]; 24 | %H=[conj(H);H]; 25 | 26 | 27 | modalh=zeros(size(H,1),length(poles)+2); 28 | 29 | poles; 30 | 31 | [P,OM]=meshgrid(poles,2*pi*f*1i); 32 | %abs(poles)/2/pi 33 | %poles 34 | %size(H) 35 | modalh(1:p:size(H,1),:)=[-1./(2*pi*f).^2 ones(length(f),1) 1./(OM-P)]; 36 | %disp('size modalh') 37 | %size(modalh) 38 | %tfplot(f,[modalh conj(modalh)]) 39 | for ii=2:p 40 | modalh(ii:p:size(H,1),:)=modalh(1:p:size(H,1),:); 41 | end 42 | modalh; 43 | 44 | BB=modalh\H; 45 | lp=length(poles); 46 | %B=transpose(BB(3:2:size(BB,1),:)) 47 | %diag(1./(poles(1:2:lp)-conj(poles(1:2:lp)))) 48 | u=transpose(BB(3:2:size(BB,1),:))*diag(1./(poles(1:2:lp)-conj(poles(1:2:lp)))); 49 | 50 | size(f); 51 | ln; 52 | ff=f((ln+1):2*ln,:); 53 | HH=H(ln+1:2*ln,:); 54 | tfplot(ff,[modalh(ln+1:ln*2,:)*BB HH]) 55 | tfplot(ff,(H)) 56 | %plot(f(ln+1:2*ln,:),20*log10(abs(H(ln+1:2*ln,:)))) 57 | %plot(f(ln+1:2*ln,:),f(ln+1:2*ln,:)) 58 | max(f(ln+1:2*ln,:)); 59 | min(f(ln+1:2*ln,:)); 60 | -------------------------------------------------------------------------------- /Modal_Analysis/polyref.m: -------------------------------------------------------------------------------- 1 | function [z,nf,poles,u]=polyref(f,H,Fmin,Fmax,nmodes) 2 | %[z,nf,poles,u]=mmcf(f,H,Fmin,Fmax,nmodes) Curve fit to MDOF FRF using polyreference. 3 | % f is the frequency vector in Hz. 4 | % H is the matrix of FRFs, in blocks of p outputs by o inputs, stacked 5 | % vertically by increasing frequency for each block. 6 | % 7 | % If Fmin and Fmax are not entered, the min and max values in 8 | % f are used. 9 | % nmodes is the number of modes to presume 10 | % If nmodes is left out, svd of the data is performed, and cool stuff 11 | % happens. Eventually 12 | % z and nf are the damping ratio and natural frequency (Hz) 13 | % p are the poles. 14 | % u are the mass normalized mode shapes, 15 | % 16 | % 17 | % EXAMPLE: 18 | % 19 | % E=7.31e10; 20 | % I=1/12*.03*.015^3; 21 | % rho=2747; 22 | % A=.015*.03; 23 | % L=0.5; 24 | % [f,h1]=vtb6_5(.1,.1,0,400,[E I rho A L],2,0.05,200); 25 | % [f,h2]=vtb6_5(.1,.15,0,400,[E I rho A L],2,0.05,200); 26 | % [f,h3]=vtb6_5(.1,.2,0,400,[E I rho A L],2,0.05,200); 27 | % [f,h4]=vtb6_5(.1,.25,0,400,[E I rho A L],2,0.05,200); 28 | % H=[h1 h2 h3 h4]; 29 | % tfplot(f,H) 30 | % [z,nf,poles,u]=polyref([f ],H,2) 31 | 32 | % Copyright Joseph C. Slater, 2/24/12 33 | 34 | 35 | z=[]; 36 | nf=[]; 37 | u=[]; 38 | p=size(H,1)/length(f); 39 | o=size(H,2); 40 | if length(f)~=size(H,1) 41 | if p~=floor(p) 42 | disp(['You cannot have ' num2str(size(H,2)/length(f)) ' outputs']) 43 | return 44 | end 45 | % H=Vscript(H,f*2*pi,0); 46 | % size(H); 47 | end 48 | 49 | if nargin==2 50 | nmodes =size(H,2); 51 | elseif nargin==3 52 | nmodes=Fmin; 53 | elseif nargin==4 54 | nmodes =size(H,2); 55 | inlow=max([floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1 1]); 56 | inhigh=min([ceil(length(f)*(Fmax-min(f))/(max(f)-min(f))) length(f)]); 57 | f=f(inlow:inhigh); 58 | H=H((1+(inlow-1)*p):(inhigh*p),:); 59 | elseif nargin==5 60 | inlow=max([floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1 1]); 61 | inhigh=min([ceil(length(f)*(Fmax-min(f))/(max(f)-min(f))) length(f)]); 62 | f=f(inlow:inhigh); 63 | H=H((1+(inlow-1)*p):(inhigh*p),:); 64 | end 65 | 66 | if p>o 67 | H=Vscript(H,f*2*pi,0); 68 | disp('p>o') 69 | end 70 | 71 | 72 | Horiginal=H; 73 | % Here we reduce the FRFs to the number of modes the user thinks we have. 74 | [U,S,V]=svd(H,'econ'); 75 | %disp('size u'); 76 | size(U); 77 | H=U(:,1:nmodes); 78 | 79 | 80 | if length(f)==size(H,1) 81 | size(H); 82 | H=Vscript(H,f*2*pi,0); 83 | size(H); 84 | end 85 | 86 | 87 | AA=[Vscript(H,f*2*pi,0) Uscript(size(H,2),f*2*pi,0)]\Vscript(H,f*2*pi,1); 88 | sA=size(AA,2); 89 | AA 90 | eig(AA(1:sA,1:sA)) 91 | [om,z,halfpoles]=damp(transpose(AA(1:sA,1:sA))) 92 | nf=om/2/pi; 93 | 94 | %poles(2:2:2*length(halfpoles),1)=halfpoles;poles(1:2:2*length(halfpoles),1)=conj(halfpoles); 95 | poles=halfpoles; 96 | 97 | u=modefit(f,Horiginal,poles); 98 | 99 | 100 | 101 | return 102 | 103 | disp('wtf') 104 | 105 | 106 | 107 | 108 | f=f(:); 109 | z=[];nf=[];u=[]; 110 | size(H) 111 | size(f) 112 | p=size(H,1)/length(f); 113 | 114 | if p~=floor(p) 115 | disp(['You cannot have ' num2str(p) ' outputs. Poorly formed H']) 116 | return 117 | 118 | 119 | else 120 | 121 | % Limit frequency range 122 | 123 | inlow=1; 124 | inhigh=length(f); 125 | if nargin==4 ||nargin==5 126 | inlow=floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1; 127 | inhigh=ceil(length(f)*(Fmax-min(f))/(max(f)-min(f))); 128 | elseif nargin==3 129 | nmodes=Fmin; 130 | end 131 | 132 | if f(inlow)==0 133 | inlow=1; 134 | end 135 | 136 | f=f(inlow:inhigh) 137 | numf=length(f); 138 | H=H((1+(inlow-1)*p):(inhigh*p),:) 139 | 140 | 141 | 142 | 143 | 144 | return 145 | 146 | 147 | 148 | 149 | 150 | 151 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 152 | % Here we make No x Ni blocks at the same frequencies when we have 153 | % MIMO data. 154 | Ni=size(H,2); 155 | No=size(H,3); 156 | if size(H,3)~=1 157 | f=f(inlow:inhigh,:); 158 | H=H(inlow:inhigh,:,:); 159 | 160 | Hold=H; 161 | fold=f; 162 | M=size(H,1); 163 | % If No>Ni, we need to fix this. This assumes reciprocity holds. 164 | if No>Ni 165 | H=zeros(Hold); 166 | for l=1:Ni 167 | H(:,:,l)=squeeze(H(:,l,:)); 168 | end 169 | end 170 | H=zeros(M*No,Ni); 171 | for l=1:No 172 | H(l:No:No*M,:)=Hold(:,:,l); 173 | f(l:No:No*M,1)=fold(:,1); 174 | end 175 | else 176 | H=H(inlow:inhigh,:); 177 | end 178 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 179 | % tfplot(f(3:3:length(f),:),H(3:3:length(f),:)) 180 | % break 181 | % Reduce to nmodes FRF for finding poles: 182 | max(f),min(f) 183 | tfplot(f(3:3:2400),H(3:3:2400,1)) 184 | size(H),size(f) 185 | return 186 | R=(H'); 187 | [U,S,V]=svd(R); 188 | 189 | svals=diag(S) 190 | if nargin==2|nargin==4 191 | lenS=length(svals); 192 | countmodes=svals(2:lenS)>svals(1:lenS-1)*.05; 193 | nmodes=sum(countmodes)+1; 194 | disp([num2str(nmodes) ' modes found.']) 195 | end 196 | numfreq=nmodes; 197 | T=U(:,1:nmodes); 198 | Hp=(T')*R; 199 | R=(Hp'); 200 | H; 201 | %disp('R=H') 202 | %R=H; 203 | %tfplot(f,R) 204 | 205 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 206 | % From here on, the reduced FRFs are stored in R. 207 | 208 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 209 | % Now we make the negative frequency parts of the FRF (and frequency vector) 210 | % This allows us to obtain both poles in each pair. 211 | M=length(f)/No; % This change when we zoomed in frequency 212 | R=[conj(R(M*No:-1:1,:,:));R]; 213 | w=2*pi*[-f(M*No:-1:1);f]; 214 | M=length(w)/No; 215 | %tfplot(abs(w)/2/pi,R) 216 | 217 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 218 | % In order to obtain the companion matrix, we need to form the 219 | % H omega matrix. We then solve for the alpha-beta matrix, then find 220 | % eigenvalues and eigenvectors 221 | 222 | % order of the method being used 223 | % 1 is Craig (Multi Reference Frequency Domain) 224 | % % Polyreference Frequency Domain 225 | m=2; 226 | diagomega=spdiags(w*sqrt(-1),0,M*No,M*No); 227 | INo=spdiags(ones(No,M*No),[-No*(M-1):No:0],No*M,No); 228 | 229 | HO=zeros(M*No,Ni*m+No*(m+2)); 230 | %HO=sparse(HO); 231 | % Since we need one more beta column, and its power is zero, we 232 | % put it in up front. 233 | 234 | % We should fill in the one lowest H, and the 3 lowest Omegas, 235 | % since they are always there (in the generic first order case) 236 | % and loop only for the other terms. 237 | % 238 | % The higher Omega parts (beta) are not shown in Allemang's 239 | % paper, but they represent residual terms. 240 | % 241 | %tfplot(f,R) 242 | R; 243 | HO(:,1:Ni)=R; 244 | %pause 245 | HO(:,m*Ni+(1:No))=-INo; 246 | HO(:,m*Ni+No+(1:No))=-diagomega*INo; 247 | HO(:,m*Ni+2*No+(1:No))=-diagomega.^2*INo; 248 | 249 | 250 | for l=2:m 251 | HO(:,l*Ni+(1-Ni:0))=diagomega.^(l-1)*R; 252 | HO(:,m*Ni+(l+1)*No+(1:No))=-diagomega.^(l+1)*INo; 253 | end 254 | % We still need the right hand side of the equation 255 | RHS=-diagomega.^m*R; 256 | %disp('HO') 257 | %HO 258 | %RHS 259 | % Now the alpha-beta matrix comes from the least squares solution 260 | alphabeta=HO\RHS; 261 | %size(alphabeta) 262 | %(HO*alphabeta-RHS)./RHS 263 | %break 264 | % Here we need to assemble the state space (companion) matrix. 265 | if m==1 266 | C=-alphabeta(1:Ni,1:Ni); 267 | else 268 | C=spdiags(ones(Ni*(m-1),1),-Ni,Ni*m,Ni*m); 269 | % full(C) 270 | 271 | for im=1:m 272 | C(1:Ni,(m-im)*Ni+(1:Ni)); 273 | alphabeta((1:Ni)+Ni*(im-1),:); 274 | C(1:Ni,(m-im)*Ni+(1:Ni))=-alphabeta((1:Ni)+Ni*(im-1),:); 275 | end 276 | end 277 | %full(C) 278 | %%%%%%%%%%%%%(^%(&*^(^%^%*^%*^%()))*%^^)((((((((((((((((((((((((*^%&(^%*&^%&*^%&*%^*%^$ 279 | 280 | % Here we solve for eigenvalues and eigenvectors 281 | 282 | damp(full(C)) 283 | % Here we find the modal participation factors 284 | 285 | disp('What happened here?') 286 | 287 | %break 288 | % Here we translate the mode shapes and modal participation factors back into real space. 289 | 290 | % junk below here 291 | n=1; 292 | N=2*n; 293 | N=2; 294 | %[x,y]=meshgrid(0:N,R); 295 | %[x,w2d]=meshgrid(0:N,w); 296 | %disp('make c') 297 | tic 298 | %cold=diag(-w.^(N))*R; 299 | %size(c) 300 | %toc 301 | %disp('alternative make c') 302 | %numfreq= 303 | tic 304 | numfreq=1023; 305 | diagomega=spdiags(w,0,numfreq*2,numfreq*2); 306 | size(diagomega) 307 | size(R) 308 | c=-diagomega.^2*R; 309 | %size(c) 310 | %[w full(diag(diagomega))] 311 | %plot(real(diag(diagomega)),real(w)),pause,break 312 | 313 | 314 | 315 | %toc 316 | % The following line was from mdofcf 317 | %aa=[w2d(:,1+(0:N-1)).^x(:,1+(0:N-1)).*y(:,1+(0:N-1)) -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 318 | 319 | %Replacement line for previous line to handle a matrix, the columns of which are 320 | %individual FRFs. Tested first half 321 | % Right half unrewritten (from -w2d on). 322 | 323 | %The following line was an intermediate step. 324 | %aa2=[ R diag(w.^1)*R -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 325 | 326 | % Rewrite of above line. 327 | sizeR=size(R,2); 328 | %[junk,wspread]=meshgrid(size(R,2),w); 329 | tic 330 | %disp('make aa') 331 | aa=[ R diagomega*R -w.^0 -w.^1 -w.^2]; 332 | %toc 333 | %more on 334 | %aa2-aa3 335 | %aa2=aa3;toc 336 | %aa=aa2;toc 337 | %disp('get b'),tic 338 | %%%%%%%%%%%%%% junk above here 339 | b=aa\c;%toc 340 | 341 | %[1 b((N-1:-1:0)+1)']; 342 | 343 | 344 | %rs=roots([1 b((N-1:-1:0)+1)']) 345 | tic 346 | %disp('solve eigenvalue problem') 347 | b=conj(b'); 348 | [xx,ee]=polyeig(b(:,1:sizeR),b(:,sizeR+1:sizeR*2),eye(sizeR)); 349 | rs=ee; 350 | %toc 351 | % We want to sort eigenvalues in increasing order, prioritizing 352 | % the imaginary parts. Matlab sorts by magnitude. 353 | % Here we take only every other root since the other is the conjugate 354 | % and therefore redundant. 355 | rs(1:2:length(rs)); 356 | [yrs,irs]=sort(abs(imag(rs))); 357 | 358 | rs=rs(irs(1:2:sizeR*2)); 359 | 360 | omega=abs(rs); 361 | z=-real(rs)./abs(rs); 362 | nf=omega/2/pi; 363 | %toc 364 | 365 | 366 | % This section now gets repeated for each FRF. Still needs to be done for MDOF, to make a matrix a. 367 | %rs) 368 | %XoF=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w.^0) 1./w.^2];%;1./w2d(:,[1 3])]; 369 | 370 | %disp('OK, just expand this to multiple poles') 371 | [rsmesh,wmesh]=meshgrid([rs; conj(rs)],w); 372 | XoF1=1./(wmesh-rsmesh); 373 | 374 | %XoF1=[1./(w-rs(1)) 1./(w-rs(2)) 1./(w-conj(rs(1))) 1./(w-conj(rs(2)))]; 375 | %XoF2=1./(w+rs(1)); 376 | XoF2=1./(w.^0); 377 | XoF3=1./w.^2; 378 | XoF=[XoF1 XoF2 XoF3]; 379 | 380 | %for i=1: 381 | 382 | H3=[H2;H]; 383 | 384 | %plot(unwrap(angle(H3))) 385 | a=XoF\H3; 386 | 387 | 388 | %size(w) 389 | %plot(abs(w)),pause 390 | %tfplot(f,H) 391 | %tfplot(f,[a*Rest,R]) 392 | %size(XoF) 393 | u=a(1:sizeR,:)'; 394 | 395 | %u=u/u(1); 396 | %u=u/norm(u); 397 | u=u/diag(exp(angle(u(1,:))*sqrt(-1))); 398 | R=XoF; 399 | for mm=1:size(a,2) 400 | 401 | if mm>1 402 | pause 403 | end 404 | clf 405 | figure(gcf) 406 | XoF=R((ll+1:2*ll),:)*a(:,mm); 407 | %plot([abs(XoF) abs(H)]) 408 | %2*ll 409 | %plot(abs(w(ll:2*ll))) 410 | %pause 411 | %break 412 | 413 | Fmin=min(f); 414 | Fmax=max(f); 415 | phase=unwrap(angle(H(:,mm)),pi*1.5)*180/pi; 416 | phase2=unwrap(angle(XoF),pi*1.5)*180/pi;size(phase); 417 | %size(XoF) 418 | subplot(2,1,1) 419 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(H(:,mm)))) 420 | 421 | as=axis; 422 | legend('Identified FRF','Experimental FRF',0) 423 | min(f); 424 | axis([Fmin Fmax as(3) as(4)]) 425 | title(['Frequency Response Function ' num2str(mm) ' Fit']) 426 | xlabel('Frequency (Hz)') 427 | ylabel('Mag (dB)') 428 | 429 | grid on 430 | zoom on 431 | 432 | drawnow 433 | 434 | % Fmin,Fmax,min(mag),max(mag) 435 | % axis([Fmin Fmax minmag maxmag]) 436 | %pause 437 | in=floor(length(f)/2); 438 | while phase2(in)>50 439 | phase2=phase2-360; 440 | end 441 | phased=phase2(in)-phase(in); 442 | phase=phase+round(phased/360)*360; 443 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 444 | subplot(2,1,2) 445 | plot(f,phase2,f,phase) 446 | xlabel('Frequency (Hz)') 447 | ylabel('Phase (deg)') 448 | legend('Identified FRF','Experimental FRF',0) 449 | 450 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 451 | gridmin_max=round(phmin_max/90)*90; 452 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 453 | grid on 454 | zoom on 455 | drawnow 456 | figure(gcf) 457 | end 458 | end -------------------------------------------------------------------------------- /Modal_Analysis/polyref2.m: -------------------------------------------------------------------------------- 1 | function [z,nf,poles,u]=polyref2(f,H,Fmin,Fmax,nmodes,options) 2 | %[z,nf,poles,u]=mmcf(f,H,Fmin,Fmax,nmodes) Curve fit to MDOF FRF using polyreference. 3 | % f is the frequency vector in Hz. 4 | % H is the matrix of FRFs, in blocks of p outputs by o inputs, stacked 5 | % vertically by increasing frequency for each block. 6 | % 7 | % If Fmin and Fmax are not entered, the min and max values in 8 | % f are used. 9 | % nmodes is the number of modes to presume 10 | % If nmodes is left out, svd of the data is performed, and cool stuff 11 | % happens. Eventually 12 | % z and nf are the damping ratio and natural frequency (Hz) 13 | % p are the poles. 14 | % u are the mass normalized mode shapes, 15 | % options=[viewsvd reviewfit debug] 16 | % viewsvd=1 plots svds and prompts the user for a number of modes for 17 | % viewsvd=2 attempts to chose number of modes automatically 18 | % reviewfit=1 plots the reduced FRFs against the curve fits, 1 at a time 19 | % debug=1 causes a whole bunch of diagnostics to be displayed 20 | % 21 | % EXAMPLE: 22 | % 23 | % E=7.31e10; 24 | % I=1/12*.03*.015^3; 25 | % rho=2747; 26 | % A=.015*.03; 27 | % L=0.5; 28 | % [f,h1]=vtb6_5(.1,.1,0,400,[E I rho A L],2,0.005,200); 29 | % [f,h2]=vtb6_5(.1,.15,0,400,[E I rho A L],2,0.005,200); 30 | % [f,h3]=vtb6_5(.1,.2,0,400,[E I rho A L],2,0.005,200); 31 | % [f,h4]=vtb6_5(.1,.25,0,400,[E I rho A L],2,0.005,200); 32 | % H=[h1 h2 h3 h4]; 33 | % tfplot(f,H) 34 | % [z,nf,poles,u]=polyref2([f ],H,2) 35 | % 36 | % EXAMPLE: 37 | % M=eye(2); 38 | % K=[2 -1;-1 2]; 39 | % C=.01*K; 40 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 41 | % R1=Recep;%+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 42 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); 43 | % R2=Recep;%+.1*randn(1024,1)+.1*randn(1024,1)*i;% Poorly Simulated Noise 44 | % [z,nf,poles,u]=polyref2(Freq,[R1 R2],2) 45 | 46 | % Copyright Joseph C. Slater, 2/24/12 47 | 48 | global freqdebug 49 | freqdebug=0; 50 | reviewfit=0; 51 | viewsvd=0; 52 | if nargin==6 53 | if length(options)>1 54 | reviewfit=options(2); 55 | end 56 | if length(options)>2 57 | freqdebug=options(3); 58 | end 59 | viewsvd=options(1); 60 | end 61 | 62 | z=[]; 63 | nf=[]; 64 | u=[]; 65 | p=size(H,1)/length(f); 66 | o=size(H,2); 67 | if length(f)~=size(H,1) 68 | if p~=floor(p) 69 | disp(['You cannot have ' num2str(size(H,2)/length(f)) ' outputs']) 70 | return 71 | end 72 | end 73 | 74 | if nargin==2 75 | nmodes =size(H,2); 76 | elseif nargin==3 77 | nmodes=Fmin; 78 | elseif nargin==4 79 | nmodes =size(H,2); 80 | inlow=max([floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1 1]); 81 | inhigh=min([ceil(length(f)*(Fmax-min(f))/(max(f)-min(f))) length(f)]); 82 | f=f(inlow:inhigh); 83 | H=H((1+(inlow-1)*p):(inhigh*p),:); 84 | elseif nargin==5|nargin==6 85 | Fmin=max([Fmin min(f)]); 86 | Fmax=min([Fmax max(f)]); 87 | inlow=max([floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1 1]) 88 | inhigh=min([ceil(length(f)*(Fmax-min(f))/(max(f)-min(f))) length(f)]) 89 | size(f) 90 | 91 | f=f(inlow:inhigh); 92 | H=H((1+(inlow-1)*p):(inhigh*p),:); 93 | end 94 | 95 | if freqdebug==1, disp('Appending FRF'),end 96 | 97 | f=[-f ;f]; 98 | H=[conj(H);H]; 99 | 100 | 101 | if p>o 102 | if freqdebug==1, disp('Re-sorting H'),end 103 | 104 | H=Vscript(H,f*2*pi,0); 105 | disp('p>o') 106 | end 107 | 108 | Horiginal=H; 109 | % Here we reduce the FRFs to the number of modes the user thinks we have. 110 | if freqdebug==1, disp('Reducing FRFs'),end 111 | 112 | [U,S,~]=svd(H,'econ'); 113 | lf=length(f); 114 | percentcontent=0; 115 | ii=0; 116 | ds=diag(S); 117 | while percentcontent<.75&&ii50 160 | phase2=phase2-360; 161 | end 162 | phased=phase2(in)-phase(in); 163 | phase=phase+round(phased/360)*360; 164 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 165 | subplot(2,1,2) 166 | plot(f,phase2,f,phase) 167 | xlabel('Frequency (Hz)') 168 | ylabel('Phase (deg)') 169 | legend('Identified FRF','Experimental FRF',0) 170 | 171 | grid on 172 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 173 | gridmin_max=round(phmin_max/90)*90; 174 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 175 | zoom on 176 | a=a(1)^2/(2*pi*nf)^2; 177 | 178 | if nargout==0 179 | disp('') 180 | disp(['zeta = ' num2str(z)]) 181 | disp(['f = ' num2str(nf) ' Hz.']) 182 | disp(['amplitude = ' num2str(2*imag(a(1))^2) '.']) 183 | disp('') 184 | clear z a nf 185 | end 186 | %disp('error still needing correction to use 7.38') 187 | %figure,tfplot(f,(a^2)./((nf*2*pi)^2-(2*pi*f).^2+z*2*nf*2*pi*2*pi*f*sqrt(-1))) 188 | -------------------------------------------------------------------------------- /Modal_Analysis/sdofcf2.m: -------------------------------------------------------------------------------- 1 | function [z,nf,a]=sdofcf2(f,TF,Fmin,Fmax) 2 | %[z,nf,a]=sdof(f,TF,Fmin,Fmax) Curve fit to SDOF FRF. 3 | % f is the frequency vector in Hz. It does not have to 4 | % start at 0 Hz. 5 | % TF is the complex transfer function. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % a is the numerator of the identified transfer function. 8 | % a 9 | % T=------------------ 10 | % 1-r^2+2 zeta r j 11 | % Only one peak may exist in the segment of the FRF passed to 12 | % sdofcf. No zeros may exist withing this segment. If so, 13 | % curve fitting becomes unreliable. 14 | % Fmin is the minimum frequency to be used for curve fitting in the 15 | % FRF 16 | % Fmax is the maximum frequency to be used for curve fitting in the 17 | % FRF 18 | % Updated to be consitent with Vibration Testing, section 8.2 19 | % 20 | % 21 | % EXAMPLE: 22 | % M=eye(2); 23 | % K=[2 -1;-1 2]; 24 | % C=.01*K; 25 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 26 | % figure(1) 27 | % n=length(Freq); 28 | % f2=Freq; 29 | % R2=Recep; 30 | % R2=R2+1*randn(n,1)+1*randn(n,1)*i;% Poorly Simulated Noise 31 | % [z,nf,a]=sdofcf2(f2,R2,.14,.17),pause 32 | % [z,nf,a]=sdofcf2(f2,R2,.27,.28) 33 | % 34 | % 35 | % Note that by changing the parts of Freq and Recep used 36 | % We can curve fit to other modes. 37 | 38 | % Copyright Joseph C. Slater, 10/8/99 39 | % Updated 11/8/99 to improve robustness 40 | % Updated 1/1/00 to improve robustness 41 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 42 | % 5/1/01 included residuals properly (Undocumented). 43 | % 4/15/03 added limits for frequency of FRF curve fit. 44 | 45 | %tfplot(f,TF) 46 | %pause 47 | 48 | 49 | % Select frequency range to curve fit 50 | inlow=1; 51 | inhigh=length(f); 52 | if nargin==4 53 | inlow=floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1; 54 | inhigh=ceil(length(f)*(Fmax-min(f))/(max(f)-min(f)))+1; 55 | end 56 | 57 | if f(inlow)==0 58 | inlow=2; 59 | end 60 | fold=f;%test code 61 | f=f(inlow:inhigh,:); 62 | TF=TF(inlow:inhigh,:); 63 | R=TF; 64 | 65 | %------------------------------------------- 66 | 67 | 68 | % 69 | ll=length(f); 70 | w=f*2*pi*sqrt(-1); 71 | w2=w*0; 72 | R3=R*0; 73 | num=2 74 | if 1==num 75 | for i=1:ll 76 | R3(i)=conj(R(ll+1-i)); 77 | w2(i)=conj(w(ll+1-i)); 78 | end 79 | w=[w2;w]; 80 | R=[R3;R]; 81 | [w R]; 82 | end 83 | 84 | %plot((w/sqrt(-1)),20*log10(abs(R))) 85 | 86 | n=1; 87 | %N=2*n; 88 | N=2; 89 | [x,y]=meshgrid(2:3,R); 90 | [x,w2da]=meshgrid(2:3,w); 91 | 92 | [x2,w2db]=meshgrid(0:4,w); 93 | matrix2tex(w/sqrt(-1)) 94 | w 95 | c=-w.^(4).*R; 96 | 97 | 98 | aa=[y.*w2da.^x -w2db.^x2] 99 | matrix2tex(aa,'%4.3f') 100 | matrix2tex(c) 101 | 102 | b=aa\c; 103 | matrix2tex(b) 104 | bb=[1 b(2) b(1) 0 0]; 105 | b=roots(bb); 106 | 107 | 108 | rs=b(3:4); 109 | [srs,irs]=sort(abs(imag(rs))); 110 | 111 | rs=rs(irs); 112 | rs; 113 | omega=abs(rs(2)); 114 | z=-real(rs(2))/abs(rs(2)); 115 | nf=omega/2/pi; 116 | 117 | 118 | XoF1=[1./(w-rs(1)) 1./(w-rs(2))]; 119 | 120 | XoF2=1./(w.^0); 121 | XoF3=1./w.^2; 122 | XoF=[XoF1 XoF2 XoF3]; 123 | %a=1; 124 | size(XoF); 125 | size(R); 126 | a=XoF\R; 127 | %size(w) 128 | %plot(abs(w)),pause 129 | %tfplot(f,TF) 130 | %tfplot(f,[a*Rest,R]) 131 | %size(XoF) 132 | 133 | 134 | 135 | 136 | 137 | if 1==num 138 | disp('aaaaaaaaaaaaaaaaaaaaaa') 139 | XoF=XoF((ll+1:2*ll)-2*0,:)*a; 140 | else 141 | disp('bbbbbbbbbbbbbbb') 142 | 143 | XoF=XoF*a; 144 | end 145 | 146 | w=fold*2*pi*sqrt(-1); 147 | XoF1=[1./(w-rs(1)) 1./(w-rs(2))]; 148 | 149 | XoF2=1./(w.^0); 150 | XoF3=1./w.^2; 151 | XoF=[XoF1 XoF2 XoF3]; 152 | %a=XoF\R; 153 | 154 | XoF=XoF*a; 155 | fnew=f 156 | f=fold 157 | 158 | a=sqrt(-2*imag(a(1))*imag(rs(1))-2*real(a(1))*real(rs(1))); 159 | 160 | %plot(abs(w(ll:2*ll))) 161 | %pause 162 | %break 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | %Plotting 171 | Fmin=min(f); 172 | Fmax=max(f); 173 | phase=unwrap(angle(TF))*180/pi; 174 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 175 | 176 | subplot(2,1,1) 177 | plot(f,20*log10(abs(XoF)),fnew,20*log10(abs(TF)),'*') 178 | as=axis; 179 | zoom on 180 | legend('Identified FRF','Experimental FRF',0) 181 | min(f); 182 | 183 | axis([Fmin Fmax as(3) as(4)]) 184 | axis 185 | xlabel('Frequency (Hz)') 186 | ylabel('Mag (dB)') 187 | grid on 188 | % Fmin,Fmax,min(mag),max(mag) 189 | % axis([Fmin Fmax minmag maxmag]) 190 | [TFmax,in]=max(abs(TF)); 191 | while phase2(in)>50 192 | phase2=phase2-360; 193 | end 194 | phased=phase2(in)-phase(in); 195 | phase=phase+round(phased/360)*360; 196 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 197 | subplot(2,1,2) 198 | plot(f,phase2,fnew,phase) 199 | xlabel('Frequency (Hz)') 200 | ylabel('Phase (deg)') 201 | legend('Identified FRF','Experimental FRF',0) 202 | 203 | grid on 204 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 205 | gridmin_max=round(phmin_max/90)*90; 206 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 207 | zoom on 208 | a=a(1)^2/(2*pi*nf)^2; 209 | 210 | if nargout==0 211 | disp('') 212 | disp(['zeta = ' num2str(z)]) 213 | disp(['f = ' num2str(nf) ' Hz.']) 214 | disp(['amplitude = ' num2str(2*imag(a(1))^2) '.']) 215 | disp('') 216 | clear z a nf 217 | end 218 | %disp('error still needing correction to use 7.38') 219 | %figure,tfplot(f,(a^2)./((nf*2*pi)^2-(2*pi*f).^2+z*2*nf*2*pi*2*pi*f*sqrt(-1))) 220 | -------------------------------------------------------------------------------- /Modal_Analysis/sdofcf2a.m: -------------------------------------------------------------------------------- 1 | function [z,nf,a]=sdofcf2(f,TF,Fmin,Fmax) 2 | %[z,nf,a]=sdof(f,TF,Fmin,Fmax) Curve fit to SDOF FRF. 3 | % f is the frequency vector in Hz. It does not have to 4 | % start at 0 Hz. 5 | % TF is the complex transfer function. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % a is the numerator of the identified transfer function. 8 | % a 9 | % T=------------------ 10 | % 1-r^2+2 zeta r j 11 | % Only one peak may exist in the segment of the FRF passed to 12 | % sdofcf. No zeros may exist withing this segment. If so, 13 | % curve fitting becomes unreliable. 14 | % Fmin is the minimum frequency to be used for curve fitting in the 15 | % FRF 16 | % Fmax is the maximum frequency to be used for curve fitting in the 17 | % FRF 18 | % Updated to be consitent with Vibration Testing, section 8.2 19 | % 20 | % 21 | % EXAMPLE: 22 | % M=eye(2); 23 | % K=[2 -1;-1 2]; 24 | % C=.01*K; 25 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 26 | % figure(1) 27 | % n=length(Freq); 28 | % f2=Freq; 29 | % R2=Recep; 30 | % R2=R2+1*randn(n,1)+1*randn(n,1)*i;% Poorly Simulated Noise 31 | % [z,nf,a]=sdofcf2(f2,R2,.14,.17),pause 32 | % [z,nf,a]=sdofcf2(f2,R2,.27,.28) 33 | % 34 | % 35 | % Note that by changing the parts of Freq and Recep used 36 | % We can curve fit to other modes. 37 | 38 | % Copyright Joseph C. Slater, 10/8/99 39 | % Updated 11/8/99 to improve robustness 40 | % Updated 1/1/00 to improve robustness 41 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 42 | % 5/1/01 included residuals properly (Undocumented). 43 | % 4/15/03 added limits for frequency of FRF curve fit. 44 | 45 | %tfplot(f,TF) 46 | %pause 47 | 48 | 49 | % Select frequency range to curve fit 50 | inlow=1; 51 | inhigh=length(f); 52 | if nargin==4 53 | inlow=floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1; 54 | inhigh=ceil(length(f)*(Fmax-min(f))/(max(f)-min(f)))+1; 55 | end 56 | 57 | if f(inlow)==0 58 | inlow=2; 59 | end 60 | fold=f;%test code 61 | f=f(inlow:inhigh,:); 62 | TF=TF(inlow:inhigh,:); 63 | R=TF; 64 | 65 | %------------------------------------------- 66 | 67 | 68 | % 69 | ll=length(f); 70 | w=f*2*pi*sqrt(-1); 71 | w2=w*0; 72 | R3=R*0; 73 | num=2 74 | if 1==num 75 | for i=1:ll 76 | R3(i)=conj(R(ll+1-i)); 77 | w2(i)=conj(w(ll+1-i)); 78 | end 79 | w=[w2;w]; 80 | R=[R3;R]; 81 | [w R]; 82 | end 83 | 84 | %plot((w/sqrt(-1)),20*log10(abs(R))) 85 | 86 | n=1; 87 | %N=2*n; 88 | N=2; 89 | [x,y]=meshgrid(2:3,R); 90 | matrix2tex(R) 91 | [x,w2da]=meshgrid(2:3,w); 92 | 93 | [x2,w2db]=meshgrid(0:4,w); 94 | matrix2tex(w/sqrt(-1)) 95 | w 96 | c=-w.^(4).*R; 97 | 98 | 99 | aa=[y.*w2da.^x -w2db.^x2] 100 | matrix2tex(aa,'%4.2f') 101 | matrix2tex(c) 102 | 103 | b=aa\c; 104 | b 105 | imag(b(4))==0 106 | matrix2tex(b) 107 | bb=[1 b(2) b(1) 0 0]; 108 | b=roots(bb); 109 | 110 | 111 | rs=b(3:4); 112 | [srs,irs]=sort(abs(imag(rs))); 113 | 114 | rs=rs(irs); 115 | rs; 116 | omega=abs(rs(2)); 117 | z=-real(rs(2))/abs(rs(2)); 118 | nf=omega/2/pi; 119 | 120 | 121 | XoF1=[1./(w-rs(1)) 1./(w-rs(2))]; 122 | 123 | XoF2=1./(w.^0); 124 | XoF3=1./w.^2; 125 | XoF=[XoF1 XoF2 XoF3]; 126 | %a=1; 127 | size(XoF); 128 | size(R); 129 | a=XoF\R; 130 | %size(w) 131 | %plot(abs(w)),pause 132 | %tfplot(f,TF) 133 | %tfplot(f,[a*Rest,R]) 134 | %size(XoF) 135 | 136 | 137 | 138 | 139 | 140 | if 1==num 141 | disp('aaaaaaaaaaaaaaaaaaaaaa') 142 | XoF=XoF((ll+1:2*ll)-2*0,:)*a; 143 | else 144 | disp('b') 145 | 146 | XoF=XoF*a; 147 | end 148 | 149 | a=sqrt(-2*imag(a(1))*imag(rs(1))-2*real(a(1))*real(rs(1))); 150 | 151 | %plot(abs(w(ll:2*ll))) 152 | %pause 153 | %break 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | %Plotting 162 | Fmin=min(f); 163 | Fmax=max(f); 164 | phase=unwrap(angle(TF))*180/pi; 165 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 166 | 167 | subplot(2,1,1) 168 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF)),'*') 169 | as=axis; 170 | zoom on 171 | legend('Identified FRF','Experimental FRF',0) 172 | min(f); 173 | 174 | axis([Fmin Fmax as(3) as(4)]) 175 | axis 176 | xlabel('Frequency (Hz)') 177 | ylabel('Mag (dB)') 178 | grid on 179 | % Fmin,Fmax,min(mag),max(mag) 180 | % axis([Fmin Fmax minmag maxmag]) 181 | [TFmax,in]=max(abs(TF)); 182 | while phase2(in)>50 183 | phase2=phase2-360; 184 | end 185 | phased=phase2(in)-phase(in); 186 | phase=phase+round(phased/360)*360; 187 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 188 | subplot(2,1,2) 189 | plot(f,phase2,f,phase) 190 | xlabel('Frequency (Hz)') 191 | ylabel('Phase (deg)') 192 | legend('Identified FRF','Experimental FRF',0) 193 | 194 | grid on 195 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 196 | gridmin_max=round(phmin_max/90)*90; 197 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 198 | zoom on 199 | a=a(1)^2/(2*pi*nf)^2; 200 | 201 | if nargout==0 202 | disp('') 203 | disp(['zeta = ' num2str(z)]) 204 | disp(['f = ' num2str(nf) ' Hz.']) 205 | disp(['amplitude = ' num2str(2*imag(a(1))^2) '.']) 206 | disp('') 207 | clear z a nf 208 | end 209 | %disp('error still needing correction to use 7.38') 210 | %figure,tfplot(f,(a^2)./((nf*2*pi)^2-(2*pi*f).^2+z*2*nf*2*pi*2*pi*f*sqrt(-1))) 211 | -------------------------------------------------------------------------------- /Modal_Analysis/sdofcfold.m: -------------------------------------------------------------------------------- 1 | function [z,nf,a]=sdofcf(f,TF) 2 | %[z,nf,a]=sdof(f,TF) Curve fit to SDOF FRF. 3 | % f is the frequency vector in Hz. It does not have to 4 | % start at 0 Hz. 5 | % TF is the complex transfer function. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % a is the product of the residues of the coordinates the 8 | % transfer function is between. (For example, in the example 9 | % below, a1 times a2 is returned. See equation 7.42) 10 | % Only one peak may exist in the segment of the FRF passed to 11 | % sdofcf. No zeros may exist withing this segment. If so, 12 | % curve fitting becomes unreliable. 13 | % 14 | % EXAMPLE: 15 | % M=eye(2); 16 | % K=[2 -1;-1 2]; 17 | % C=.01*K; 18 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 19 | % figure(1) 20 | % n=250; 21 | % f2=Freq((1:n)+450); 22 | % R2=Recep((1:n)+450); 23 | % R2=R2+.1*randn(n,1)+.1*randn(n,1)*i;% Poorly Simulated Noise 24 | % [z,nf,a]=sdofcf(f2,R2) 25 | % 26 | % Note that by changing the parts of Freq and Recep used 27 | % We can curve fit to other modes. 28 | 29 | % Copyright Joseph C. Slater, 10/8/99 30 | % Updated 11/8/99 to improve robustness 31 | % Updated 1/1/00 to improve robustness 32 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 33 | %tfplot(f,TF) 34 | %pause 35 | R=TF; 36 | [y,in]=max(abs(TF)); 37 | 38 | ll=length(f); 39 | w=f*2*pi*sqrt(-1); 40 | w2=w*0; 41 | R3=R*0; 42 | for i=1:ll 43 | R3(i)=conj(R(ll+1-i)); 44 | w2(i)=conj(w(ll+1-i)); 45 | end 46 | w=[w2;w]; 47 | R=[R3;R]; 48 | 49 | c=-w.^2.*R; 50 | a0=w.^0.*R; 51 | a1=w.^1.*R; 52 | a2=R*0-1; 53 | a=[a0 a1 a2]; 54 | %a(1:10,:) 55 | b=a\c; 56 | rs=roots([1 b(2) b(1)]); 57 | 58 | omega=abs(rs(1)); 59 | z=-real(rs(1))/abs(rs(1)); 60 | nf=omega/2/pi; 61 | 62 | XoF=1./(w.^2+2*z*w*omega+omega^2); 63 | 64 | a=1; 65 | 66 | a=XoF\R; 67 | %tfplot(f,TF) 68 | %tfplot(f,[a*Rest,R]) 69 | XoF=a*XoF(ll+1:2*ll); 70 | 71 | 72 | %break 73 | Fmin=min(f); 74 | Fmax=max(f); 75 | phase=unwrap(angle(TF))*180/pi; 76 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 77 | %size(XoF) 78 | subplot(2,1,1) 79 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF))) 80 | as=axis; 81 | zoom on 82 | legend('Identified FRF','Experimental FRF',0) 83 | min(f); 84 | 85 | axis([Fmin Fmax as(3) as(4)]) 86 | xlabel('Frequency (Hz)') 87 | ylabel('Mag (dB)') 88 | grid on 89 | % Fmin,Fmax,min(mag),max(mag) 90 | % axis([Fmin Fmax minmag maxmag]) 91 | while phase2(in)>50 92 | phase2=phase2-360; 93 | end 94 | phased=phase2(in)-phase(in); 95 | phase=phase+round(phased/360)*360; 96 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 97 | subplot(2,1,2) 98 | plot(f,phase2,f,phase) 99 | xlabel('Frequency (Hz)') 100 | ylabel('Phase (deg)') 101 | legend('Identified FRF','Experimental FRF',0) 102 | 103 | grid on 104 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 105 | gridmin_max=round(phmin_max/90)*90; 106 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 107 | zoom on 108 | 109 | -------------------------------------------------------------------------------- /Modal_Analysis/sdofcvscript.m: -------------------------------------------------------------------------------- 1 | % Method From page 6-77 Allemang 2 | % These from vtb7_4 example 3 | % -5.00e-03 + 1.00e+00i 5.00e-03 1.00e+00 4 | % -5.00e-03 - 1.00e+00i 5.00e-03 1.00e+00 5 | % -1.50e-02 + 1.73e+00i 8.66e-03 1.73e+00 6 | % -1.50e-02 - 1.73e+00i 8.66e-03 1.73e+00 7 | %w=f2*2*pi*i; 8 | %w=w(110:120); 9 | %R=-R2;%-R2(110:120); 10 | 11 | % Above here is note for Greg 12 | dr=.0001; 13 | om=1; 14 | i=sqrt(-1); 15 | w=(0:.1:2)'*sqrt(-1); 16 | 17 | R=1./(w.^2+2*dr*w*om+om^2); 18 | 19 | %w=[30;40;50]*i 20 | %R=[(7.1298e-5-3.0556e-6*i); -1.9109e-18-1.25e-3*i; -5.5385e-5-3.0769e-6*i] 21 | 22 | c=-w.^2.*R; 23 | a0=w.^0.*R; 24 | a1=w.^1.*R; 25 | a2=R*0-1; 26 | a=[a0 a1 a2]; 27 | %a(1:10,:) 28 | b=a\c; 29 | rs=roots([1 b(2) b(1)]) 30 | f=abs(rs(1)) 31 | z=real(rs(1))/abs(rs(1)) 32 | damp(rs) 33 | b 34 | disp('Note the wacky root (rs(1)). This is a residual, I think') 35 | disp('Now we include the negative (j\omega) part of the axis to get the conjugates in the answer)') 36 | pause 37 | 38 | 39 | ll=length(w) 40 | w2=w*0; 41 | R3=R*0; 42 | for i=1:ll 43 | R3(i)=conj(R(ll+1-i)); 44 | w2(i)=conj(w(ll+1-i)); 45 | end 46 | w=[w2;w]; 47 | R=[R3;R]; 48 | 49 | c=-w.^2.*R; 50 | a0=w.^0.*R; 51 | a1=w.^1.*R; 52 | a2=R*0-1; 53 | a=[a0 a1 a2]; 54 | %a(1:10,:) 55 | b=a\c 56 | rs=roots([1 b(2) b(1)]) 57 | f=abs(rs(1)) 58 | z=real(rs(1))/abs(rs(1)) 59 | damp(rs) 60 | dr,om 61 | -------------------------------------------------------------------------------- /Modal_Analysis/sdtest.m: -------------------------------------------------------------------------------- 1 | zeta=.0001; 2 | om=1; 3 | amp=10; 4 | i=sqrt(-1); 5 | w=(0:.01:2)'; 6 | f=w/2/pi; 7 | R=amp./(-w.^2+2*i*zeta*w*om+om^2); 8 | [z,nf,a]=sdofcf(f,R) 9 | -------------------------------------------------------------------------------- /Modal_Analysis/sec8p1.m: -------------------------------------------------------------------------------- 1 | w=[1i ;1.5i;2i] 2 | k=2.25;m=1;c=.1; 3 | h=1./(m*w.^2+c*w+k) 4 | %matrix2tex(h) 5 | V=[h(1) w(1)*h(1) w(1)^2*h(1); 6 | h(2) w(2)*h(2) w(2)^2*h(2); 7 | h(3) w(3)*h(3) w(3)^2*h(3)] 8 | V\[1;1;1] 9 | w(4)=2.5i;h=1./(m*w.^2+c*w+k); 10 | V(4,:)=[h(4) w(4)*h(4) w(4)^2*h(4)] 11 | V\[1;1;1;1] 12 | -------------------------------------------------------------------------------- /Modal_Analysis/single_thesis_modes_simple.m: -------------------------------------------------------------------------------- 1 | % thesis 2 | clear all 3 | close all 4 | 5 | %C:\WINDOWS\Desktop\SINGLE\L5_short_tubes.trf\L5_S02_ASCIIdata\ 6 | Hxy = uigetfile('*.txt','Pick a Hxy (transfer function) file'); 7 | 8 | % get transfer function from file 9 | % ASCII file setup is {Hz Real Imag} 10 | % Channel 2 - x dir 11 | % Channel 3 - y dir 12 | % Channel 4 - z dir 13 | % Channel 5 - velocity from vibrometer 14 | % Channel 8 - base accelerometer 15 | 16 | 17 | %data = dlmread(Hxy,'\t',8,1); 18 | load dat 19 | f = data(:,1); % in Hz 20 | 21 | x = data(:,6); 22 | y = i*data(:,7); % z dir in g/g 23 | 24 | 25 | TF = x+y; 26 | 27 | [z,nf,u]=mmcf(f,TF) 28 | %%% need mmcf.p to run this script %%% 29 | 30 | %[z,nf,u]=mmcf(f,TF,Fmin,Fmax,nmodes) Curve fit to MDOF FRF. 31 | % f is the frequency vector in Hz. 32 | % 33 | % TF is the complex transfer functions, each FRF in a column. 34 | % z and nf are the damping ratio and natural frequency (Hz) 35 | % u is the mode shape. 36 | % 37 | % If Fmin and Fmax are not entered, the min and max values in 38 | % f are used. 39 | % 40 | % If nmodes is not included, it is estimated automatically. 41 | 42 | -------------------------------------------------------------------------------- /Modal_Analysis/vtb74test.m: -------------------------------------------------------------------------------- 1 | M=eye(2);K=[2 -1;-1 2];C=.01*K; 2 | %[Freq,Recep,Mobil,Inert]=sostf(M,C,K,1,1,linspace(0,.5,1024)); 3 | [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); 4 | 5 | figure(1) 6 | %tfplot(Freq,Recep) 7 | n=250; 8 | f2=Freq((1:n)+450); 9 | R2=Recep((1:n)+450); 10 | R2=R2+.1*randn(n,1)+.1*randn(n,1)*i; 11 | [z,w,a,com]=vtb7_4(f2,R2) 12 | -------------------------------------------------------------------------------- /Modal_Analysis/vtb7_4_1.m: -------------------------------------------------------------------------------- 1 | function [z,nf,amp]=vtb7_4_1(f,TF1,TF2,TF3,TF4,TF5,TF6,b) 2 | % 3 | %[z,nf,amp]=vtb7_4_1(f,TF1,TF2,TF3,TF4,TF5,TF6) Curve fit to MDOF FRF. 4 | % f is the frequency vector in Hz. It does not have to 5 | % start at 0 Hz. 6 | % TF1 is the complex transfer function for node 1. 7 | % TF2 is the complex transfer function for node 2. 8 | % TF3 is the complex transfer function for node 3. 9 | % TF4 is the complex transfer function for node 4. 10 | % TF5 is the complex transfer function for node 5. 11 | % TF6 is the complex transfer function for node 6. 12 | % z and nf are the damping ratio and natural frequency (Hz) 13 | % amp is the amplitude vector giving the amplitude at each 14 | % node corresponding to the natural frequency. 15 | % 16 | % STOP! To be able to use this code, you need to have the complex 17 | % transfer function data corresponding to all the six nodes. For this 18 | % purpose run the code 'loaddata'. 19 | 20 | %##################################################################### 21 | global XoF 22 | global sz 23 | if nargin==7 24 | 25 | 26 | 27 | TF=[TF1,TF2,TF3,TF4,TF5,TF6]; 28 | sz=max(size(TF(1,:))); 29 | lf=length(f); 30 | z=0.0005; 31 | xx=zeros(sz+2+3*sz,1); 32 | 33 | for J=1:sz 34 | TFN=TF(:,J); 35 | [y,in]=max(abs(TFN)); 36 | f(in); 37 | a0=abs(TFN(1))*(2*pi*f(in))^2; 38 | a0=-sign(imag(TFN(in)))*abs(TFN(in))*2*z*(2*pi*f(in))^2; 39 | xx(J,1)=a0; 40 | end 41 | 42 | xx(sz+1,1)=z; 43 | xx(sz+2,1)=2*pi*f(in); 44 | x=xx; 45 | 46 | 47 | 48 | if in-3<1|in+2>length(f) 49 | disp('The peak response must be near the middle of the data') 50 | disp('Please center your peak and try again') 51 | break 52 | end 53 | 54 | 55 | 56 | x=fmins('vtb7_4_1',x,[],[],f(in-3:in+2),TF1(in-3:in+2),TF2(in-3:in+2),TF3(in-3:in+2),TF4(in-3:in+2),TF5(in-3:in+2),TF6(in-3:in+2)); 57 | x; 58 | 59 | cost=vtb7_4_1(x,f,TF1,TF2,TF3,TF4,TF5,TF6); 60 | x=fmins('vtb7_4_1',x,[],[],f,TF1,TF2,TF3,TF4,TF5,TF6); 61 | x; 62 | 63 | cost=vtb7_4_1(x,f,TF1,TF2,TF3,TF4,TF5,TF6); 64 | x=fmins('vtb7_4_1',x,[],[],f,TF1,TF2,TF3,TF4,TF5,TF6); 65 | x; 66 | 67 | cost=vtb7_4_1(x,f,TF1,TF2,TF3,TF4,TF5,TF6); 68 | x=fmins('vtb7_4_1',x,[],[],f,TF1,TF2,TF3,TF4,TF5,TF6); 69 | x; 70 | 71 | cost=vtb7_4_1(x,f,TF1,TF2,TF3,TF4,TF5,TF6); 72 | x=fmins('vtb7_4_1',x,[],[],f,TF1,TF2,TF3,TF4,TF5,TF6); 73 | x; 74 | 75 | cost=vtb7_4_1(x,f,TF1,TF2,TF3,TF4,TF5,TF6); 76 | x=fmins('vtb7_4_1',x,[],[],f,TF1,TF2,TF3,TF4,TF5,TF6); 77 | x; 78 | 79 | z=x(sz+1); 80 | om=x(sz+2); 81 | nf=om/2/pi; 82 | amp=x(1:sz); 83 | plot(amp); 84 | grid 85 | title('Mode Shape Plot') 86 | 87 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 88 | else 89 | x=f; 90 | f=TF1; 91 | TF1=TF2; 92 | TF2=TF3; 93 | TF3=TF4; 94 | TF4=TF5; 95 | TF5=TF6; 96 | TF6=b; 97 | 98 | w2=f*2*pi; 99 | lx=length(x); 100 | x(sz+1)=abs(x(sz+1)); 101 | x(sz+2)=abs(x(sz+2)); 102 | 103 | 104 | xfer=[TF1,TF2,TF3,TF4,TF5,TF6]; 105 | t=1; 106 | error1=0; 107 | for K=sz+3:3:lx 108 | XoF=x(K)+x(K+1)*i*w2-x(K+2)*w2.^2; 109 | XoF=XoF+x(t)./(-w2.^2+2*x(sz+1)*w2*i*x(sz+2)+x(sz+2)^2); 110 | error=norm(XoF-xfer(:,t)); 111 | error1=error1+error; 112 | t=t+1; 113 | end 114 | sla74=error1; 115 | z=sla74; 116 | end 117 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vibration-Testing-Matlab 2 | Vibration Testing code affiliated with the in-progress manuscript Vibration Testing with Modal Analysis and Health Monitoring- Matlab version 3 | 4 | A demonstration of many of the features can be access by running the 5 | script `vtdem`. 6 | -------------------------------------------------------------------------------- /asd.m: -------------------------------------------------------------------------------- 1 | function [fout,Pyyout]=asd(y,dt,n,ave) 2 | %ASD Onesided Auto or power spectrum density estimate of the data sequence y. 3 | % [F,Pyy] = ASD(Y,DT,N,AVE) estimates the Power/Auto Spectrum 4 | % Density using the direct method. N is the number of 5 | % points to be used in the Fourier Transform. The default 6 | % is not to zero pad to the next power of 2. If DT is the time 7 | % vector, DT is extracted as T(2)-T(1). If Y is a matrix, 8 | % ASD will find the Auto Spectrum Density for each column 9 | % and average the results unless AVE is set to 'noave'. 10 | % N and AVE are optional. Either can be left out. 11 | % 12 | % Zero padding is turned off harshly now. 13 | % 14 | % ASD(Y,DT,N,AVE) plots the Auto Spectrum Density if there 15 | % are no output arguments. 16 | % 17 | % See page 38, R.K. Otnes and L. Enochson, Digital Time Series 18 | % Analysis, J. Wiley and Sons, 1972. 19 | % 20 | % See also TFEST, CRSD, TFPLOT 21 | 22 | % Copyright (c) 1994 by Joseph C. Slater 23 | % Amplitude adjusted to match Vibration Testing...3/31/2003 24 | % Frequency Scale Fixed to work with a large number of 25 | % short data sets. 12/27/98 26 | % Frequency Scale Fixed 7/21/98 27 | % Normalized for magnitude 7/21/98 28 | % Fixed amplitude of zero frequency value 3/30/16 (filed by Admir Makas) 29 | 30 | 31 | n=length(y); 32 | sy=size(y); 33 | if nargin==2 34 | %n=2^nextpow2(sy(1)); 35 | 36 | ave='yes'; 37 | elseif nargin==3 38 | if strcmp(n,'noave') 39 | ave=n; 40 | n=length(y); 41 | else 42 | ave='yes'; 43 | end 44 | end 45 | 46 | if length(dt)>1 47 | dt=dt(2)-dt(1); 48 | end 49 | 50 | if isempty(n) 51 | n=2^nextpow2(sy(1)); 52 | end 53 | 54 | ffty=fft(y,n)*dt; 55 | 56 | Pyy=real(ffty.*conj(ffty))/(n*dt)*2; 57 | 58 | Pyy=Pyy(1:ceil(n/2),:); 59 | 60 | Pyy(:,1)=Pyy(:,1)/2; 61 | 62 | if sy(2)~=1 & ~strcmp(ave,'noave') 63 | Pyy=mean(Pyy')'; 64 | end 65 | nfreq=1/dt/2; 66 | sfft=size(ffty); 67 | lfft=sfft(1); 68 | size(Pyy); 69 | fmax=(nfreq/(lfft/2))*(size(Pyy,1)-1); 70 | %f=(0:(nfreq/(lfft/2)):nfreq-1)'; 71 | f=(0:(nfreq/(lfft/2)):fmax)'; 72 | size(f); 73 | if nargout==0 74 | plot(f,10*log10(Pyy))%see appendix 75 | 76 | title('Power Spectrum Density of F(t) (dB)') 77 | xlabel('Frequency (Hz)') 78 | ylabel('Power Spectrum Density') 79 | grid 80 | zoom on 81 | return 82 | end 83 | 84 | fout=f; 85 | Pyyout=Pyy; 86 | -------------------------------------------------------------------------------- /asdtest.m: -------------------------------------------------------------------------------- 1 | t=0:1/1024:1-1/1024; 2 | a=sin(t*2*pi*20); 3 | t2=0:1/256:1-1/256; 4 | a2=sin(t2*2*pi*20); 5 | [f,p]=asd(a',t); 6 | [f2,p2]=asd(a2',t2); 7 | semilogy(f,p,f2,p2) 8 | -------------------------------------------------------------------------------- /blackwin.m: -------------------------------------------------------------------------------- 1 | function f = blackwin(n) 2 | %BLACKWIN Returns or applies a Blackman window. 3 | % X=BLACKWIN(N) produces an N-point Blackman window 4 | % 5 | % YWIN=BLACKWIN(Y) Returns Y with a Blackman window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % See also BOXWIN, EXPWIN, HAMMWIN, TRIWIN, and VONHANN. 10 | 11 | % Copyright (c) 1994 by Joseph C. Slater 12 | 13 | sn=size(n); 14 | 15 | if sn==[1 1] 16 | f=(0.42-0.5*cos(2*pi*((0:n-1)+.5)/(n))+0.08*cos(4*pi*((0:n-1)+.5)/n))'*sqrt(5000/1523); 17 | else 18 | blackmesh=meshgrid(blackwin(sn(1)),1:sn(2))'; 19 | f=n.*blackmesh; 20 | end 21 | 22 | -------------------------------------------------------------------------------- /boxwin.m: -------------------------------------------------------------------------------- 1 | function f = boxwin(n) 2 | %BOXWIN Returns or applied a Boxcar window 3 | % X=BOXWIN(N) produces an N-point Boxcar window 4 | % 5 | % YWIN=BOXWIN(Y) Returns Y with a Boxcar window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % See also BLACKWIN, EXPWIN, HAMMWIN, TRIWIN, and VONHANN. 10 | 11 | % Copyright (c) 1994 by Joseph C. Slater 12 | 13 | sn=size(n); 14 | 15 | if sn==[1 1] 16 | f=ones(n,1); 17 | else 18 | f=n; 19 | end 20 | -------------------------------------------------------------------------------- /coh.m: -------------------------------------------------------------------------------- 1 | function [fout,cohout]=coh(x,y,dt,n,ave) 2 | %COH Coherance. 3 | % [F,COH]=COH(X,Y,DT,N,AVE) determines the coherance between 4 | % signals X and Y using CRSD and ASD. 5 | % The coherance should be near 1 near the poles and may be 6 | % near zero near the zeros without causing undue concern. 7 | % DT is the time between samples. N is the number of 8 | % points to be used in the Fourier Transform. 9 | % The default for N is to zero pad the data to the next 10 | % power of 2. 11 | % If DT is the time vector, DT is extracted as T(2)-T(1). 12 | % If X and Y are matrices, averaging will be performed on the 13 | % power spectrums before the coherance is calculated 14 | % unless AVE is set to 'noave'. N and AVE are optional. 15 | % Either can be left out. 16 | % 17 | % COH(X,Y,DT,N) plots the Coherance if there are no ouput 18 | % arguments. Click in the region of interest to zoom in. 19 | % Each click will double the size of the plot. Double click 20 | % to return to full scale. 21 | % 22 | % See also TFEST, ASD, CRSD, and TFPLOT. 23 | 24 | % Copyright (c) 1994 by Joseph C. Slater 25 | sy=size(y); 26 | if nargin==3 27 | n=2^nextpow2(sy(1)); 28 | ave='yes'; 29 | elseif nargin==4 30 | if strcmp(n,'noave') 31 | ave=n; 32 | n=2^nextpow2(sy(1)); 33 | else 34 | ave='yes'; 35 | end 36 | end 37 | 38 | if isempty(n) 39 | n=2^nextpow2(sy(1)); 40 | end 41 | 42 | if length(dt)>1 43 | dt=dt(2)-dt(1); 44 | end 45 | 46 | [f,Pxx]=crsd(x,x,dt,n,ave); 47 | [f,Pxy]=crsd(x,y,dt,n,ave); 48 | [f,Pyy]=crsd(y,y,dt,n,ave); 49 | coh=abs(Pxy).^2./(Pxx.*Pyy); 50 | if nargout==0 51 | plot(f,coh) 52 | %logo 53 | title('Coherance') 54 | xlabel('Frequency (Hz)') 55 | ylabel('Coherance') 56 | grid 57 | zoom on 58 | return 59 | end 60 | 61 | cohout=coh; 62 | fout=f; 63 | -------------------------------------------------------------------------------- /crcor.m: -------------------------------------------------------------------------------- 1 | function [tout,crcorout]=crcor(x,y,dt,type,ave) 2 | %CRCOR Cross correlation. 3 | % [Tau,COR]=CRCOR(X,Y,DT,TYPE,AVE) returns the Cross Correlation 4 | % between signals X and Y. 5 | % [Tau,COR]=CRCOR(X,X,DT,TYPE,AVE) returns the Auto Correlation 6 | % of the signal X. 7 | % DT is the time between samples. 8 | % If DT is the time vector, DT is extracted as T(2)-T(1). 9 | % TYPE is the type of correlation. TYPE = 1 causes CRCOR 10 | % to return the linear correlation function. TYPE = 2 11 | % causes CRCOR to return the circular correlation function. 12 | % The default value is 1. 13 | % If X and Y are matrices, averaging will be performed on the 14 | % Correlations unless AVE is set to 'noave'. TYPE and AVE are 15 | % optional. Either can be left out. 16 | % 17 | % COH(X,Y,DT,N,AVE) plots the Correlation if there are no ouput 18 | % arguments. Click in the region of interest to zoom in. 19 | % Each click will double the size of the plot. Double click 20 | % to return to full scale. 21 | % 22 | % See also TFEST, ASD, COH, CRSD, and TFPLOT. 23 | 24 | % Copyright (c) 1994 by Joseph C. Slater 25 | sy=size(y); 26 | sy=size(y); 27 | if nargin==3 28 | type=1; 29 | ave='yes'; 30 | elseif nargin==4 31 | if strcmp(type,'noave') 32 | ave=n; 33 | type=1; 34 | else 35 | ave='yes'; 36 | end 37 | end 38 | 39 | if isempty(type) 40 | type=1; 41 | end 42 | 43 | sx=size(x); 44 | nc=sx(2); 45 | 46 | if type==1 47 | n=sx(1)*2; 48 | else 49 | n=sx(1); 50 | end 51 | 52 | if length(dt)~=1 53 | dt=dt(2)-dt(1); 54 | end 55 | 56 | tmax=dt*(length(x)-1); 57 | t=(-tmax:(2*tmax/(n-1)):tmax)'-(tmax/(n-1)); 58 | 59 | X=fft(x,n); 60 | Y=fft(y,n); 61 | pxy=real(ifft(conj(X).*Y)); 62 | 63 | crcr=fftshift(real(pxy)); 64 | crcr=crcr(1:length(crcr),:); 65 | 66 | if nc~=1 & ~strcmp(ave,'noave') 67 | crcr=mean(crcr')'; 68 | end 69 | 70 | if nargout==0 71 | plot(t,crcr) 72 | %logo 73 | if type==1 74 | text1='Linear '; 75 | else 76 | text1='Circular '; 77 | end 78 | if x==y 79 | text2='Auto '; 80 | else 81 | text2='Cross '; 82 | end 83 | text3=[text1 text2 'Correlation']; 84 | title(text3) 85 | xlabel('Time') 86 | ylabel(text3) 87 | grid 88 | zoom on 89 | return 90 | end 91 | 92 | crcorout=crcr; 93 | tout=t; 94 | -------------------------------------------------------------------------------- /crsd.m: -------------------------------------------------------------------------------- 1 | function [fout,Pxyout]=crsd(x,y,dt,n,ave) 2 | %CRSD One sided cross spectrum density estimate of the data sequences X and Y (Sxy). 3 | % [F,Pxy] = CRSD(X,Y,DT,N,AVE) estimates the Cross Spectrum 4 | % Density using the direct method. 5 | % DT is the time between date samples. 6 | % If DT is the time vector, DT is extracted as T(2)-T(1). 7 | % N is the number of points to be used in the Fourier 8 | % Transform. The default for N is to zero pad the data 9 | % to the next power of 2. 10 | % If X and Y are matrices, CRSD will find the Cross Spectrum 11 | % Density for each column and average the results 12 | % unless AVE is set to 'noave'. N and AVE are optional. 13 | % Either can be left out. 14 | % 15 | % CRSD(X,Y,DT,...) plots the Cross Spectrum Density if there 16 | % are no output arguments. Click in the region of interest 17 | % to zoom in. Each click will double the size of the plot. 18 | % Double click to return to full scale. 19 | % 20 | % See page 38, R.K. Otnes and L. Enochson, Digital Time Series 21 | % Analysis, J. Wiley and Sons, 1972. 22 | % 23 | % See also TFEST, ASD, TFPLOT 24 | 25 | % Copyright (c) 1994 by Joseph C. Slater 26 | % Amplitude adjusted to match Vibration Testing... 3/31/2003 27 | % Frequency Scale Fixed to work with a large number of 28 | % short data sets. 12/27/98 29 | % Normalized for magnitude 9/23/98 30 | % Frequency Scale Fixed 9/23/98 31 | % Fixed amplitude of zero frequency value 3/30/16 (filed by Admir Makas) 32 | 33 | sy=size(y); 34 | if nargin==3 35 | n=2^nextpow2(sy(1)); 36 | ave='yes'; 37 | elseif nargin==4 38 | if strcmp(n,'noave') 39 | ave=n; 40 | n=2^nextpow2(sy(1)); 41 | else 42 | ave='yes'; 43 | end 44 | end 45 | 46 | if isempty(n) 47 | n=2^nextpow2(sy(1)); 48 | end 49 | 50 | if length(dt)>1 51 | dt=dt(2)-dt(1); 52 | end 53 | n=length(x); 54 | ffty=fft(y,n)*dt; 55 | fftx=fft(x,n)*dt; 56 | Pxy=ffty.*conj(fftx)/(n*dt)*2; 57 | 58 | Pxy(:,1) = Pxy(:,1)/2; 59 | 60 | 61 | Pxy=Pxy(1:ceil(n/2),:); 62 | if sy(2)~=1 & ~strcmp(ave,'noave') 63 | Pxy=mean(Pxy')'; 64 | end 65 | nfreq=1/dt/2; 66 | sfft=size(fftx); 67 | lfft=sfft(1); 68 | %f=(0:(nfreq/(lfft/2-1)):nfreq)'; 69 | fmax=(nfreq/(lfft/2))*(size(Pxy,1)-1); 70 | %f=(0:(nfreq/(lfft/2)):nfreq-1)'; 71 | f=(0:(nfreq/(lfft/2)):fmax)'; 72 | if nargout==0 73 | semilogy(f,abs(Pxy)) 74 | 75 | title('Cross Spectrum Density') 76 | xlabel('Frequency (Hz)') 77 | ylabel('Cross Spectrum Density') 78 | grid 79 | zoom on 80 | return 81 | end 82 | 83 | fout=f; 84 | Pxyout=Pxy; 85 | -------------------------------------------------------------------------------- /expwin.m: -------------------------------------------------------------------------------- 1 | function f = expwin(n,ts) 2 | %EXPWIN Returns or applies an N-point exponential window 3 | % X=EXPWIN(N,TS) produces an N-point exponential window 4 | % 5 | % YWIN=EXPWIN(Y,TS) Returns Y with a exponential window 6 | % applied to the vector Y or set of vectors represented 7 | % by the matrix Y. 8 | % 9 | % TS is the point in the window at which the exponential 10 | % reaches .05 (TS between 0 and 1). The default value 11 | % for TS is 0.75. 12 | % 13 | % See also BLACKWIN, BOXWIN, HAMMWIN, TRIWIN, and VONHANN. 14 | 15 | 16 | % Copyright (c) 1994 by Joseph C. Slater 17 | % 4/6/2003 Normalization for ASD (accurate in limit) 18 | 19 | if nargin==1 20 | ts=.75; 21 | disp('Using 75% window length for 5% window magnitude.') 22 | end 23 | 24 | if ts > 1 | ts < 0 25 | tstxt=num2str(ts); 26 | text=['Error: TS should be between 0 and 1. '... 27 | 'TS was entered as ' tstxt '.']; 28 | error(text) 29 | end 30 | 31 | tc=ts/2.9957; 32 | 33 | sn=size(n); 34 | 35 | if sn==[1 1] 36 | v=(n-1)/n*(0:n-1)+(n-1)/n/2; 37 | f=exp(-v/tc/(n-1))'; 38 | f=f/sqrt(f'*f)*sqrt(length(f)); 39 | else 40 | % expomesh=meshdom(expwin(sn(1),.75),1:sn(2))'; 41 | expomesh=meshgrid(expwin(sn(1),.75),1:sn(2))'; 42 | f=n.*expomesh; 43 | end 44 | 45 | -------------------------------------------------------------------------------- /freqdemo.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/freqdemo.mat -------------------------------------------------------------------------------- /guyanold.m: -------------------------------------------------------------------------------- 1 | function [Mr,Kr,T,master,slave]=guyan(m,k,thresh) 2 | %GUYAN Reduce size of second order system of equations by 3 | % applying Guyan reduction. 4 | % M x'' + K x = 0 5 | % Mr xm'' + Kr xm = 0 6 | % Where x = T*xm, Mr= transpose(T)*M*T, Kr= transpose(T)*K*T 7 | % 8 | %[Mr,Kr,T,master,slave]=GUYAN(M,K,thresh) slaves coordinates i for which 9 | % thresh>(k(i,i)/m(i,i))/max(k(i,i)/m(i,i)). Master coordinates are returned 10 | % in the vector master, slave coordinate indices are returned in the vector 11 | % slave. 12 | % 13 | %[Mr,Kr,T,master,slave]=GUYAN(M,K,master) slaves coordinates which are not 14 | % listed in the vector master. Master coordinates are returned 15 | % in the vector master, slave coordinate indices are returned in the vector 16 | % slave. 17 | % 18 | %[Kr,T,master,slave]=GUYAN(K,master) performs static condensation, slaving 19 | % coordinates that are not listed in the vector master. Master coordinates are 20 | % returned in the vector master, slave coordinate indices are returned in the 21 | % vector slave. 22 | % 23 | %[Mr,Kr,T,master,slave]=GUYAN(M,K) slaves coordinates i for which 24 | % 0.1>(k(i,i)/m(i,i))/max(k(i,i)/m(i,i)). Master coordinates are returned 25 | % in the vector master, slave coordinate indices are returned in the vector 26 | % slave. 27 | % 28 | % Reduced coordinate system forces can be obtained by 29 | % fr=transpose(T)*F 30 | % 31 | % Reduced damping matrix can be obtained using Cr=transpose(T)*C*T. 32 | % 33 | % If mode shapes are obtained for the reduced system, full system mode shapes 34 | % are phi=T*phi_r 35 | % 36 | 37 | % 38 | % Copyright Joseph C. Slater, 6/19/2000 39 | if size(k,1)==1 or size(k,2)==1 40 | statcond=1; 41 | thresh=k; 42 | k=m; 43 | m=eye(size(k)); 44 | end 45 | 46 | 47 | sprse=1; 48 | if ~issparse(m) 49 | m=sparse(m); 50 | k=sparse(k); 51 | sprse=0; 52 | end 53 | if nargin==2 54 | thresh=.1; 55 | end 56 | 57 | ncoord=length(m); 58 | 59 | if length(thresh)==1 60 | if thresh>=1 61 | thresh=.1; 62 | warndlg({'thresh must be less than 1.';'thresh has been set to .1'},'Threshold too hign') 63 | % disp('move on') 64 | end 65 | dm=diag(m); 66 | dk=diag(k); 67 | rat=dm./dk; 68 | %pause 69 | %plot(sort(1./rat)) 70 | %pause 71 | mr=rat./max(rat); 72 | %plot(sort(mr)) 73 | %pause 74 | mth=min(rat)/max(rat); 75 | master=(mr)>thresh; 76 | numofmasters=sum(master); 77 | [rat,i]=sort(mr); 78 | slave=i(1:ncoord-numofmasters); 79 | master=i(ncoord-numofmasters+1:ncoord)'; 80 | lmaster=length(master); 81 | else 82 | master=thresh; 83 | i=1:ncoord; 84 | lmaster=length(master); 85 | i(master)=zeros(lmaster,1); 86 | i=sort(i); 87 | slave=i(lmaster+1:ncoord); 88 | end 89 | if lmaster==ncoord 90 | figure(gcf) 91 | plot((1:ncoord)',rat./max(rat),[1 ncoord],[thresh thresh]) 92 | axis([1,ncoord, 0,1]) 93 | legend('Normalized Ratios','Cutoff for Slave Coordinates',0) 94 | grid on 95 | xlabel('Coordinate number') 96 | ylabel('Normalized diagonal ratio.') 97 | h=warndlg({['thresh must be greater than ' num2str(mth) ' for']... 98 | ;'this problem. Run aborted.'},'Threshold too hign'); 99 | t=(1:.1:70)'; 100 | noise=sin(10*t)+sin(3*t); 101 | quiet=0*t; 102 | sound([noise;quiet;noise;quiet;noise]) 103 | slave=0;master=0;Mr=0;Kr=0;T=0; 104 | break 105 | end 106 | kmm=k(master,master); 107 | ksm=k(slave,master); 108 | kss=k(slave,slave); 109 | kms=ksm'; 110 | T=zeros(ncoord,lmaster); 111 | T=sparse(T); 112 | T(master,1:lmaster)=eye(lmaster,lmaster); 113 | T(slave,1:lmaster)=-kss\ksm; 114 | if statcond~=1 115 | Mr=T'*m*T; 116 | end 117 | Kr=T'*k*T; 118 | if sprse==0 119 | Mr=full(Mr); 120 | Kr=full(Kr); 121 | T=full(T); 122 | end 123 | if statcond==1 124 | Mr=Kr; 125 | Kr=T; 126 | T=master; 127 | master=slave; 128 | end 129 | -------------------------------------------------------------------------------- /hammwin.m: -------------------------------------------------------------------------------- 1 | function f = hammwin(n) 2 | %HAMMWIN Returns or applies a Hamming window. 3 | % X=HAMMWIN(N) produces an N-point Hamming window 4 | % 5 | % YWIN=HAMMWIN(Y) Returns Y with a Hamming window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % See also BLACKWIN, BOXWIN, EXPWIN, TRIWIN, and VONHANN. 10 | 11 | % Copyright (c) 1994 by Joseph C. Slater 12 | 13 | sn=size(n); 14 | 15 | if sn==[1 1] 16 | f=(0.54-0.46*cos(2*pi*((0:n-1)+.5)/(n))')*sqrt(5000/1987); 17 | else 18 | hammmesh=meshgrid(hammwin(sn(1)),1:sn(2))'; 19 | f=n.*hammmesh; 20 | end 21 | -------------------------------------------------------------------------------- /hannwin.m: -------------------------------------------------------------------------------- 1 | function f=hannwin(n) 2 | %HANNWIN Calls the function VONHANN. 3 | % 4 | % See also BLACKWIN, BOXWIN, EXPWIN, HAMMWIN, and TRIWIN. 5 | 6 | % Copyright (c) 1994 by Joseph C. Slater 7 | 8 | f=vonhann(n); 9 | -------------------------------------------------------------------------------- /hkdat1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/hkdat1.mat -------------------------------------------------------------------------------- /household.m: -------------------------------------------------------------------------------- 1 | function [a,p]=household(b,tol) 2 | % HOUSEHOLD Generates Householder matrix 3 | % [A,P]=HOUSEHOLD(B) returns A and P such that 4 | % P'*B*P = A 5 | 6 | % Copyright Joseph C. Slater, 5/2000 7 | l=length(b)-2; 8 | ii=eye(l+2); 9 | pp=ii; 10 | binit=b; 11 | if nargin==1 12 | tol=eps; 13 | end 14 | 15 | if length(b)<1 16 | disp('This matrix is already tridiagonal.') 17 | else 18 | 19 | for i=1:l 20 | v(1,1:i)=zeros(1,i); 21 | alpha=norm(b(i,i+1:l+2)) 22 | sn=sign(b(i,i+1)); 23 | v(1,i+1)=sqrt((1+b(i,i+1)*sn/alpha)/2); 24 | for j=i+2:l+2 25 | v(1,j)=sn*b(i,j)/2/alpha/v(1,i+1); 26 | end 27 | v 28 | P=ii-2*v'*v 29 | pp=pp*P; 30 | b=pp'*binit*pp 31 | end 32 | a=b; 33 | %a=pp'*binit*pp; 34 | p=pp; 35 | 36 | j=1:l; 37 | er=max(abs(diag(a(j,j+2)))./abs(diag(a(j,j+1)))) 38 | if er>tol 39 | disp('Recursion') 40 | ainit=a; 41 | [a,pp]=household(a,tol) 42 | p=p*pp; 43 | a=p'*binit*p 44 | % disp('Recursion') 45 | 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /irf.m: -------------------------------------------------------------------------------- 1 | function [tout,impout]=irf(frf,dF,n,ave) 2 | %IRF Impulse Response Function estimate of the Frequency 3 | % response function FRF. 4 | % [T,I] = IRF(FRF,DF,N,AVE) estimates the Impulse Response 5 | % Function by taking the inverse DFT of the Frequency 6 | % Response Function. N is the number of points to be used 7 | % in the Inverse Fourier Transform. The default is N= 8 | % length(FRF). If DF is the frequency vector in Hz, the 9 | % frequency spacing between FRF points is extracted as 10 | % F(2) - F(1). If FRF is a matrix, IRF will find the 11 | % Impulse Response Function for each column and average 12 | % the results unless AVE is set to 'noave'. N and AVE 13 | % are optional. Either one may be left out. 14 | % 15 | % IRF(FRF,DF,N,AVE) plots the Impulse Response Function if 16 | % there are no output arguments. 17 | % 18 | % See Also TFEST 19 | 20 | % Copyright (c) 1994 by Joseph C. Slater 21 | 22 | sfrf=size(frf); 23 | 24 | if nargin==2 25 | ave='yes'; 26 | n=sfrf(1); 27 | elseif nargin==3 28 | if strcmp(n,'noave') 29 | ave=n; 30 | n=length(frf); 31 | else 32 | ave='yes'; 33 | end 34 | end 35 | if n==[] 36 | n=2^nextpow2(sfrf(1)); 37 | end 38 | 39 | if length(dF)>1 40 | dF=dF(2)-dF(1); 41 | end 42 | lfrf=sfrf(1); 43 | 44 | frfmir=[frf ; zeros(1,sfrf(2)); conj(frf(length(frf):-1:2,:))]; 45 | 46 | impres=ifft(frfmir,n*2); 47 | 48 | lenimpres=length(impres); 49 | dt=1/dF; 50 | t=(0:lenimpres-1)'/(lenimpres-2)*dt; 51 | 52 | 53 | if sfrf(2)~=1 & ~strcmp(ave,'noave') 54 | impres=mean(impres')'; 55 | end 56 | 57 | if nargout==0 58 | plot(t,real(impres)) 59 | 60 | title('Impulse Response') 61 | xlabel('Time') 62 | ylabel('Impulse Response') 63 | grid 64 | zoom on 65 | if norm(imag(impres))>norm(real(impres))/100 66 | warndlg(['Frequency response data is faulty. Impulse ';... 67 | 'response is complex. Please check your input';... 68 | 'data. Continuing with calculations. ']); 69 | end 70 | % impres; 71 | return 72 | end 73 | 74 | if norm(imag(impres))>norm(real(impres))/100 75 | warndlg(['Frequency response data is faulty. Impulse ';... 76 | 'response is complex. Please check your input';... 77 | 'data. Continuing with calculations. ']); 78 | end 79 | impres; 80 | impres=real(impres); 81 | 82 | tout=t; 83 | impout=impres; 84 | -------------------------------------------------------------------------------- /loadfile.m: -------------------------------------------------------------------------------- 1 | %LOADFILE loads a file using the GUI open dialog box. 2 | % The selected MAT-file will be loaded. 3 | % 4 | % See also ADDPATH, DELETEFILE, EDITFILE, FILEBAR 5 | 6 | % Copyright Joseph C. Slater 1994 7 | 8 | [filename,pathname]=uigetfile('*','Select M-File to Load'); 9 | destr=['load ' '''' [pathname filename] '''' ' -mat']; 10 | if exist([pathname filename])==1 | exist([pathname filename])==2 11 | eval(destr); 12 | disp(['File ' filename ' loaded.']) 13 | else 14 | disp(['File ' filename ' not found. No action taken']) 15 | end 16 | clear pathname filename 17 | -------------------------------------------------------------------------------- /mckiddat.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/mckiddat.mat -------------------------------------------------------------------------------- /mdofcf.m: -------------------------------------------------------------------------------- 1 | function [z,nf,u]=mdofcf(f,TF,Fmin,Fmax) 2 | %[z,nf,u]=mdofcf(f,FRF,Fmin,Fmax) Curve fit to MDOF FRF. 3 | % f is the frequency vector in Hz. 4 | % 5 | % FRF are columns comprised of the FRFs presuming single input, multiple output 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % u is the mode shape. 8 | % Only one peak may exist in the segment of the FRF passed to 9 | % sdofcf. No zeros may exist withing this segment. If so, 10 | % curve fitting becomes unreliable. 11 | % 12 | % If called without outputs, i.e. 13 | % mdofcf(f,FRF,Fmin,Fmax) 14 | % The FRFs and the fit to them will be plotted instead of output being 15 | % returned. 16 | % 17 | % If Fmin and Fmax are not entered, the min and max values in 18 | % f are used. 19 | % 20 | % If the first column of TF is a collocated (input and output location are 21 | % the same), then the mode shape returned is the mass normalized mode shape 22 | % 23 | % This can then be used to generate an identified mass, damping, and 24 | % stiffness matrix as shown in the following example. 25 | % 26 | % EXAMPLE: 27 | % M=eye(2)*2; 28 | % K=[2 -1;-1 2]; 29 | % C=.01*K; 30 | % [Freq,Recep1,Mobil1,Inert1]=vtb7_5(M,C,K,1,1,linspace(0,.5,1024)); %Frequency response function between node 1 and itself 31 | % [Freq,Recep2,Mobil2,Inert2]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); %Frequency response function between node 1 and node 2 32 | % figure(1) 33 | % plot(Freq,20*log10(abs(Recep1))) 34 | % Recep=[Recep1 Recep2]; 35 | % Recep=Recep+.1*randn(size(Recep))+i*.1*randn(size(Recep)); 36 | % % Curve fit first peaks 37 | % mdofcf(Freq,Recep,.1,.12); % Plot fits. 38 | % [z1,nf1,u1]=mdofcf(Freq,Recep,.1,.12); 39 | % z(1,1)=z1; 40 | % lambda(1,1)=(nf1*2*pi)^2; 41 | % 42 | % S(:,1)=real(u1);%/abs(sqrt(u1(1))); 43 | % % Curve fit second peaks 44 | % mdofcf(Freq,Recep,.16,.25); % Plot fits 45 | % [z2,nf2,u2]=mdofcf(Freq,Recep,.16,.25); 46 | % z(2,2)=z2; 47 | % lambda(2,2)=(nf2*2*pi)^2; 48 | % S(:,2)=real(u2);%/abs(sqrt(u2(1))); 49 | % dampingratios=diag(z) 50 | % naturalfrequencies=sqrt(diag(lambda))/2/pi 51 | % M=M 52 | % Midentified=S'\eye(2)/S%Make Mass matrix 53 | % K=K 54 | % Kidentified=S'\lambda/S%Make Stiffness Matrix 55 | % C=C 56 | % Cidentified=S'\(2*z*sqrt(lambda))/S%Make damping matrix 57 | 58 | % 59 | % Note that by changing the parts of Freq and Recep used 60 | % We can curve fit to other modes. 61 | 62 | % Copyright Joseph C. Slater, 10/8/99 63 | % Updated 11/8/99 to improve robustness 64 | % Updated 1/1/00 to improve robustness 65 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 66 | % Updated 5/1/01 to start adding MDOF. 67 | % Updated 5/15/01 to include frequency range for curve fitting 68 | % Updated 11/13/07 to mass normalize mode shapes 69 | % Updated 11/13/07 example to demonstrate ID of system matrices 70 | 71 | %disp('This is beta software written 07-May-2001') 72 | %disp('This code may not be used by anyone not authorized by J. Slater') 73 | %disp('This code will expire 15-Jun-2001') 74 | 75 | %if datenum('10-Jun-2001')1 181 | 182 | pause 183 | end 184 | clf 185 | figure(gcf) 186 | XoF=R((ll+1:2*ll),:)*a(:,mm); 187 | %plot([abs(XoF) abs(TF)]) 188 | %2*ll 189 | %plot(abs(w(ll:2*ll))) 190 | %pause 191 | %break 192 | 193 | Fmin=min(f); 194 | Fmax=max(f); 195 | phase=unwrap(angle(TF(:,mm)))*180/pi; 196 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 197 | %size(XoF) 198 | subplot(2,1,1) 199 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF(:,mm)))) 200 | 201 | as=axis; 202 | legend('Identified FRF','Experimental FRF') 203 | min(f); 204 | axis([Fmin Fmax as(3) as(4)]) 205 | title(['Frequency Response Function ' num2str(mm) ' Fit']) 206 | xlabel('Frequency (Hz)') 207 | ylabel('Mag (dB)') 208 | 209 | grid on 210 | zoom on 211 | 212 | drawnow 213 | 214 | % Fmin,Fmax,min(mag),max(mag) 215 | % axis([Fmin Fmax minmag maxmag]) 216 | %pause 217 | 218 | while phase2(in)>50 219 | phase2=phase2-360; 220 | end 221 | phased=phase2(in)-phase(in); 222 | phase=phase+round(phased/360)*360; 223 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 224 | subplot(2,1,2) 225 | plot(f,phase2,f,phase) 226 | xlabel('Frequency (Hz)') 227 | ylabel('Phase (deg)') 228 | legend('Identified FRF','Experimental FRF') 229 | 230 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 231 | gridmin_max=round(phmin_max/90)*90; 232 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 233 | grid on 234 | zoom on 235 | drawnow 236 | figure(gcf) 237 | disp(['DOF ' num2str(mm) ' of ' num2str(size(a,2)) '. Press return to plot next curve-fit FRF or end.']) 238 | end 239 | end 240 | -------------------------------------------------------------------------------- /parzen.m: -------------------------------------------------------------------------------- 1 | function f = parzen(n) 2 | %PARZWIN Returns or applies a Parzen window. 3 | % X=PARZEN(N) produces an N-point Parzen window 4 | % 5 | % YWIN=PARZEN(Y) Returns Y with a Parzen window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % See also BLACKWIN, BOXWIN, EXPWIN, TRIWIN, HAMMWIN, and VONHANN. 10 | % Doesn't work for odd number of points. 11 | 12 | % Copyright (c) 2003 by Joseph C. Slater 13 | % 4/6/2003 Normalization for ASD (accurate in limit) 14 | sn=size(n); 15 | 16 | if sn==[1 1] 17 | normt=(1/(n-1):2/(n-1):1)'; 18 | m=floor(n/4); 19 | normt1=normt(1:m); 20 | normt2=normt(m+1:floor(n/2)); 21 | f1=1-6*normt1.^2+6*normt1.^3; 22 | f2=2*(1-normt2).^3; 23 | f=[f1; f2]; 24 | f=[f(length(f):-1:1,1) ;f]; 25 | f=f/sqrt(f'*f)*sqrt(length(f)); 26 | else 27 | parzmesh=meshgrid(parzwin(sn(1)),1:sn(2))'; 28 | f=n.*parzmesh; 29 | end 30 | -------------------------------------------------------------------------------- /sdofcf.m: -------------------------------------------------------------------------------- 1 | function [z,nf,a]=sdofcf(f,TF,Fmin,Fmax) 2 | %[z,nf,a]=sdofcf(f,TF,Fmin,Fmax) Curve fit to SDOF FRF. 3 | % f is the frequency vector in Hz. It does not have to 4 | % start at 0 Hz. 5 | % TF is the complex transfer function. 6 | % z and nf are the damping ratio and natural frequency (Hz) 7 | % a is the numerator of the identified transfer function. 8 | % a 9 | % T=------------------ 10 | % 1-r^2+2 zeta r j 11 | % Only one peak may exist in the segment of the FRF passed to 12 | % sdofcf. No zeros may exist withing this segment. If so, 13 | % curve fitting becomes unreliable. 14 | % Fmin is the minimum frequency to be used for curve fitting in the 15 | % FRF 16 | % Fmax is the maximum frequency to be used for curve fitting in the 17 | % FRF 18 | % 19 | % 20 | % EXAMPLE: 21 | % M=eye(2); 22 | % K=[2 -1;-1 2]; 23 | % C=.0001*K; 24 | % [Freq,Recep,Mobil,Inert]=vtb7_5(M,C,K,1,2,linspace(0,.5,1024)); 25 | % figure(1) 26 | % n=length(Freq); 27 | % f2=Freq; 28 | % R2=Recep; 29 | % R2=R2+1*randn(n,1)+1*randn(n,1)*i;% Poorly Simulated Noise 30 | % [z,nf,a]=sdofcf(f2,R2,.14,.17),pause 31 | % [z,nf,a]=sdofcf(f2,R2,.27,.28) 32 | % 33 | % 34 | % 35 | % Note that by changing the parts of Freq and Recep used 36 | % We can curve fit to other modes. 37 | 38 | % Copyright Joseph C. Slater, 10/8/99 39 | % Updated 11/8/99 to improve robustness 40 | % Updated 1/1/00 to improve robustness 41 | % Updated 4/1/01 from vtb7_4 to linear curve fitting. 42 | % 5/1/01 included residuals properly (Undocumented). 43 | % 4/15/03 added limits for frequency of FRF curve fit. 44 | 45 | %tfplot(f,TF) 46 | %pause 47 | 48 | inlow=1; 49 | inhigh=length(f); 50 | if nargin==4 51 | inlow=floor(length(f)*(Fmin-min(f))/(max(f)-min(f)))+1; 52 | inhigh=ceil(length(f)*(Fmax-min(f))/(max(f)-min(f)))+1; 53 | end 54 | 55 | if f(inlow)==0 56 | inlow=2; 57 | end 58 | f=f(inlow:inhigh,:); 59 | TF=TF(inlow:inhigh,:); 60 | 61 | 62 | R=TF; 63 | [y,in]=max(abs(TF)); 64 | 65 | ll=length(f); 66 | w=f*2*pi*sqrt(-1); 67 | w2=w*0; 68 | R3=R*0; 69 | for i=1:ll 70 | R3(i)=conj(R(ll+1-i)); 71 | w2(i)=conj(w(ll+1-i)); 72 | end 73 | w=[w2;w]; 74 | R=[R3;R]; 75 | 76 | n=1; 77 | N=2*n; 78 | N=2; 79 | [x,y]=meshgrid(0:N,R); 80 | [x,w2d]=meshgrid(0:N,w); 81 | c=-w.^(N).*R; 82 | 83 | aa=[w2d(:,1+(0:N-1)).^x(:,1+(0:N-1)).*y(:,1+(0:N-1)) -w2d(:,1+(0:N)).^x(:,1+(0:N))]; 84 | 85 | %aa(1:4,:) 86 | %a0=w.^0.*R; 87 | %a1=w.^1.*R; 88 | %a2=w.^2.*R; 89 | %a3=w.^3.*R; 90 | %a3=R*0-1; 91 | %aa=[a0 a1 a2 -w.^0 -w.^1]; 92 | 93 | %a=[a0 a1 a2];% -w.^0 -w.^1]; 94 | %a=[a0 a1 a2 -w.^0 -w.^1]; 95 | %a(1:10,:) 96 | 97 | %size(aa),size(c) 98 | 99 | 100 | b=aa\c; 101 | %real([1 b((N-1:-1:0)+1)']) 102 | %[1 b((N-1:-1:0)+1)'] 103 | rs=roots([1 b((N-1:-1:0)+1)']); 104 | 105 | [srs,irs]=sort(abs(imag(rs))); 106 | 107 | rs=rs(irs); 108 | rs; 109 | omega=abs(rs(2)); 110 | z=-real(rs(2))/abs(rs(2)); 111 | nf=omega/2/pi; 112 | 113 | XoF1=1./(w.^2+2*z*w*omega+omega^2); 114 | XoF1=[1./(w-rs(1)) 1./(w-rs(2))]; 115 | XoF2=1./(w+rs(1)); 116 | XoF2=1./(w.^0); 117 | XoF3=1./w.^2; 118 | XoF=[XoF1 XoF2 XoF3]; 119 | a=1; 120 | size(XoF); 121 | size(R); 122 | a=XoF\R; 123 | %size(w) 124 | %plot(abs(w)),pause 125 | %tfplot(f,TF) 126 | %tfplot(f,[a*Rest,R]) 127 | %size(XoF) 128 | XoF=XoF((ll+1:2*ll)-2*0,:)*a; 129 | 130 | a=sqrt(-2*imag(a(1))*imag(rs(1))-2*real(a(1))*real(rs(1))); 131 | 132 | %plot(abs(w(ll:2*ll))) 133 | %pause 134 | %break 135 | Fmin=min(f); 136 | Fmax=max(f); 137 | phase=unwrap(angle(TF))*180/pi; 138 | phase2=unwrap(angle(XoF))*180/pi;size(phase); 139 | %size(XoF) 140 | subplot(2,1,1) 141 | plot(f,20*log10(abs(XoF)),f,20*log10(abs(TF))) 142 | as=axis; 143 | zoom on 144 | legend('Identified FRF','Experimental FRF',0) 145 | min(f); 146 | 147 | axis([Fmin Fmax as(3) as(4)]) 148 | xlabel('Frequency (Hz)') 149 | ylabel('Mag (dB)') 150 | grid on 151 | % Fmin,Fmax,min(mag),max(mag) 152 | % axis([Fmin Fmax minmag maxmag]) 153 | while phase2(in)>50 154 | phase2=phase2-360; 155 | end 156 | phased=phase2(in)-phase(in); 157 | phase=phase+round(phased/360)*360; 158 | phmin_max=[floor(min(min([phase;phase2]))/45)*45 ceil(max(max([phase;phase2]))/45)*45]; 159 | subplot(2,1,2) 160 | plot(f,phase2,f,phase) 161 | xlabel('Frequency (Hz)') 162 | ylabel('Phase (deg)') 163 | legend('Identified FRF','Experimental FRF',0) 164 | 165 | grid on 166 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 167 | gridmin_max=round(phmin_max/90)*90; 168 | set(gca,'YTick',gridmin_max(1):22.5:gridmin_max(2)) 169 | zoom on 170 | a=a(1)^2/(2*pi*nf)^2; 171 | 172 | if nargout==0 173 | disp('') 174 | disp(['zeta = ' num2str(z)]) 175 | disp(['f = ' num2str(nf) ' Hz.']) 176 | disp(['amplitude = ' num2str(2*imag(a(1))^2) '.']) 177 | disp('') 178 | clear z a nf 179 | end 180 | %disp('error still needing correction to use 7.38') 181 | %figure,tfplot(f,(a^2)./((nf*2*pi)^2-(2*pi*f).^2+z*2*nf*2*pi*2*pi*f*sqrt(-1))) 182 | -------------------------------------------------------------------------------- /so2ss.m: -------------------------------------------------------------------------------- 1 | function [a,b,c,d]=so2ss(M, Dso, K, Bt, Cd, Cv, Ca) 2 | % SO2SS [a,b,c,d]=SO2SS(M, C, K, Bt, Cd, Cv, Ca) returns the state system 3 | % [xdot ] [ 0 I ][ x ] [ 0 ] 4 | % [ ] = [ ][ ] + [ ] [u] 5 | % [xddot] [-M^-1*K -M^-1*C][xdot] [M^-1*Bs] 6 | % 7 | % y = C z + D u 8 | % 9 | % where z = [x' xdot']' 10 | % 11 | % given the second order form equations 12 | % M xddot + C xdot + K x=Bs u 13 | % y = Cd x + Cv xdot + Ca xddot 14 | 15 | % Copyright Joseph C. Slater, 2003 16 | % Updates Dec 11, 2017 to include Cd, Cv, and Ca. 17 | 18 | l=size(M,1); 19 | 20 | if nargin==4 21 | Cd = eye(l) 22 | Ca = zeros(l) 23 | Cv = Ca 24 | elseif nargin<4 25 | Bt=eye(l) 26 | end 27 | 28 | if nargin<3 29 | K=D;D=0*K; 30 | end 31 | 32 | a=[zeros(l) eye(l);-M\K -M\Dso]; 33 | b=[zeros(l,size(Bt,2)); M\Bt]; 34 | c=[Cd-Ca*(M\K), Cv-Ca*(M\Dso)] 35 | d=Ca*(M\Bt); 36 | 37 | -------------------------------------------------------------------------------- /soeig.m: -------------------------------------------------------------------------------- 1 | function [fr,ms]=soeig(m,k,n) 2 | % [fr,ms]=SOEIG(m,k,n) returns the first n natural 3 | % frequencies (in Hz) and mode shapes of 4 | % the second order system defined by m and k. 5 | 6 | % Copyright Joseph C. Slater, 1996 7 | % All rights reserved. 8 | % Added to Vibration Toolbox 9/23/98 9 | 10 | l=max(size(m)); 11 | if nargin==2 12 | n=l; 13 | end 14 | if n>l 15 | disp(['Only ' num2str(l) ' exist.']) 16 | break 17 | end 18 | m=sparse(m); 19 | k=sparse(k); 20 | r=chol(m); 21 | %whos; 22 | kt=(r')\k/r; 23 | kt=(kt+kt')/2; 24 | [v,d]=eig(full(kt)); 25 | [d,i]=sort(sqrt(diag(d)/2/pi)); 26 | u=r\sparse(v); 27 | u=u(:,i); 28 | 29 | fr=d(1:n); 30 | ms=full(u(:,1:n)); 31 | -------------------------------------------------------------------------------- /sostf.m: -------------------------------------------------------------------------------- 1 | function [freqout,recep,mobil,inert]=sostf(M,D,K,numin,numout,freq) 2 | %SOSTF Transfer Function from second order system matrices 3 | % [Freq,Recep,Mobil,Inert] = SOSTF(M,D,K,NUMIN,NUMOUT,Freq) 4 | % returns the Compliance, Mobility, and Inertance Transfer 5 | % Functions (FRF) between a force at degree of freedom 6 | % NUMIN and a response at degree of freedom NUMOUT. 7 | % M, D, and K are the mass, damping, and stiffness matrices 8 | % repectively. Freq is a vector of frequencies over which 9 | % the evaluated transfer function is desired (in Hz). 10 | % 11 | % SOSTF(M,D,K,NUMIN,NUMOUT,Freq) plots the Transfer Functions 12 | % if there are no output arguments. Click in the region of 13 | % interest to zoom in. Each click will double the size of 14 | % the plot. Double click to return to full scale. 15 | % 16 | % See also TFEST and TFPLOT. 17 | 18 | % Copyright (c) 1995 by Joseph C. Slater 19 | % Renamed from tf to sostf 9/23/98 to avoid conflict 20 | % with control toolbox 21 | % Switched call from f_sspace to ssit 9/23/98 22 | 23 | n=256; 24 | M=sparse(M); 25 | K=sparse(K); 26 | D=sparse(D); 27 | if exist('freq')~=1 28 | % nf=(sqrt(eig(K,M)))/2/pi 29 | % [nf2,shape]=f_sspace(K,M,1,ones(max(size(M)),1)); 30 | [nf2,shape]=ssit(M,K,1); 31 | nf2=nf2*2*pi*2*pi; 32 | nfmax=1/nf2*1.3; 33 | [nf2,shape]=ssit(M,K,1); 34 | nfmin=nf2/4; 35 | freq=(nfmin:(nfmax-nfmin)/(n-1):nfmax)'; 36 | elseif length(freq)==2 37 | fmin=freq(1);fmax=freq(2); 38 | freq=(fmin:(fmax-fmin)/(n-1):fmax)'; 39 | elseif size(freq,1)==1 40 | freq=freq'; 41 | end 42 | if freq(1)==0 43 | freq(1)=freq(2)/100; 44 | end 45 | 46 | omega=freq*2*pi; 47 | 48 | sizem=max(size(M)); 49 | p=[1:sizem]'; 50 | if numin==1; 51 | pin=p(2:sizem); 52 | elseif numin==sizem 53 | pin=p(1:numin-1); 54 | else 55 | pin=p([1:numin-1,numin+1:sizem]); 56 | end 57 | 58 | if numout==1; 59 | pout=p(2:sizem); 60 | elseif numin==sizem 61 | pout=p(1:numout-1); 62 | else 63 | pout=p([1:numout-1,numout+1:sizem]); 64 | end 65 | 66 | adsign=(-1)^(numin+numout); 67 | tfunc1=omega; 68 | 69 | Ms=M(pout,pin); 70 | Ds=D(pout,pin); 71 | Ks=K(pout,pin); 72 | 73 | for i=1:length(omega) 74 | MDKs=Ks+j*omega(i)*Ds-omega(i)^2*Ms; 75 | MDK=K+j*omega(i)*D-omega(i)^2*M; 76 | tfunc1(i)=det(MDKs)/det(MDK); 77 | end 78 | 79 | tfunc1=tfunc1*adsign; 80 | 81 | %i=1:length(omega); 82 | %tfunc1=adsign*det(Ks+j*omega(i)*Ds-omega(i).^2*Ms)/det(K+j*omega(i)*D-omega(i).^2*M); 83 | 84 | tfunc2=tfunc1.*omega*j; 85 | tfunc3=-tfunc1.*omega.^2; 86 | 87 | % If no left hand arguments then plot results 88 | if nargout==0 89 | subplot(211) 90 | plot(freq,20*log10(abs(tfunc1))) 91 | title('Compliance Transfer Function') 92 | 93 | xlabel('Frequency (Hz)') 94 | ylabel('Mag (dB)') 95 | grid on 96 | zoom on 97 | subplot(212) 98 | phase=[angle(tfunc1(1)) ; unwrap(angle(tfunc1(2:length(tfunc1))))]*180/pi; 99 | plot(freq,phase) 100 | 101 | xlabel('Frequency (Hz)') 102 | ylabel('Phase (deg)') 103 | grid on 104 | sphase=sort(phase); 105 | numnan=sum(isnan(sphase));size(numnan); 106 | sphase=sphase(1:length(sphase)-numnan); 107 | phmin_max=[floor(min(sphase)/45)*45-5 ceil(max(sphase)/45)*45+5]; 108 | set(gca,'YLim',phmin_max) 109 | gridmin_max=round(phmin_max/90)*90; 110 | % set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 111 | % set(gca,'GridLineStyle','--') 112 | % gridmin_max=round(phmin_max/45)*45; 113 | % set(gca,'YTick',gridmin_max(1):45:gridmin_max(2)) 114 | % set(gca,'GridLineStyle',':') 115 | % set(gca,'YTickLabels',gridmin_max(1):90:gridmin_max(2)) 116 | zoom on 117 | % uicontrol('style','pushbutton','units','normal','position',[.91 .95 .075 .05],'string','Print','callback','print') 118 | pause 119 | 120 | subplot(211) 121 | plot(freq,20*log10(abs(tfunc2))) 122 | title('Mobility Transfer Function') 123 | xlabel('Frequency (Hz)') 124 | ylabel('Mag (dB)') 125 | grid on 126 | zoom on 127 | subplot(212) 128 | if isnan(angle(tfunc2(1)))==1 129 | tfunc2(1)=0; 130 | end 131 | angle(tfunc2(1:10)); 132 | 133 | phase=[angle(tfunc2(1)) ; unwrap(angle(tfunc2(2:length(tfunc2))))]*180/pi; 134 | plot(freq,phase) 135 | 136 | xlabel('Frequency (Hz)') 137 | ylabel('Phase (deg)') 138 | grid on 139 | sphase=sort(phase); 140 | numnan=sum(isnan(sphase)); 141 | sphase=sphase(1:length(sphase)-numnan); 142 | phmin_max=[floor(min(sphase)/45)*45-5 ceil(max(sphase)/45)*45+5]; 143 | set(gca,'YLim',phmin_max) 144 | gridmin_max=round(phmin_max/90)*90; 145 | % set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 146 | % set(gca,'GridLineStyle','--') 147 | % gridmin_max=round(phmin_max/45)*45; 148 | % set(gca,'YTick',gridmin_max(1):45:gridmin_max(2)) 149 | set(gca,'GridLineStyle',':') 150 | % set(gca,'YTickLabels',gridmin_max(1):90:gridmin_max(2)) 151 | zoom on 152 | pause 153 | 154 | subplot(211) 155 | %plot(freq,20*log10(abs(tfunc3))) 156 | title('Inertance Transfer Function') 157 | 158 | xlabel('Frequency (Hz)') 159 | ylabel('Mag (dB)') 160 | grid on 161 | zoom on 162 | subplot(212) 163 | if isnan(angle(tfunc3(1)))==1 164 | tfunc3(1)=0; 165 | end 166 | phase=[angle(tfunc3(1)) ; unwrap(angle(tfunc1(2:length(tfunc3))))]*180/pi; 167 | plot(freq,phase) 168 | 169 | xlabel('Frequency (Hz)') 170 | ylabel('Phase (deg)') 171 | grid on 172 | sphase=sort(phase); 173 | numnan=sum(isnan(sphase)); 174 | sphase=sphase(1:length(sphase)-numnan); 175 | phmin_max=[floor(min(sphase)/45)*45-5 ceil(max(sphase)/45)*45+5]; 176 | if phmin_max(1)==phmin_max(2) 177 | phmin_max(1)=-.000000000001+phmin_max(1); 178 | phmin_max(2)=.000000000001+phmin_max(2); 179 | end 180 | set(gca,'YLim',phmin_max) 181 | gridmin_max=round(phmin_max/90)*90; 182 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 183 | % set(gca,'GridLineStyle','--') 184 | % gridmin_max=round(phmin_max/45)*45; 185 | % set(gca,'YTick',gridmin_max(1):45:gridmin_max(2)) 186 | set(gca,'GridLineStyle',':') 187 | % set(gca,'YTickLabels',gridmin_max(1):90:gridmin_max(2)) 188 | zoom on 189 | 190 | return 191 | end 192 | 193 | freqout=freq; 194 | recep=tfunc1; 195 | mobil=tfunc2; 196 | inert=tfunc3; 197 | 198 | -------------------------------------------------------------------------------- /ssim.m: -------------------------------------------------------------------------------- 1 | function [xout,xdotout,xddotout]=ssim(M,D,K,f,t,x0,v0) 2 | %SSIM Linear second order system simulation. 3 | % [X,V,A] = SSIM(M,D,K,f,t,x0,v0) simulates the system described by 4 | % 2 5 | % d x dx 6 | % M -- + D -- + K x = f 7 | % 2 dt 8 | % dt 9 | % 10 | % to the force f. The matrix f must have as many columns as 11 | % there are degrees of freedom. Each row "i" of f corresponds to 12 | % the forcing function vector evaluated at t(i). The length of f 13 | % must be the same as the length of t. The vectors x0 and v0 14 | % represent the initial conditions, if they exist. 15 | % 16 | % SSIM(M,D,K,f,t) will plot the response of the system. 17 | % 18 | % Example: 19 | % m=eye(2); % mass matrix 20 | % k=[2 -1;-1 1]; % stiffness matrix 21 | % d=.05*k; % damping matrix 22 | % n=4048;dt=.2; % 23 | % t=(0:n-1)'*dt; % time vector 24 | % f=[sin(10*t) zeros(size(t))]; % 25 | % ssim(m,d,k,f,t) 26 | % 27 | % See also LSIM 28 | 29 | % Copyright (c) 1995 by Joseph C. Slater 30 | 31 | sm=size(M); 32 | 33 | if nargin==5 34 | x0=zeros(sm(1),1); 35 | v0=x0; 36 | end 37 | 38 | A=[zeros(sm) eye(sm);-M\K -M\D]; 39 | 40 | B=eye(sm*2); 41 | 42 | dt=t(2)-t(1); 43 | 44 | Ad=expm(A*dt); 45 | Bd=A\(Ad-eye(size(Ad)))*B; 46 | 47 | sf=size(f); 48 | z=ltitr(Ad,Bd,[zeros(size(f)),f],[x0;v0]); 49 | 50 | X=z(:,1:sf(2)); 51 | 52 | V=z(:,sf(2)+1:sf(2)*2); 53 | 54 | A=M\(f'-D*V'-K*X'); 55 | 56 | if nargout==0 57 | 58 | plot(t,X) 59 | 60 | title('Displacements versus Time') 61 | xlabel('Time') 62 | ylabel('Displacements') 63 | grid 64 | zoom on 65 | 66 | pause 67 | plot(t,V) 68 | 69 | title('Velocities versus Time') 70 | xlabel('Time') 71 | ylabel('Velocities') 72 | grid 73 | zoom on 74 | pause 75 | plot(t,A) 76 | 77 | title('Accelerations versus Time') 78 | xlabel('Time') 79 | ylabel('Accelerations') 80 | grid 81 | zoom on 82 | return 83 | end 84 | xout=X; 85 | xdotout=V; 86 | xddotout=A; 87 | 88 | 89 | -------------------------------------------------------------------------------- /ssit.m: -------------------------------------------------------------------------------- 1 | function [lambda,phi]=ssit(M,K,p,tol,q) 2 | % SSIT Subspace iteration 3 | % 4 | % [lambda,phi] = SSIT(M,K,p,tol,q) produces matrices lambda and phi 5 | % corresponding to the first p eigenvalues and eigenvectors of 6 | % the eigenvalue problem M*phi=K*lambda*phi. The variable tol defines 7 | % the convergence tolerance such that lambda(i) has converged to tol 8 | % places for 16 25 | n=6; 26 | else 27 | n=1; 28 | end 29 | 30 | shift=mean(diag(K))/mean(diag(M))/10^6; 31 | K=K+M*shift; 32 | % Sparse setup 33 | M=sparse(M); 34 | K=sparse(K); 35 | n=length(M); 36 | R=chol(M);%whos 37 | K=R'\K/R; 38 | M=diag(sparse(ones(n,1))); 39 | % Set up initial vectors 40 | MX=zeros(n,q);MX=sparse(MX); 41 | [y,i]=sort(-1./diag(K)); 42 | MX(i(1:q-1),1:q-1)=eye(q-1,q-1); 43 | MX(:,q)=diag(M); 44 | X=K\MX; 45 | 46 | % We'll do this a lot, so let's get it right now. 47 | kim=K\M; 48 | 49 | 50 | % We need something to compare to the first time. 51 | % The negative assures convergence won't happen the first time. 52 | %pause 53 | lambdaold=-eye(p,p); 54 | 55 | for fa=1:10000 56 | kp=X'*K*X;%disp('kp') 57 | mp=X'*M*X;%disp('mp'), 58 | [phip,lambda]=eig(full(kp),full(mp));%disp('eig') 59 | [y,i]=sort(diag(lambda)); 60 | phip=sparse(phip(1:q,i)); 61 | lambda=sparse(diag(y));%whos 62 | disp(['Iteration ' num2str(fa) '. Current 1st natural frequency ' num2str(sqrt(lambda(1,1)-shift)/2/pi) ' Hz.' ]) 63 | X=X*phip; 64 | % Normalization that is not really needed except for final result 65 | nx=diag(1./sqrt(sum(X.^2,1))); 66 | X=X*nx; 67 | lambda 68 | % Check to see if first p eigenvalues have converged. 69 | abs(diag(lambdaold(n:p,n:p)-lambda(n:p,n:p))/diag(lambdaold(n:p,n:p))) 70 | if (abs(diag(lambdaold(n:p,n:p)-lambda(n:p,n:p))/diag(lambdaold(n:p,n:p))))... 71 | <10^(-tol) 72 | break 73 | end 74 | % pause 75 | X=kim*X; 76 | lambdaold=lambda; 77 | 78 | end 79 | nx=diag(1./sqrt(sum(X.^2,1))); 80 | phi=X*nx; 81 | j; 82 | phi=R\phi; 83 | lambda=lambda-shift*eye(size(lambda)); 84 | -------------------------------------------------------------------------------- /templogo.m: -------------------------------------------------------------------------------- 1 | cura=gca; 2 | axes('units','normal','position',[0 0 .4 .05],'visible','off') 3 | h=text(0.0,0.0,'The Vibration Toolbox','color',[1 1 0],... 4 | 'units','normalized','fontsize',10,... 5 | 'fontname','times','fontangle','ital','verticalalignment','bottom',... 6 | 'horizontalalignment','left','visible','on'); 7 | set(gcf,'currentaxes',cura); 8 | -------------------------------------------------------------------------------- /testdata.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/testdata.mat -------------------------------------------------------------------------------- /tfest.m: -------------------------------------------------------------------------------- 1 | function [freqout,tfout]=tfest(x,f,dt,n,options) 2 | %TFEST Estimates Transfer Function 3 | % [Freq,Txf] = TFEST(X,F,DT,N,OPTIONS) estimates the 4 | % Frequency Response Function (FRF) between X and F 5 | % (X/F) using either a Fast Fourier Transform when 6 | % possible, or a Discrete Fourier Transform otherwise. 7 | % TFEST calculates the H1 FRF (Sxf/Sff) by default. 8 | % Freq is the frequency vector in Hertz and Txf is the 9 | % Transfer Function in complex form. N is the number 10 | % of points used in the Fourier transform. The default 11 | % value is the length of the vectors if it is a power 12 | % of 2 or the next power of 2 after the length of the 13 | % vectors. DT is the time step of the sampled data. 14 | % If DT is replaced by the time vector, DT will be extracted 15 | % from the time vector using DT = T(2) - T(1). If X and 16 | % F are matrices, TFEST will find the frequency response 17 | % function for each column and average the results unless 18 | % OPTIONS{1} is set to 'no'. 19 | % The value of OPTIONS{2} defines the type of FRF estimation. 20 | % OPTIONS{2} = 1 is the default, resulting in use of the H1 21 | % FRF algorithm (Sxf/Sff) minimizing noise on the output. If 22 | % OPTIONS{2} = 2, the H2 FRF algorithm (Sxx/Sff) is used, 23 | % minimizing noise on the input. If OPTIONS{2} = 3, the Hv 24 | % algorithm is used, minimizing noise on both the input and 25 | % the output. 26 | % 27 | % NOTE: Using the Hv algorithm will take significantly longer 28 | % to run. 29 | % NOTE: OPTIONS is a cell array. Please be sure to use curly brackets "{}" 30 | % as shown if you choose to use this option. 31 | % N and OPTIONS are optional. Either can be 32 | % be left out. 33 | % 34 | % TFEST(X,Y,DT,N,OPTIONS) plots the Frequency Response Function 35 | % if there are no output arguments. Click in the region of 36 | % interest to zoom in. Each click will double the size of the 37 | % plot. Double click to return to full scale. 38 | % 39 | % See also COH, ASD, CRSD, and TFPLOT. 40 | 41 | % Copyright (c) 1994 by Joseph C. Slater 42 | % Modifications: 43 | % -------------- 44 | % 7/6/00: Changed default FRF calculation from H2 to H1 45 | % Added H1, H2, and Hv options. 46 | sy=size(f); 47 | if nargin==3 48 | n=2^nextpow2(sy(1)); 49 | ave='yes'; 50 | frftype=1; %H1 51 | elseif nargin==4 52 | if strcmp(n(1),'no')|strcmp(n(1),'yes') 53 | ave=n{1}; 54 | if length(n)==1 55 | frftype=1; 56 | else 57 | frftype=n{2}; 58 | end 59 | n=2^nextpow2(sy(1)); 60 | else 61 | ave='yes'; 62 | frftype=1; 63 | end 64 | else 65 | frftype=options{2}; 66 | ave=options{1}; 67 | end 68 | 69 | if isempty(n) 70 | n=2^nextpow2(sy(1)); 71 | end 72 | 73 | 74 | if length(dt)~=1 75 | dt=dt(2)-dt(1); 76 | end 77 | 78 | 79 | if frftype==1 80 | [freq,Pff]=asd(f,dt,n); 81 | [freq,Pxf]=crsd(x,f,dt,n); 82 | tfunc=Pxf./Pff; 83 | disp('H1') 84 | elseif frftype==2 85 | [freq,Pxx]=asd(x,dt,n); 86 | [freq,Pxf]=crsd(x,f,dt,n); 87 | tfunc=Pxx./conj(Pxf); 88 | disp('H2') 89 | elseif frftype==3 90 | [freq,Pxx]=asd(x,dt,n); 91 | [freq,Pff]=asd(f,dt,n); 92 | [freq,Pxf]=crsd(x,f,dt,n); 93 | disp('Hv') 94 | for i=1:size(Pxx,1) 95 | for j=1:size(Pxx,2) 96 | frfm=[Pff(i,j) conj(Pxf(i,j));Pxf(i,j) Pxx(i,j)] 97 | [v,d]=eig(frfm) 98 | [y,yi]=sort(diag(d)); 99 | tfunc(i,j)=-v(1,yi(1))/v(2, yi(1));%,pause 100 | end 101 | end 102 | end 103 | 104 | tfunc=conj(tfunc); 105 | 106 | sfft=size(Pxf); 107 | if sfft(2)~=1 & ~strcmp(ave,'no') 108 | tfunc=mean(tfunc')'; 109 | end 110 | 111 | % If no left hand arguments then plot results 112 | if nargout==0 113 | subplot(211) 114 | plot(freq,20*log10(abs(tfunc))) 115 | 116 | xlabel('Frequency (Hz)') 117 | ylabel('Mag (dB)') 118 | grid 119 | zoom on 120 | subplot(212) 121 | phase=unwrap(angle(tfunc))*180/pi; 122 | %phase=angle(tfunc)*180/pi; 123 | plot(freq,phase) 124 | 125 | xlabel('Frequency (Hz)') 126 | ylabel('Phase (deg)') 127 | grid 128 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 129 | set(gca,'YLim',phmin_max) 130 | gridmin_max=round(phmin_max/90)*90; 131 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 132 | 133 | set(gca,'GridLineStyle',':') 134 | set(gca,'YTickLabel',gridmin_max(1):90:gridmin_max(2)) 135 | zoom on 136 | return 137 | end 138 | 139 | freqout=freq; 140 | tfout=tfunc; 141 | -------------------------------------------------------------------------------- /tfplot.m: -------------------------------------------------------------------------------- 1 | function TFPLOT(F,Xfer,Fmin,Fmax,FLAG) 2 | %TFPLOT Plots various transfer functions. 3 | % TFPLOT(F,Xfer,Fmin,Fmax) plots the transfer function 4 | % between Fmin and Fmax. F is the frequency vector (in Hz), 5 | % Xfer is the transfer function. Fmin and Fmax are the 6 | % minimum and maximum frequencies to be shown on the plot. 7 | % 8 | % TFPLOT(F,Xfer) plots the transfer function over the 9 | % entire frequency range of F. 10 | % 11 | % TFPLOT(F,Xfer,Fmin,Fmax,FLAG) plots the transfer 12 | % function in different forms depending on the value 13 | % of FLAG. Click in the region of interest 14 | % to zoom in. Each click will double the size of the plot. 15 | % Double click to return to full scale. 16 | % 17 | % FLAG(1) Plot Type 18 | % ------- --------- 19 | % 1 (def) Magnitude and Phase versus F 20 | % 2 Magnitude and Phase versus log10(F) 21 | % 3 Bodelog (Magnitude and Phase versus log10(w)) 22 | % 4 Real and Imaginary 23 | % 5 Nyquist (Real versus Imaginary) 24 | % 6 Magnitude versus F 25 | % 7 Phase versus F 26 | % 8 Real versus F 27 | % 9 Imaginary versus F 28 | % 10 Magnitude versus log10(F) 29 | % 11 Phase versus log10(F) 30 | % 12 Real versus log10(F) 31 | % 13 Imaginary versus log10(F) 32 | % 14 Magnitude versus log10(w) 33 | % 15 Phase versus log10(w) 34 | % 35 | % 36 | % TFPLOT(F,Xfer,FLAG) plots the transfer function 37 | % over the entire frequency range of F in the 38 | % form defined by FLAG. 39 | % 40 | % Example (copy and paste into Matlab command line): 41 | % f=(0:.01:100)'; 42 | % w=f*2*pi; 43 | % k=1e5;m=1;c=1; 44 | % tf=1./(m*(w*j).^2+c*j*w+k); 45 | % figure(1);tfplot(f,tf) 46 | % figure(2);tfplot(f,tf,5) 47 | % 48 | % See also TFEST, ASD, and CRSD. 49 | 50 | % Copyright J. Slater, Dec 17, 1994 51 | % Updated April 27, 1995 52 | 53 | %Copy protection, expires Jan 1, 2001 54 | lenF=length(F); 55 | 56 | if lenF==1; 57 | F=(0:length(Xfer)-1)'*F; 58 | end 59 | if nargin==2 60 | Fmin=min(F); 61 | Fmax=max(F); 62 | FLAG=1; 63 | elseif nargin==3 64 | FLAG=Fmin; 65 | if FLAG~=2 66 | Fmin=min(F); 67 | Fmax=max(F); 68 | else 69 | Wmin=min(F)*2*pi; 70 | Wmax=max(F)*2*pi; 71 | end 72 | elseif nargin==4 73 | Fmax=min([max(F) Fmax]); 74 | Fmin=max([min(F) Fmin]); 75 | FLAG=1; 76 | else 77 | if (FLAG~=3 & FLAG~=14 & FLAG~=15) 78 | Fmax=min([max(F) Fmax]); 79 | Fmin=max([min(F) Fmin]); 80 | else 81 | Wmax=min([max(F)*2*pi Fmax*2*pi]); 82 | Wmin=max([min(F)*2*pi Fmin*2*pi]); 83 | end 84 | end 85 | 86 | if Fmin>Fmax 87 | disp('Fmin must be less than Fmax.') 88 | return 89 | end 90 | 91 | 92 | inlow=floor(length(F)*(Fmin-min(F))/(max(F)-min(F)))+1; 93 | 94 | inhigh=ceil(length(F)*(Fmax-min(F))/(max(F)-min(F)))+1; 95 | if inlow<1,inlow=1;end 96 | if inhigh>lenF,inhigh=lenF;end 97 | Xfer=Xfer(inlow:inhigh,:); 98 | F=F(inlow:inhigh,:); 99 | mag=20*log10(abs(Xfer)); 100 | mag; 101 | minmag=min(min(mag)); 102 | maxmag=max(max(mag)); 103 | phase=unwrap(angle(Xfer))*180/pi; 104 | phmin_max=[floor(min(min(phase))/45)*45 ceil(max(max(phase))/45)*45]; 105 | minreal=min(min(real(Xfer))); 106 | maxreal=max(max(real(Xfer))); 107 | minimag=min(min(imag(Xfer))); 108 | maximag=max(max(imag(Xfer))); 109 | 110 | 111 | if FLAG==1 112 | subplot(2,1,1) 113 | plot(F,mag) 114 | xlabel('Frequency (Hz)') 115 | ylabel('Mag (dB)') 116 | grid on 117 | % Fmin,Fmax,min(mag),max(mag) 118 | axis([Fmin Fmax minmag maxmag]) 119 | zoom on 120 | subplot(2,1,2) 121 | plot(F,phase) 122 | xlabel('Frequency (Hz)') 123 | ylabel('Phase (deg)') 124 | grid on 125 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 126 | gridmin_max=round(phmin_max/90)*90; 127 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 128 | zoom on 129 | elseif FLAG==2 130 | subplot(2,1,1) 131 | semilogx(F,mag) 132 | xlabel('Frequency (Hz)') 133 | ylabel('Mag (dB)') 134 | grid on 135 | % Fmin,Fmax,min(mag),max(mag) 136 | axis([Fmin Fmax minmag maxmag]) 137 | zoom on 138 | subplot(2,1,2) 139 | semilogx(F,phase) 140 | xlabel('Frequency (Hz)') 141 | ylabel('Phase (deg)') 142 | grid on 143 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 144 | gridmin_max=round(phmin_max/90)*90; 145 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 146 | zoom on 147 | elseif FLAG==3 148 | subplot(2,1,1) 149 | mag=20*log10(abs(Xfer)); 150 | semilogx(F*2*pi,mag) 151 | xlabel('Frequency (Rad/s)') 152 | ylabel('Mag (dB)') 153 | grid on 154 | axis([Wmin Wmax minmag maxmag]) 155 | zoom on 156 | subplot(2,1,2) 157 | semilogx(F*2*pi,phase) 158 | xlabel('Frequency (Rad/s)') 159 | ylabel('Phase (deg)') 160 | grid on 161 | axis([Wmin Wmax phmin_max(1) phmin_max(2)]) 162 | gridmin_max=round(phmin_max/90)*90; 163 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 164 | zoom on 165 | elseif FLAG==4 166 | subplot(2,1,1) 167 | plot(F,real(Xfer)) 168 | xlabel('Frequency (Hz)') 169 | ylabel('Real') 170 | grid on 171 | axis([Fmin Fmax minreal maxreal]) 172 | zoom on 173 | subplot(2,1,2) 174 | plot(F,imag(Xfer)) 175 | xlabel('Frequency (Hz)') 176 | ylabel('Imaginary') 177 | grid on 178 | axis([Fmin Fmax minimag maximag]) 179 | zoom on 180 | elseif FLAG==5 181 | subplot(1,1,1) 182 | imax=round(length(F)*Fmax/max(F)); 183 | imin=round(length(F)*Fmin/max(F))+1; 184 | plot(real(Xfer(imin:imax)),imag(Xfer(imin:imax))) 185 | xlabel('Real') 186 | ylabel('Imaginary') 187 | grid on 188 | zoom on 189 | elseif FLAG==6 190 | subplot(1,1,1) 191 | mag=20*log10(abs(Xfer)); 192 | plot(F,mag) 193 | xlabel('Frequency (Hz)') 194 | ylabel('Mag (dB)') 195 | grid on 196 | axis([Fmin Fmax minmag maxmag]) 197 | zoom on 198 | elseif FLAG==7 199 | subplot(1,1,1) 200 | plot(F,phase) 201 | xlabel('Frequency (Hz)') 202 | ylabel('Phase (deg)') 203 | grid on 204 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 205 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 206 | gridmin_max=round(phmin_max/90)*90; 207 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 208 | zoom on 209 | elseif FLAG==8 210 | subplot(1,1,1) 211 | plot(F,real(Xfer)) 212 | xlabel('Frequency (Hz)') 213 | ylabel('Real') 214 | grid on 215 | axis([Fmin Fmax minreal maxreal]) 216 | zoom on 217 | elseif FLAG==9 218 | subplot(1,1,1) 219 | plot(F,imag(Xfer)) 220 | xlabel('Frequency (Hz)') 221 | ylabel('Imaginary') 222 | grid on 223 | axis([Fmin Fmax minimag maximag]) 224 | zoom on 225 | elseif FLAG==10 226 | subplot(1,1,1) 227 | mag=20*log10(abs(Xfer)); 228 | semilogx(F,mag) 229 | xlabel('Frequency (Hz)') 230 | ylabel('Mag (dB)') 231 | grid on 232 | axis([Fmin Fmax minmag maxmag]) 233 | zoom on 234 | elseif FLAG==11 235 | subplot(1,1,1) 236 | semilogx(F,phase) 237 | xlabel('Frequency (Hz)') 238 | ylabel('Phase (deg)') 239 | grid on 240 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 241 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 242 | gridmin_max=round(phmin_max/90)*90; 243 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 244 | zoom on 245 | elseif FLAG==12 246 | subplot(1,1,1) 247 | semilogx(F,real(Xfer)) 248 | xlabel('Frequency (Hz)') 249 | ylabel('Real') 250 | grid on 251 | axis([Fmin Fmax minreal maxreal]) 252 | zoom on 253 | elseif FLAG==13 254 | subplot(1,1,1) 255 | semilogx(F,imag(Xfer)) 256 | xlabel('Frequency (Hz)') 257 | ylabel('Imaginary') 258 | grid on 259 | axis([Fmin Fmax minimag maximag]) 260 | zoom on 261 | elseif FLAG==14 262 | subplot(1,1,1) 263 | mag=20*log10(abs(Xfer)); 264 | semilogx(F*2*pi,mag) 265 | xlabel('Frequency (Rad/s)') 266 | ylabel('Mag (dB)') 267 | grid on 268 | axis([Wmin Wmax minmag maxmag]) 269 | zoom on 270 | elseif FLAG==15 271 | subplot(1,1,1) 272 | semilogx(F*2*pi,phase) 273 | xlabel('Frequency (Rad/s)') 274 | ylabel('Phase (deg)') 275 | grid on 276 | axis([Wmin Wmax phmin_max(1) phmin_max(2)]) 277 | gridmin_max=round(phmin_max/90)*90; 278 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 279 | zoom on 280 | else 281 | subplot(2,1,1) 282 | mag=20*log10(abs(Xfer)); 283 | plot(F,mag) 284 | xlabel('Frequency (Hz)') 285 | ylabel('Mag (dB)') 286 | grid on 287 | axis([Fmin Fmax minmag maxmag]) 288 | zoom on 289 | subplot(2,1,2) 290 | plot(F,phase) 291 | xlabel('Frequency (Hz)') 292 | ylabel('Phase (deg)') 293 | grid on 294 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 295 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 296 | gridmin_max=round(phmin_max/90)*90; 297 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 298 | zoom on 299 | end 300 | -------------------------------------------------------------------------------- /tfplot2.m: -------------------------------------------------------------------------------- 1 | function TFPLOT(F,Xfer,Fmin,Fmax,FLAG,junk) 2 | %TFPLOT Plots various transfer functions. 3 | % TFPLOT(F,Xfer,Fmin,Fmax) plots the transfer function 4 | % between Fmin and Fmax. F if the frequency vector (Hz), 5 | % Xfer is the transfer function. Fmin and Fmax are the 6 | % minimum and maximum frequencies to be shown on the plot. 7 | % 8 | % TFPLOT(F,Xfer) plots the transfer function over the 9 | % entire frequency range of F. 10 | % 11 | % TFPLOT(F,Xfer,Fmin,Fmax,FLAG) plots the transfer 12 | % function in different forms depending on the value 13 | % of FLAG. Click in the region of interest 14 | % to zoom in. Each click will double the size of the plot. 15 | % Double click to return to full scale. 16 | % 17 | % FLAG(1) Plot Type 18 | % ------- --------- 19 | % 1 (def) Bodelin (Magnitude and Phase versus F) 20 | % 2 Bodelog (Magnitude and Phase versus log10(W)) 21 | % 3 Real and Imaginary 22 | % 4 Nyquist (Real versus Imaginary) 23 | % 5 Magnitude Only 24 | % 6 Phase Only 25 | % 7 Real Only 26 | % 8 Imaginary Only 27 | % 28 | % FLAG(1)=2 plots versus the log base 10 of the frequency in 29 | % Rad/s. 30 | % 31 | % TFPLOT(F,Xfer,FLAG) plots the transfer function 32 | % over the entire frequency range of F in the 33 | % form defined by FLAG. 34 | % 35 | % See also TFEST, ASD, and CRSD. 36 | 37 | % Copyright J. Slater, Dec 17, 1994 38 | if length(F)==1; 39 | F=(0:length(Xfer)-1)'*F; 40 | end 41 | if nargin==2 42 | Fmin=min(F); 43 | Fmax=max(F); 44 | FLAG=1; 45 | elseif nargin==3 46 | FLAG=Fmin; 47 | Fmin=min(F); 48 | Fmax=max(F); 49 | elseif nargin==4 50 | Fmax=min([max(F) Fmax]); 51 | Fmin=max([min(F) Fmin]); 52 | FLAG=1; 53 | end 54 | if nargin~=6 55 | global tfinfo 56 | gcf 57 | tfinfo(gcf,2:5)=[Fmin Fmax length(Xfer) F(2)-F(1)]; 58 | tfinfo(gcf,1:length(Xfer)+5)=[tfinfo(gcf,1:5) Xfer']; 59 | size(tfinfo) 60 | tfinfo(:,1:8) 61 | % tfinfo: Each row is for a new figure (new call to function) 62 | % 1st column is for plot type 63 | % 2nd column if for Fmin 64 | % 3rd column is for Fmax 65 | % 4th column is number of points in transfer function 66 | % 5th column is delta F 67 | % The rest are the data points of the transfer function 68 | tfinfo(gcf,1)=uicontrol(gcf,'style','popup','string',... 69 | 'Bode|Imaginary|Magnitude|Nyquist|Phase|Real|Real and Imaginary',... 70 | 'units','normalized',... 71 | 'position',[.81 .95 .25 .05],... 72 | 'callback',[... 73 | 'global tfinfo ,',... 74 | 'cb_col=[2,8,5,4,6,7,3];',... 75 | 'tfinfo(gcf,1),',... 76 | 'gcf,',... 77 | 'tfinfo(gcf,4),'... 78 | 'disp(''no. points''),',... 79 | 'cb_col(get(tfinfo(gcf,1),''value'')),'... 80 | 'tfplot2(tfinfo(gcf,5),tfinfo(gcf,6:5+tfinfo(gcf,4))'',tfinfo(gcf,2),tfinfo(gcf,3),cb_col(get(tfinfo(gcf,1),''value'')),1)']); 81 | format short 82 | end 83 | % 'cb_col=[''2'',''8'',''5'',''4'',''6'',''7'',''3''];',... 84 | 85 | 86 | Fmax=min([max(F) Fmax]); 87 | Fmin=max([min(F) Fmin]); 88 | 89 | if FLAG==1 90 | subplot(2,1,1) 91 | mag=20*log10(abs(Xfer)); 92 | plot(F,mag) 93 | xlabel('Frequency (Hz)') 94 | ylabel('Mag (dB)') 95 | grid on 96 | axis([Fmin Fmax min(mag) max(mag)]) 97 | zoom on 98 | subplot(2,1,2) 99 | phase=unwrap(angle(Xfer))*180/pi; 100 | plot(F,phase) 101 | xlabel('Frequency (Hz)') 102 | ylabel('Phase (deg)') 103 | grid on 104 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 105 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 106 | gridmin_max=round(phmin_max/90)*90; 107 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 108 | zoom on 109 | elseif FLAG==2 110 | subplot(2,1,1) 111 | mag=20*log10(abs(Xfer)); 112 | semilogx(F*2*pi,mag) 113 | xlabel('Frequency (Rad/s)') 114 | ylabel('Mag (dB)') 115 | grid on 116 | Wmin=min(F)*2*pi; 117 | Wmax=max(F)*2*pi; 118 | axis([Wmin Wmax min(mag) max(mag)]) 119 | zoom on 120 | subplot(2,1,2) 121 | phase=unwrap(angle(Xfer))*180/pi; 122 | semilogx(F*2*pi,phase) 123 | xlabel('Frequency (Rad/s)') 124 | ylabel('Phase (deg)') 125 | grid on 126 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 127 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 128 | gridmin_max=round(phmin_max/90)*90; 129 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 130 | zoom on 131 | elseif FLAG==3 132 | subplot(2,1,1) 133 | plot(F,real(Xfer)) 134 | xlabel('Frequency (Hz)') 135 | ylabel('Real') 136 | grid on 137 | axis([Fmin Fmax min(real(Xfer)) max(real(Xfer))]) 138 | zoom on 139 | subplot(2,1,2) 140 | plot(F,imag(Xfer)) 141 | xlabel('Frequency (Hz)') 142 | ylabel('Imaginary') 143 | grid on 144 | axis([Fmin Fmax min(imag(Xfer)) max(imag(Xfer))]) 145 | zoom on 146 | elseif FLAG==4 147 | subplot(1,1,1) 148 | imax=round(length(F)*Fmax/max(F)); 149 | imin=round(length(F)*Fmin/max(F))+1; 150 | plot(real(Xfer(imin:imax)),imag(Xfer(imin:imax))) 151 | xlabel('Real') 152 | ylabel('Imaginary') 153 | grid on 154 | zoom on 155 | elseif FLAG==5 156 | subplot(1,1,1) 157 | mag=20*log10(abs(Xfer)); 158 | plot(F,mag) 159 | xlabel('Frequency (Hz)') 160 | ylabel('Mag (dB)') 161 | grid on 162 | axis([Fmin Fmax min(mag) max(mag)]) 163 | zoom on 164 | elseif FLAG==6 165 | subplot(1,1,1) 166 | phase=unwrap(angle(Xfer))*180/pi; 167 | plot(F,phase) 168 | xlabel('Frequency (Hz)') 169 | ylabel('Phase (deg)') 170 | grid on 171 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 172 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 173 | gridmin_max=round(phmin_max/90)*90; 174 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 175 | zoom on 176 | elseif FLAG==7 177 | subplot(1,1,1) 178 | plot(F,real(Xfer)) 179 | xlabel('Frequency (Hz)') 180 | ylabel('Real') 181 | grid on 182 | axis([Fmin Fmax min(real(Xfer)) max(real(Xfer))]) 183 | zoom on 184 | elseif FLAG==8 185 | subplot(1,1,1) 186 | plot(F,imag(Xfer)) 187 | xlabel('Frequency (Hz)') 188 | ylabel('Imaginary') 189 | grid on 190 | axis([Fmin Fmax min(imag(Xfer)) max(imag(Xfer))]) 191 | zoom on 192 | else 193 | subplot(2,1,1) 194 | mag=20*log10(abs(Xfer)); 195 | plot(F,mag) 196 | xlabel('Frequency (Hz)') 197 | ylabel('Mag (dB)') 198 | grid on 199 | axis([Fmin Fmax min(mag) max(mag)]) 200 | zoom on 201 | subplot(2,1,2) 202 | phase=unwrap(angle(Xfer))*180/pi; 203 | plot(F,phase) 204 | xlabel('Frequency (Hz)') 205 | ylabel('Phase (deg)') 206 | grid on 207 | phmin_max=[floor(min(phase)/45)*45 ceil(max(phase)/45)*45]; 208 | axis([Fmin Fmax phmin_max(1) phmin_max(2)]) 209 | gridmin_max=round(phmin_max/90)*90; 210 | set(gca,'YTick',gridmin_max(1):90:gridmin_max(2)) 211 | zoom on 212 | end 213 | -------------------------------------------------------------------------------- /triwin.m: -------------------------------------------------------------------------------- 1 | function f = triwin(n) 2 | %TRIWIN Returns of applies Bartlett (triangular) window. 3 | % X=TRIWIN(N) produces an N-point triangle window. 4 | % 5 | % YWIN=TRIWIN(Y) Returns Y with a triangle window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % See also BLACKWIN, BOXWIN, EXPWIN, HAMMWIN, and 10 | % VONHANN. 11 | 12 | % Copyright (c) 1994 by Joseph C. Slater 13 | % 4/6/2003 Normalization for ASD (accurate in limit) 14 | 15 | sn=size(n); 16 | 17 | if sn==[1 1] 18 | if n/2~=floor(n/2) 19 | v=((-n/2+.5):1:(n/2-.5))*2/n; 20 | f=1-abs(v'); 21 | f=f/sqrt(f'*f)*sqrt(length(f)); 22 | %f=f*sqrt(3); 23 | %f=f*(sqrt(n/(n+2/n))); 24 | else 25 | v=(((-n/2)+.5):1:((n/2)-.5))/(n)*2; 26 | f=1-abs(v'); 27 | %f=f*sqrt(3); 28 | f=f/sqrt(f'*f)*sqrt(length(f)); 29 | %f=f*(sqrt(n/(n+2/n))); 30 | end 31 | else 32 | trimesh=meshdom(triwin(sn(1)),1:sn(2))'; 33 | f=n.*trimesh; 34 | end 35 | 36 | -------------------------------------------------------------------------------- /vonhann.m: -------------------------------------------------------------------------------- 1 | function f = vonhann(n) 2 | %VONHANN Returns or applies a von Hann window. 3 | % X=VONHANN(N) produces an N-point von Hann window 4 | % 5 | % YWIN=VONHANN(Y) Returns Y with a von Hann window 6 | % applied to the vector Y or set of vectors 7 | % represented by the matrix Y. 8 | % 9 | % The von Hann window is more commonly known as 10 | % the "hanning" window and derives its name from 11 | % Julius von Hann. 12 | % 13 | % See also BLACKWIN, BOXWIN, EXPWIN, HAMMWIN, and TRIWIN. 14 | 15 | % Copyright (c) 1994 by Joseph C. Slater 16 | % Updated July 20, 1998 to use meshgrid 17 | sn=size(n); 18 | 19 | if sn==[1 1] 20 | f=(sin(pi*((0:n-1)+.5)/(n)).^2)'*sqrt(8/3); 21 | else 22 | hannmesh=meshgrid(hannwin(sn(1)),1:sn(2))'; 23 | f=n.*hannmesh; 24 | end 25 | -------------------------------------------------------------------------------- /vtbfrdem.m: -------------------------------------------------------------------------------- 1 | 2 | %VTDEM Demo for Frequency Domain Section of the Vibration Testing Toolbox 3 | % Run by typing sshow('vtdem') 4 | % 5 | 6 | % Copyright Joseph C. Slater, 1995 7 | 8 | % 9 | numdat=5; %number of runs for averaging 10 | clear y u 11 | %if ~exist('SlideShowGUIFlag'),sshow('vtdem'),return;end 12 | if ~exist('SlideShowGUIFlag'), figNumber=0;end 13 | 14 | load vtdem1 15 | subplot(1,1,1) 16 | imhan=image(x); 17 | colormap(map) 18 | axis('image') 19 | axis('off') 20 | cfun=get(gcf,'units'); 21 | set(gcf,'units','pixels') 22 | cfpos=get(gcf,'position'); 23 | ScreenUnits=get(0,'units'); 24 | set(0,'units','pixels'); 25 | Screensize=get(0,'screensize'); 26 | height=344;width=428; 27 | %cfpos(1:2)=[cfpos(1) cfpos(2)+cfpos(4)-height]; 28 | %cfpos(3:4)=[width height]; 29 | cfpos(1)=(Screensize(3)-width)/2; 30 | cfpos(2)=(Screensize(4)*5/6-height); 31 | cfpos(3)=width; 32 | cfpos(4)=height; 33 | set(gcf,'position',cfpos) 34 | set(gcf,'units',cfun,'resize','off') 35 | 36 | if ssinit(figNumber) 37 | str=... 38 | ['Let''s consider taking a simple two degree of freedom ' 39 | 'spring-mass-damper system connected to ground at the ' 40 | 'left end. Each mass is 1 kg, the springs have a stiffness' 41 | 'of 1 N/m, and dashpots run parallel to the springs ' 42 | 'with damping of .05 N-s/m. ' 43 | '>>m=eye(2); ' 44 | '>>k=[2 -1;-1 1]; ' 45 | '>>d=.05*k; ']; 46 | ssdisp(figNumber,str); 47 | if figNumber,return;end 48 | end 49 | m=eye(2); 50 | k=[2 -1;-1 1]; 51 | d=.05*k; 52 | 53 | str=... 54 | ['The transfer function between a force at degree ' 55 | 'of freedom 1 and the motion at degree of freedom 1 ' 56 | 'can be observed using TF. We''ll plot only the ' 57 | 'compliance transfer function here, but the mobility' 58 | 'and inertance transfer functions can also be easily' 59 | 'obtained using TF. ' 60 | '>>sostf(M,D,K,1,1,[0 1]) ']; 61 | 62 | ssdisp(figNumber,str); 63 | 64 | [Freq,Recep,Mobil,Inert]=sostf(m,d,k,1,1,[0 1]); 65 | tfplot(Freq,Recep) 66 | %subplot(2,1,1) 67 | title('Receptance') 68 | %delete(imhan); 69 | set(gcf,'resize','on') 70 | chil=get(gcf,'children'); 71 | 72 | if sspause(figNumber),return;end; 73 | 74 | dt=.2; 75 | n=4048; 76 | t=(0:n-1)'*dt; 77 | u=randn(n,1); 78 | 79 | for i=1:length(chil) 80 | if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 81 | delete(chil(i)) 82 | i=length(chil); 83 | drawnow 84 | end 85 | end 86 | 87 | str=... 88 | ['To simulate the system under random excitation, we first ' 89 | 'generate a time vector, then use the function RANDN to ' 90 | 'generate a random signal. ' 91 | '>>dt=.2;n=4048; ' 92 | '>>t=(0:n-1)''*dt; ' 93 | '>>u=randn(n,1); ']; 94 | 95 | ssdisp(figNumber,str); 96 | subplot(1,1,1) 97 | curaxe=gca; 98 | plot(t,u), 99 | grid on, 100 | xlabel('Time'), 101 | ylabel('Forcing Function'), 102 | title('Random Force') 103 | %delete(curaxe) 104 | 105 | if sspause(figNumber),return;end; 106 | 107 | str=... 108 | ['It can be seen that this forcing function has a good ' 109 | 'distribution as well (zero mean, nearly Gausian). ' 110 | '>>hist(u); ' 111 | '>>grid ']; 112 | 113 | ssdisp(figNumber,str); 114 | curaxe=gca; 115 | delete(curaxe) 116 | hist(u),grid 117 | axis([-4 4 0 1500]) 118 | if sspause(figNumber),return;end; 119 | 120 | str=... 121 | ['This forcing function has a near constant auto ' 122 | '(power) spectral density too... ' 123 | '>>asd(u,t) ']; 124 | 125 | ssdisp(figNumber,str); 126 | asd(u,t) 127 | chil=get(gcf,'children'); 128 | for i=1:length(chil) 129 | if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 130 | delete(chil(i)) 131 | i=length(chil); 132 | drawnow 133 | break 134 | end 135 | end 136 | 137 | if sspause(figNumber),return;end; 138 | 139 | str=... 140 | ['For a random signal, the auto correlation should be ' 141 | 'zero everywhere except tau=0. ' 142 | '>>crcor(u,u,dt) ']; 143 | 144 | ssdisp(figNumber,str); 145 | crcor(u,u,dt) 146 | chil=get(gcf,'children'); 147 | for i=1:length(chil) 148 | if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 149 | delete(chil(i)) 150 | i=length(chil); 151 | drawnow 152 | break 153 | end 154 | end 155 | 156 | for i=2:numdat 157 | u1=randn(length(t),1); 158 | u=[u u1]; 159 | end 160 | 161 | if sspause(figNumber),return;end; 162 | 163 | str=... 164 | ['Running this process repeatedly, we can obtain a set of' 165 | '5 forcing functions to excite the system with. ' 166 | '>>for i=2:5 ' 167 | '>> u1=randn(length(t),1); ' 168 | '>> u=[u u1]; ' 169 | '>>end ' 170 | '>>plot(t,u) ']; 171 | 172 | ssdisp(figNumber,str); 173 | plot(t,u) 174 | grid on, 175 | xlabel('Time'), 176 | ylabel('Forcing Function'), 177 | title('Random Forces') 178 | pause(.0001) 179 | 180 | 181 | if sspause(figNumber),return;end; 182 | 183 | str=... 184 | ['The cross correlation between each of these signals ' 185 | 'should be zero everywhere if they are truly random. ' 186 | 'This can be observed using the function CRCOR on any ' 187 | 'pair of signals. ' 188 | '>>crcor(u(:,1),u(:,2),dt) ' 189 | '>>axis([-1000 1000 -1000 5000] ']; 190 | 191 | ssdisp(figNumber,str); 192 | 193 | [Tau,Pxy]=crcor(u(:,1),u(:,2),dt); 194 | plot(Tau,Pxy) 195 | title('Linear Cross Correlation') 196 | xlabel('Tau') 197 | ylabel('Linear Cross Correlation') 198 | grid 199 | axis([-1000 1000 -1000 5000]) 200 | drawnow 201 | 202 | zoom on 203 | xtot=[]; 204 | for i=1:numdat 205 | [x,v,a]=ssim(m,d,k,[u(:,i) zeros(length(u(:,1)),1)],t); 206 | xtot=[xtot x(:,1)]; 207 | end 208 | 209 | 210 | if sspause(figNumber),return;end; 211 | 212 | str=... 213 | ['The responses of the first mass to these excitations ' 214 | 'can be obtained using the function SSIM. ' 215 | '>>for i=1:5 ' 216 | '>> [x,v,a]=ssim(m,d,k,[u(:,i) zeros(length(u(:,1)),1)],t); ' 217 | '>> y=[y x(:,1)]; ' 218 | '>>end ']; 219 | 220 | ssdisp(figNumber,str); 221 | y=xtot; 222 | plot(t,y) 223 | grid on 224 | xlabel('Time') 225 | ylabel('Response') 226 | title('Response of a 2DOF system to a random excitation') 227 | [Freq,Txf]=tfest(y,u,t); 228 | 229 | if sspause(figNumber),return;end; 230 | 231 | 232 | str=... 233 | ['Unlike the forcing functions, the auto correlation of' 234 | 'the response is not zero everywhere other than tau=0.' 235 | 'The average auto correlation shows that the signals ' 236 | 'are not completely random. ' 237 | '>>crcor(y,y,t) ']; 238 | 239 | crcor(y,y,t) 240 | ssdisp(figNumber,str); 241 | chil=get(gcf,'children'); 242 | for i=1:length(chil) 243 | if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 244 | delete(chil(i)) 245 | i=length(chil); 246 | drawnow 247 | break 248 | end 249 | end 250 | 251 | if sspause(figNumber),return;end; 252 | 253 | str=... 254 | ['Looking at the average power spectral density using CRSD ' 255 | 'demonstrates that the response does indeed contain significant' 256 | 'energy at two distinct frequencies. ' 257 | '>>crsd(y,y,t) ']; 258 | 259 | ssdisp(figNumber,str); 260 | crsd(y,y,t) 261 | title('Auto Spectrum Density') 262 | chil=get(gcf,'children'); 263 | for i=1:length(chil) 264 | if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 265 | delete(chil(i)) 266 | i=length(chil); 267 | drawnow 268 | break 269 | end 270 | end 271 | if sspause(figNumber),return;end; 272 | 273 | str=... 274 | ['An estimate of the transfer function can be obtained using the' 275 | 'function TFEST. You can zoom in on the plot by clicking on a ' 276 | 'point in the plot and zoom out by using the right mouse button' 277 | '(shift click on the Mac). You can also drag a box around an ' 278 | 'area you''d like to zoom into. Double clicking brings you back ' 279 | 'to the full view. TFEST will automatically average the data ' 280 | 'transfer for you by default. You can specify no averaging and ' 281 | 'modify the default zero padding as well. ' 282 | '>>tfest(y,u,t); ']; 283 | 284 | ssdisp(figNumber,str); 285 | tfplot(Freq,Txf) 286 | axis([0 2.5 -240 240]) 287 | %pause 288 | % chil=get(gcf,'children'); 289 | % for i=1:length(chil) 290 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 291 | % delete(chil(i)) 292 | % i=length(chil); 293 | % drawnow 294 | % break 295 | % end 296 | % end 297 | if sspause(figNumber),return;end; 298 | 299 | str=... 300 | ['The actual estimate can be obtained in vector form by' 301 | 'using left hand side arguments. The results may then ' 302 | 'be plotted using TFPLOT. TFPLOT gives you much more ' 303 | 'control over the way the transfer function estimate ' 304 | 'is displayed. For instance, let''s look at the ' 305 | 'frequency range near the peaks... ' 306 | '>>[Freq,Txf]=tfest(y,u,t); ' 307 | '>>tfplot(Freq,Txf,0,.4) ']; 308 | 309 | ssdisp(figNumber,str); 310 | tfplot(Freq,Txf,0,.6) 311 | % chil=get(gcf,'children'); 312 | % for i=1:length(chil) 313 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 314 | % delete(chil(i)) 315 | % i=length(chil); 316 | % drawnow 317 | % break 318 | % end 319 | % end 320 | if sspause(figNumber),return;end; 321 | 322 | str=... 323 | ['or perhaps the Nyquist plot... ' 324 | '>>tfplot(Freq,Txf,0,.6,5) ']; 325 | 326 | ssdisp(figNumber,str); 327 | tfplot(Freq,Txf,0,.6,5) 328 | % chil=get(gcf,'children'); 329 | % for i=1:length(chil) 330 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 331 | % delete(chil(i)) 332 | % i=length(chil); 333 | % drawnow 334 | % break 335 | % end 336 | % end 337 | if sspause(figNumber),return;end; 338 | tic 339 | tfplot(Freq,Txf,0,.6) 340 | % chil=get(gcf,'children'); 341 | % for i=1:length(chil) 342 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 343 | % delete(chil(i)) 344 | % i=length(chil); 345 | % drawnow 346 | % break 347 | % end 348 | % end 349 | 350 | str=... 351 | ['These results do not look very good, though. This is' 352 | 'likely the results of leakage (using incomplete data ' 353 | 'cycles). We can improve the results by applying a ' 354 | 'window of some form, for example a Hanning (von ' 355 | 'Hanning) window. ' 356 | '>>plot(t,hannwin(u)) ' 357 | '>>plot(t,hannwin(y)) ']; 358 | 359 | ssdisp(figNumber,str); 360 | drawnow 361 | uh=hannwin(u); 362 | yh=hannwin(y); 363 | %pause(5-toc) 364 | subplot(2,1,1) 365 | plot(t,uh) 366 | grid on 367 | xlabel('Time') 368 | %ylabel('Windowed Forcing Function') 369 | title('Windowed Forcing Function') 370 | subplot(2,1,2) 371 | plot(t,yh) 372 | grid on 373 | xlabel('Time') 374 | %ylabel('Windowed Response') 375 | title('Windowed Response') 376 | drawnow 377 | [Freq,Txf]=tfest(hannwin(y),hannwin(u),t); 378 | if sspause(figNumber),return;end; 379 | 380 | str=... 381 | ['After applying a von Hanning window to the forcing ' 382 | 'function and to the response, the transfer function' 383 | 'estimate looks much better. ' 384 | '>>[Freq,Txf]=tfest(hannwin(y),hannwin(u),t); ' 385 | '>>tfplot(Freq,Txf,0,.6) ']; 386 | 387 | ssdisp(figNumber,str); 388 | 389 | tfplot(Freq,Txf,0,.6) 390 | % chil=get(gcf,'children'); 391 | % for i=1:length(chil) 392 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 393 | % delete(chil(i)) 394 | % i=length(chil); 395 | % drawnow 396 | % break 397 | % end 398 | % end 399 | 400 | if sspause(figNumber),return;end; 401 | 402 | str=... 403 | ['The quality of the transfer function can be ' 404 | 'verified by plotting the coherance function ' 405 | 'using COH. ' 406 | '>>coh(y,u,t) ']; 407 | 408 | ssdisp(figNumber,str); 409 | 410 | subplot(1,1,1) 411 | coh(hannwin(y),hannwin(u),t) 412 | axis([0 .6 0 1]) 413 | 414 | % chil=get(gcf,'children'); 415 | % for i=1:length(chil) 416 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 417 | % delete(chil(i)) 418 | % i=length(chil); 419 | % drawnow 420 | % break 421 | % end 422 | % end 423 | 424 | if sspause(figNumber),return;end; 425 | 426 | str=... 427 | ['These results can be compared to the "true" transfer ' 428 | 'obtained earlier by using TFPLOT to plot them over each other.' 429 | '>>tfplot(Freq,[Txf, Recep],0,.5) ']; 430 | 431 | ssdisp(figNumber,str); 432 | 433 | [Freq,Recep,Mobil,Inert]=sostf(m,d,k,1,1,Freq); 434 | 435 | tfplot(Freq,[Txf, Recep],0,.5) 436 | % chil=get(gcf,'children'); 437 | % for i=1:length(chil) 438 | % if strcmp(get(chil(i),'type'),'axes') & chil(i)~=gca 439 | % delete(chil(i)) 440 | % i=length(chil); 441 | % drawnow 442 | % break 443 | % end 444 | % end 445 | 446 | -------------------------------------------------------------------------------- /vtblogo.m: -------------------------------------------------------------------------------- 1 | cura=gca; 2 | axes('units','normal','position',[0 0 .4 .05],'visible','off') 3 | h=text(0.0,0.0,'The Vibration Toolbox','color',[1 1 0],... 4 | 'units','normalized','fontsize',10,... 5 | 'fontname','times','fontangle','ital','verticalalignment','bottom',... 6 | 'horizontalalignment','left','visible','on'); 7 | set(gcf,'currentaxes',cura); 8 | -------------------------------------------------------------------------------- /vtdem1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/vtdem1.mat -------------------------------------------------------------------------------- /vtestingdata1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibration-Testing/Vibration-Testing-Matlab/02093825310dea7c299253edfc1ef9977d58fa25/vtestingdata1.mat --------------------------------------------------------------------------------