function [StrideFrequency, QualityInd, PeakWidth, MeanNormalizedPeakWidth] = StrideFrequencyRispen(AccXYZ, F)

%% Description
% Estimate stride frequency in 3d accelerometer data, using multi-taper and
% pwelch spectral densities
%
% Input: 
%   AccXYZ: a three-dimensional time series with trunk accelerations (is
%   for error)
%   FS: the sample frequency of the time series
%   StrideFreqGuess: a first guess of the stride frequency
%
% Output:
%   StrideFrequency: the estimated stride frequency
%   QualityInd: a number (0-1, 0=no confidence, 1=fully confident) indicating how much confidence we have in the
%   estimated stride frequency

%% Copyright
%     COPYRIGHT (c) 2012 Sietse Rispens, VU University Amsterdam
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
% 
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
% 
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.

%% Author
%  Sietse Rispens

%% History
%  February 2013, version 1.1, adapted from StrideFrequencyFrom3dAcc
%% Additional information 
% Stride frequency was estimated from the median of the modal
% frequencies (half the modal frequency for VT and AP) for all three
% directions. Whenever the median of the three frequencies fell
% outside the range 0.6–1.2 Hz, it was replaced by one of the other
% two frequencies, if available, within this range. Finally, if all modal
% frequencies were within 10% of an integer multiple of the resulting
% frequency, it was replaced by the mean of the three associated base
% frequencies. frequencies.

%% Check input
if size(AccXYZ,2) ~= 3
    error('AccXYZ must be 3-d time series, i.e. contain 3 columns');
elseif size(AccXYZ,1) < 10*F
    error('AccXYZ must be at least ten seconds long');
end


%% Get PSD (Power Spectral Density)
if numel(F) == 1, % Calculate the PSD from time series AccXYZ, F is the sample frequency
    AccFilt = detrend(AccXYZ,'constant');  % Detrend data to get rid of DC component in most of the specific windows
    LenPSD = 10*F;
    for i=1:3,
        [P1,Fwf] = pwelch(AccFilt(:,i),hamming(LenPSD),[],LenPSD,F);
        [P2,Fwf] = pwelch(AccFilt(end:-1:1,i),hamming(LenPSD),[],LenPSD,F);
        Pwf(:,i) = (P1+P2)/2;
    end
elseif numel(F)==size(AccXYZ,1), % F are the frequencies of the power spectrum AccXYZ
    Fwf = F;
    Pwf = AccXYZ;
end
Pwf(:,4) = sum(Pwf,2); % if input = F 
    

%% Estimate stride frequency
% set parameters
HarmNr = [2 1 2]; % AP / V --> Biphasic
CommonRange = [0.6 1.2]; % Whenever the median of the three frequencies fell outside the range 0.6–1.2 Hz, it was replaced by one of the other two frequencies,
% Get modal frequencies and the 'mean freq. of the peak'
for i=1:4,
    MF1I = find([zeros(5,1);Pwf(6:end,i)]==max([zeros(5,1);Pwf(6:end,i)]),1);
    MF1 = Fwf(MF1I,1);
    IndAround = Fwf>=MF1*0.5 & Fwf<=MF1*1.5;
    MeanAround = mean(Pwf(IndAround,i));
    PeakBeginI = find(IndAround & Fwf<MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'last');
    PeakEndI = find(IndAround & Fwf>MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'first');
    if isempty(PeakBeginI), PeakBeginI = find(IndAround,1,'first'); end
    if isempty(PeakEndI), PeakEndI = find(IndAround,1,'last'); end
    ModalF(i) = sum(Fwf(PeakBeginI:PeakEndI,1).*Pwf(PeakBeginI:PeakEndI,i))/sum(Pwf(PeakBeginI:PeakEndI,i));
    if i==4
        HarmNr(4) = HarmNr(find(Pwf(MF1I,1:3)==max(Pwf(MF1I,1:3)),1));
    end
end
% Get stride frequency and quality indicator from modal frequencies
StrFreqFirstGuesses = ModalF./HarmNr;
StdOverMean = std(StrFreqFirstGuesses)/mean(StrFreqFirstGuesses);
StrideFrequency1 = median(StrFreqFirstGuesses(1:3));
if StrideFrequency1 > CommonRange(2) && min(StrFreqFirstGuesses(1:3)) < CommonRange(2) && min(StrFreqFirstGuesses(1:3)) > CommonRange(1)
    StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
if StrideFrequency1 < CommonRange(1) && max(StrFreqFirstGuesses(1:3)) > CommonRange(1) && max(StrFreqFirstGuesses(1:3)) < CommonRange(2)
    StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
HarmGuess = ModalF/StrideFrequency1;
StdHarmGuessRoundErr = std(HarmGuess - round(HarmGuess));
if StdOverMean < 0.1
    QI1 = 1;
    StrideFrequency = mean(StrFreqFirstGuesses);
else
    if StdHarmGuessRoundErr < 0.1 && all(round(HarmGuess) >= 1)
        QI1 = 0.5;
        StrideFrequency = mean(ModalF./round(HarmGuess));
    else
        QI1 = 0;
        StrideFrequency = StrideFrequency1;
    end
end
if nargout >= 2
    QualityInd = QI1;
end

if nargout >= 3
    N_Harm = 20;
    PeakWidth = nan(1,3);
    if nargout >= 4
        MeanNormalizedPeakWidth = nan(1,3);
    end
    %% Get (mean) widths of harmonic peaks
    for i=1:3,
        WidthHarm = nan(1,N_Harm);
        PowerHarm  = nan(1,N_Harm);
        for HarmonicNr = 1:N_Harm,
            FreqRangeIndices = ...
                Fwf >= StrideFrequency*(HarmonicNr-0.5) ...
                & Fwf <= StrideFrequency*(HarmonicNr+0.5);
            PeakPower = sum(Pwf(FreqRangeIndices,i));
            PeakMean = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices))/PeakPower;
            PeakMeanSquare = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices).^2)/PeakPower;
            WidthHarm(HarmonicNr) = sqrt(PeakMeanSquare-PeakMean.^2);
            PowerHarm(HarmonicNr) = PeakPower;
        end
        PeakWidth(i) = WidthHarm(HarmNr(i)); % Take the 1st or 2nd harmonic width as original measure
        if nargout >= 4
            MeanNormalizedPeakWidth(i) = sum(WidthHarm./(1:N_Harm).*PowerHarm)/sum(PowerHarm);
        end
    end
end

if nargout == 0
    IXplotw = Fwf<10;
    figure();
    for i=1:3,
        subplot(2,2,i);
        plot(Fwf(IXplotw,1),Pwf(IXplotw,i));
    end
    subplot(2,2,4);
    plot(Fwf(IXplotw,1),Pwf(IXplotw,1:3));
end




