% SFtest perfomes a Spectral F-Test on PSDs.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: SFtest performes a Spectral F-Test on two input PSD objects.
%              The null hypothesis H0 (the two PSDs belong to the same
%              statistical distribution) is rejected at the confidence
%              level for the alternative hypotheis H1 (the two PSDs belong
%              to different statistical distributions) if the test
%              statistic falls in the critical region.
%              SFtest uses utils.math.Ftest which does the test at each
%              frequency bin.
%
% VERSION:     $Id: SFtest.m,v 1.3 2011/03/07 17:38:05 congedo Exp $
%
% HISTORY:     18-02-2011 G. Congedo
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function test = SFtest(X,Y,alpha,showPlots)

  % Assume a two-tailed test
  twoTailed = 1;

  % Extract the degree of freedom
  dofX = X.getdof.y;
  dofY = Y.getdof.y;
  
  % Ratio of the two spectra: this test statistic is F-distributed
  F = X/Y;
  F.setYunits('');
  F.setName('F statistic');
  
  n = numel(F.y);
  
  % Interquartile range
  Fy = sort(F.y);
  m = median(Fy);
  q1 = median(Fy(Fy<=m));
  q3 = median(Fy(Fy>=m));
  iqr = q3 - q1;
  
  % Freedman–Diaconis rule
  binSz = 2*iqr*n^(-1/3);
  nBin = round((max(Fy)-min(Fy))/binSz);
  
  % Sample PDF
  samplePDF = hist(F,plist('N',nBin,'norm',1));
  samplePDF.setName('sample PDF');
  
  % Sample PDF moments
%   sampleK = utils.math.Kurt(samplePDF.x);
%   sampleS = utils.math.Skew(samplePDF.x);
  
  % Theor PDF
  theorPDF = copy(samplePDF,1);
  theorPDF.setY(Fpdf(samplePDF.x,dofX,dofY));
  theorPDF.setName('theor. PDF');
  
  % Theor PDF moments
%   theorK = utils.math.Kurt(samplePDF.x);
%   theorS = utils.math.Skew(samplePDF.x);
  
  % Plot PDFs
  if showPlots
    iplot(samplePDF,theorPDF);
    set(get(gca,'YLabel'),'String','PDF')
    set(get(gca,'XLabel'),'String','F statistic')
  end
  
  % Perform test on the hypothesis that both distributions should be
  % chi2-distributed or, equivalently, that the ratio of the two spectra
  % should be F-distributed. The comparison is actually done in chi2 sense.
  sampleHIST = hist(F,plist('N',nBin));
  ix = sampleHIST.y>=5;
  C = sum(sampleHIST.y)*mean(diff(sampleHIST.x));
  NN = sampleHIST.y(ix);
  nn = C*theorPDF.y(ix);
  r = (NN-nn).^2./nn;
  chi2 = sum(r);
  dof = numel(NN) - 1;
  Y2 = dof + sqrt(2*dof/(2*dof+sum(1./nn)))*(chi2-dof);
  critValue(1) = utils.math.Chi2inv(alpha/2,dof);
  critValue(2) = utils.math.Chi2inv(1-alpha/2,dof);
  
  % Perform the test on PDFs
  Chi2test = Y2<critValue(1) | Y2>critValue(2);
  
%   % Sample CDF
%   samplePDF = hist(F,plist('N',1000));
%   sampleCDF = copy(samplePDF,1);
%   sampleCDF.setY(cumsum(samplePDF.y)/sum(samplePDF.y));
%   sampleCDF.setName('sample CDF');
%   
%   % Theor CDF
%   theorCDF = copy(samplePDF,1);
%   theorCDF.setY(Fcdf(samplePDF.x,dofX,dofY));
%   theorCDF.setName('theoretical CDF');
%   
%   % Plot CDFs
%   iplot(sampleCDF,theorCDF);
%   set(get(gca,'YLabel'),'String','CDF')
%   set(get(gca,'XLabel'),'String','F statistic')
   
  % Critical values
  [test,critValue,pValue] = utils.math.Ftest(F.y,dofX,dofY,alpha,twoTailed);
  
  % Build AOs for critical values
%   if twoTailed
    critValueLB = ao(plist('xvals',X.x,'yvals',repmat(critValue(1),size(X.x)),...
      'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','critical values'));
    critValueUB = ao(plist('xvals',X.x,'yvals',repmat(critValue(2),size(X.x)),...
      'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','critical values'));
%   else
%     critValue = ao(plist('xvals',X.x,'yvals',repmat(critValue,size(X.x)),...
%       'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','critical values'));
%   end
    
%   % Build AOs for p-values and confidence levels
%   pValue = ao(plist('xvals',X.x,'yvals',pValue,...
%     'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','p-values'));
% %   pValue.setDy(pValueDy);
%   
%   if twoTailed
%     confLevelUB = ao(plist('xvals',X.x,'yvals',repmat(1-alpha/2/numel(F.y),size(X.x)),...
%       'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','confidence level'));
%     confLevelLB = ao(plist('xvals',X.x,'yvals',repmat(alpha/2/numel(F.y),size(X.x)),...
%       'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','confidence level'));
%   else
%     confLevel = ao(plist('xvals',X.x,'yvals',repmat(1-alpha/n,size(X.x)),...
%       'type','fsdata','fs',X.fs,'xunits',X.xunits,'name','confidence level'));
%   end
  
  % Rejection index
  ix = find(test);
  if ~isempty(ix)
    H1 = F.setXY(plist('x',F.x(ix),'y',F.y(ix)));
    H1.setDy([]);
    H1.setName('H0 rejected');
  end
  
  % Compute the number of sigmal corresponding to the confidence level
%   Ns = erfinv(1-alpha)*sqrt(2);
  
  % Make the test: H0 rejected?
%   if twoTailed
% %     test = any( (F.y-Ns.*F.dy)>critValueUB.y | (F.y+Ns.*F.dy)<critValueLB.y );
%     test = any( F.y>critValueUB.y | F.y<critValueLB.y );
%   else
% %     test = any( (F.y-Ns.*F.dy)>critValue.y );
%     test = any( F.y>critValue.y );
%   end
  
  % Perform the F-test on spectra
  Ftest = any(test);
  
  % Plot results
  pl = plist('yscales',{'All', 'log'},'autoerrors',0);
%   if twoTailed
  if showPlots
    if Ftest
      [hfig, hax, hli] = iplot(F,critValueLB,critValueUB,H1,pl);
      set(hli(4),'linestyle','none','marker','s','MarkerSize',10,'MarkerEdgeColor','r');
    else
      [hfig, hax, hli] = iplot(F,critValueLB,critValueUB,pl);
    end
    set(hli(2:3),'color','r');
%     h2 = iplot(pValue,confLevelLB,confLevelUB,pl);
%   else
%     if Ftest
%       [hfig, hax, hli] = iplot(F,critValue,H1,pl);
%       set(hli(3),'linestyle','none','marker','s','MarkerSize',10,'MarkerEdgeColor','r');
%     else
%       [hfig, hax, hli] = iplot(F,critValue,pl);
%     end
%     set(hli(2),'color','r');
% %     h2 = iplot(pValue,confLevel,pl);
%   end
    set(get(gca,'YLabel'),'String','F statistic')
  end
  
  % Output final result
  test = any(Chi2test | Ftest);
  
end

