%function  [s, c, ph, ci, phi] = cmtm(x,y,dt,NW,qbias,confn,qplot);
%
%Multi-taper method coherence using adaptive weighting and correcting 
%for the bias inherent to coherence estimates.  The 95% coherence
%confidence level is computed by cohconf.m.  In addition, a built-in
%Monte Carlo estimation procedure is available to estimate phase 95%
%confidence limits. 
%
% Inputs:
%         x     - Input data vector 1.  
%         y     - Input data vector 2.  
%         dt    - Sampling interval (default 1) 
%         NW    - Number of windows to use (default 8) 
%         qbias - Correct coherence estimate for bias (yes, 1)  (no, 0, default).
%         confn - Number of iterations to use in estimating phase uncertainty using a Monte Carlo
%                 method. (default 0)
%         qplot - Plot the results, (yes, 1), (No, 0, default).  The upper tickmarks indicate the
%                 bandwidth of the coherence and phase estimates.  
%
% Outputs:
%         s       - frequency
%         c       - coherence
%         ph      - phase
%         ci      - 95% coherence confidence level
%         phi     - 95% phase confidence interval, bias corrected
%                   (add and subtract phi from ph).
%
%
%required files: cohconf.m, cohbias.m, cohbias.mat, Matlab signal processing toolbox.
%
%Peter Huybers
%MIT, 2003
%phuyber@mit.edu

function [s, c, ph, ci, phi] = cmtm(x,y,dt,NW,qbias,confn,qplot);

%check input
if nargin<2, help cmtm; return; end;
if nargin<7, qplot=0;  end;
if nargin<6, confn=0;  end;
if nargin<5, qbias=0;  end;
if nargin<4, NW=8;     end;
if length(NW)==0, NW=8;end;
if nargin<3, dt=1;     end;
if length(dt)==0, dt=1;end;


if NW<1.5, disp('Warning: NW must be greater or equal to 1.5'); return; end;
if nargin>4, 
	  disp('-------------------------');
disp(['Number of windows: ',num2str(NW)]);
if qbias==1, disp('Bias correction:   On');
else,        disp('Bias correction:   Off'); end;
disp(['Confidence Itera.: ',num2str(confn)]);
if qplot==1, disp('Plotting:          On');
else,        disp('Plotting:          Off'); end;
disp('-------------------------');
end;

x=x(:)-mean(x); 
y=y(:)-mean(y);
if length(x)~=length(y), disp('Warning: the lengths of x and y must be equal.'); return; end;

%define some parameters
N   = length(x);
k   = min(round(2*NW),N); 
k   = max(k-1,1);
s   = (0:1/(N*dt):1/dt-1/(N*dt))';
pls=2:(N+1)/2+1;
v   = (2*NW-1); %approximate degrees of freedom

if rem(length(y),2)==1; pls=pls(1:end-1); end;

%Compute the discrete prolate spheroidal sequences, requires the spectral analysis toolbox.
[E,V]=dpss(N,NW,k);

%Compute the windowed DFTs.
fkx=fft(E(:,1:k).*x(:,ones(1,k)),N);
fky=fft(E(:,1:k).*y(:,ones(1,k)),N);

Pkx=abs(fkx).^2;
Pky=abs(fky).^2;

%Itteration to determine adaptive weights:    
for i1=1:2,
  if i1==1,   vari=x'*x/N; Pk=Pkx; end;
  if i1==2,   vari=y'*y/N; Pk=Pky; end;
  P    = (Pk(:,1)+Pk(:,2))/2;   % initial spectrum estimate
  Ptemp= zeros(N,1);
  P1   = zeros(N,1);
  tol  = .0005*vari/N;          % usually within 'tol'erance in about three iterations, see equations from [2] (P&W pp 368-370).   
  a    = vari*(1-V);
  while sum(abs(P-P1)/N)>tol            
    b=(P*ones(1,k))./(P*V'+ones(N,1)*a'); % weights
    wk=(b.^2).*(ones(N,1)*V');            % new spectral estimate
    P1=(sum(wk'.*Pk')./ sum(wk'))';
    Ptemp=P1; P1=P; P=Ptemp;              % swap P and P1
  end
  if i1==1, 
    fkx=sqrt(k)*sqrt(wk).*fkx./repmat(sum(sqrt(wk'))',1,k);
    Fx=P;  %Power density spectral estimate of x
  end;
  if i1==2, 
    fky=sqrt(k)*sqrt(wk).*fky./repmat(sum(sqrt(wk'))',1,k);
    Fy=P;  %Power density spectral estimate of y
  end;
end;
%As a check, the quantity sum(abs(fkx(pls,:))'.^2) is the same as Fx and
%the spectral estimate from pmtmPH.

%Compute coherence
Cxy= sum([fkx.*conj(fky)]');
ph = angle(Cxy)*180/pi;
c  = abs(Cxy)./sqrt(sum(abs(fkx').^2).*sum(abs(fky').^2));

%correct for the bias of the estimate
if qbias==1,
  c=cohbias(v,c)'; 
end;

%Phase uncertainty estimates via Monte Carlo analysis. 
if confn>1,
  cb=cohbias(v,c)';
for iter=1:confn;
  if rem(iter,10)==0, disp(['phase confidence iteration: ',num2str(iter)]); end;
  fx=fft(randn(size(x))+1);
  fx=fx/sum(abs(fx));
  fy=fft(randn(size(y))+1); 
  fy=fy/sum(abs(fy));
  ys =real(ifft(fy.*sqrt(1-cb'.^2)));    
  ys =ys+real(ifft(fx.*cb')); 
  xs =real(ifft(fx));
  [si, ciph(iter,:), phi(iter,:)]=cmtm(xs,ys,dt,NW);
end;
  pl=round(.975*iter);     %sorting and averaging to determine confidence levels.
  phi=sort(phi);  
  phi=[phi(pl,:); -phi(iter-pl+1,:)];
  phi=mean(phi);
  phi=conv(phi(1:end),[1 1 1]/3);  
  phi=phi(2:end-1);
else,
  phi=zeros(size(pls)); 
end;
  
%Cut to one-sided funtions
c = c(pls);
s = s(pls)';
ph=ph(pls);
phl=ph-phi;
phu=ph+phi;

%Coherence confidence level
ci=cohconf(v,.95);  %not corrected for bias, this is conservative.
ci=ci*ones(size(c));

%plotting
if qplot==1,
  %coherence
  figure(gcf); clf;
  subplot(211); hold on;
  plot(s,c);
  h=ylabel('coherence');
  h=xlabel('frequency');
  plot(s,ci,'k--');
  pl=find(c>ci(1));
  title(['mean is ',num2str(mean(c),2),'   ',num2str(100*length(pl)/length(c),2),'% of estimates above 95% confidence level']);
  axis tight; h=axis; axis([h(1:2) 0 1.025]);
  w  = NW/(dt*N);   %half-bandwidth of the dpss
  plot([s(1) h(2)],[1.02 1.02],'k');
  for ds=min(s):2*w:max(s);
    plot([ds ds],[.98 1.02],'k');
  end;
  
  %phase
  subplot(212); hold on;
  plot(s,ph);
  if confn>0,
    col=[.9 .9 .9];
    h=fill([s(1) s(1:end) fliplr([s(1:end) s(end)])],[phu(1) phl fliplr([phu phl(end)])],col);
    set(h,'edgecolor',col);

    pl=find(phu<=180); phu(pl)=-180;
    pl=find(phu> 180); phu(pl)=phu(pl)-360;
    phlt=-180*ones(size(phl));
    h=fill([s(1) s(1:end) fliplr([s(1:end) s(end)])],[phu(1) phlt fliplr([phu phlt(end)])],col);
    set(h,'edgecolor',col);

    pl=find(phl>=-180); phl(pl)=180;
    pl=find(phl< -180); phl(pl)=phl(pl)+360;
    phut=180*ones(size(phl));
    h=fill([s(1) s(1:end) fliplr([s(1:end) s(end)])],[phut(1) phl fliplr([phut phl(end)])],col);    
    set(h,'edgecolor',col);        
  end;
  h=plot(s,ph); 
  plot(s,zeros(size(s)),'k--');
  axis tight; h=axis; axis([h(1:2) -180 180]);
  h=xlabel('frequency'); 
  h=ylabel('phase'); 
end;



