function varargout = spectral(x,dt,win,Nb,P,Wn,ftype,n)
% Spectrum using periodogram method
%
% USAGE:
%   q = spectral(x,dt,win,Nb,P,Wn,ftype,n)
%   [psdf,f] = spectral(x,dt,win,Nb,P,Wn,ftype,n)
%   [psdf,psdfc,f] = spectral(x,dt,win,Nb,P,Wn,ftype,n)
%
% DESCRIPTION:
%   Calculates the spectrum for x
%   using the periodogram method 
%   If a window other than boxcar is used
%   than the method is refered to as modified
%   periodogram method.
%   The confidence intervals are calculated
%   using the inverse of chi-square CDF.
%   Also includes a filtering option using the 
%   butterworth filter to see the effect of the 
%   filter on the spectrum
%
% INPUT VARIABLES:
%   x - Time series, [vector]
%   dt - Sampling Rate, [scalar]
%   win - Window, one of: 
%       'hanning', 'hamming', 'boxcar'
%   Nb - Band Averaging, number of bands to average
%   P - Probability for confidence intervals
%   Wn - Cut-Off frequencies, used for filtering
%   ftype - Type of filter, 'high', 'low' or 'stop'
%   ncb - Number of coefficients to use in
%       the Butterworth filter
%
% OUTPUT VARIABLES:
%   q - structure with the following fields:
%       xp - detrended x
%       f = Frequencies
%       T - Periods
%       m - Magnitude
%       a - Amplitude
%       s - Power spectrum, Sxx(win), [Power]
%       psdw - Power Spectral Density, Pxx(win), [Power/rad/sample]
%       psdf - Power Spectral Density, Pxx(f), [Power/sample-freq]
%       psdT - Power Spectral Density, Pxx(T), [Power*time-unit]
%       conf - Upper and Lower Confidence Interval multiplication 
%               factors using chi-squared approach 
%
%   See also SPECWELCH
%
%Copy-Left, Alejandro Sanchez

if nargin<2
    dt = 1;    
end
if nargin<3
    win = 'boxcar';    
end
if nargin<4 || isempty(Nb)
    Nb = 1; 
end
if nargin<5 || isempty(P)
    P = 0.95;
end
if (nargin<7) && (nargin>5)
    ftype = 'low';
end
if (nargin<8) && (nargin>5)
    n = 5;
end

if nargin==0
    spectraldemo
    return
end

x = x(:);
isf = isfinite(x);

if nargout==0
    figure('Position',[624, 74, 666, 1018])
    t = dt*(0:(length(x)-1));
    subplot(4,1,1)
    plot(t,x,'b')
    hold on
    t = t(isf);
end

x = x(isf);
mx = mean(x);
x = detrend(x); %also removes mean
N = sum(isf);

fn = (1/(2*dt)); %Nyquist frequency
nfft = max(256, 2^(nextpow2(N)));
f = (1:nfft/2)/(nfft/2)*fn; %frequencies, Note: starts from 1
f = f(:); %Frequencies

%Makes a window
try
    w = eval([win,'(',num2str(N),')']);
catch
    error('Invalid Window')
end

%Butterworth Filter
if nargin>5
    [b1,b2] = butter(n,Wn*2*dt,ftype); %Wn/nyquist = Wn*2*dt
    x = filtfilt(b1,b2,x);
%     q.xf = x;
end

if nargout==0
    plot(t,x+mx,'r')
    axis tight
    set(gca,'xlim',[t(1),t(end)])
end

% q.xp = x; %save before applying window
x = w.*x; %apply window

% Evaluate the window normalization constant
% A 1/nfft factor has been omitted since it will cancel below
R = w'*w;  % compute sum of squares of window

%Compute Fourier Coefficients
%Pad with zeros to length nfft, makes fft much faster
%and increases frequency resolution, df=1/N/dt;
c = fft(x,nfft); 

%The magnitude is multiplied by one of the following constants
%to compensate for the lost energy when the window is applied
%the values are taken from Emery & Thomson pag. 446-448
%In the case of the boxcar window the constant is 1 and is
%therefore ommitted
if strcmpi(win,'hanning')
    K = 0.5*sqrt(8/3);
elseif strcmpi(win,'hamming')
    K = 0.5*sqrt(5/2);
elseif strcmpi(win,'boxcar')
    K = 1;
else
    error('Invalid Window')
end

%Magnitude
m = abs(c(2:nfft/2+1)); %skip first coefficient which is the mean

%Do band averaging now
if Nb>1
    f = bandaverage(f,Nb);
    m = bandaverage(m,Nb);
end
T = 1./f; %Periods

%Amplitude
a = K*m.*2./R;

%Sxx(win), Angular-Frequency Power Spectrum, [Power]
s = 2*(m.^2)./R; 

%Correction for one-sided spectrum
% s(2:end-1) = 2*s(2:end-1);

%Pxx(win), Amgular-Frequency Spectrum
%Power Spectrum Density (PSD), [Power/rad/sample]
psdw = s/2/pi;

%Pxx(f), Frequency Spectrum
%Power Spectrum Density (PSD), [Power/sample-freq]
psdf = s*dt;

%Pxx(T), Period Spectrum
%Power Spectrum Density (PSD), [Power*time-unit]
psdT = 2*pi*psdw./T.^2; 

%Finally Calculate phase
ph = unwrap(angle(c(1:fix(N/2))));

%Confidence Intervals using chi-squared approach
v = 2*Nb;
alpha2 = (1-P)/2;
conf = v./chi2inv([alpha2,1-alpha2],v);

%Collect variables
switch nargout
    case 0
        %do nothing
    case 1
        varargout{1}.f = f;
        varargout{1}.T = T;
        varargout{1}.m = m;
        varargout{1}.a = a;
        varargout{1}.s = s;
        varargout{1}.phase = ph;
        varargout{1}.psdw = psdw;
        varargout{1}.psdf = psdf;
        varargout{1}.psdT = psdT;
        varargout{1}.conf = conf;
    case 2
        varargout{1} = psdf;
        varargout{2} = f;
    case 3
        varargout{1} = psdf;
        varargout{2} = conf;
        varargout{3} = f;
    otherwise
        error('Invalid number of output variables')
end %switch

%Plotting
if nargout==0
    subplot(4,1,2)
    semilogx(T,a)
    set(gca,'xlim',[T(end),T(1)])
    set(gca,'xticklabel',get(gca,'xtick'))
    xlabel('Period')
    ylabel('Amplitude')
    grid on
    
    subplot(4,1,3)
    loglog(T,psdT)
    hold on
    loglog(T,psdT*conf,'--r')
    axis tight
    set(gca,'xticklabel',get(gca,'xtick'))
    xlabel('Period')
    ylabel('PSD')
    grid on
   
    %Filter or window
    subplot(4,1,4)
    if exist('Wn','var')
        H = freqz(b1,b2,f*pi*2*dt);
        semilogx(T,abs(H),'b');
        axis tight
        set(gca,'xticklabel',get(gca,'xtick'))
        xlabel('Period')
        ylabel('Filter Response')
    else
        plot(w)
        ylabel('window')
        set(gca,'xticklabel',get(gca,'xtick'))
        axis tight
%         plot(ph)
%         xlabel('Period')
    end
end

return
%----------------------------------------------------
function yy = bandaverage(y,Nb)
%Does the band averaging
Len = length(y);
yc = conv(ones(Nb,1)/Nb,y);
yy = wkeep(yc,Len);
return

%-------------------------------------------
function spectraldemo
dt = 1/100;
t=0:dt:200;
sr = 2*randn(size(t)); %white noise
s1 = 4*sin(2*pi*t/1);
s2 = 2*sin(2*pi*t/4);
s3 = 1*sin(t*2*pi/10);
s4 = 3*sin(t*2*pi/20);
s5 = -0.05*t;
s0 = 5;
x = s0 + s1 + s2 + s3 + s4 + s5 + sr;
x(1000:6000) = NaN;
Wn = 6;
ftype = 'low';
win = 'hanning';
Nb = 1;
P = 0.95;
n = 5;
spectral(x,dt,win,Nb,P,Wn,ftype,n)

return

