Code covered by the BSD License  

Highlights from
Detrended Flucatuation Analysis (DFA) of Long-range temporal correlations

Detrended Flucatuation Analysis (DFA) of Long-range temporal correlations

by

 

25 Jan 2013 (Updated )

The DFA algorithm is a scaling analysis method used to estimate long-range temporal correlations.

nbt_doDFA(Signal, InfoObject, FitInterval, CalcInterval, DFA_Overlap, DFA_Plot, ChannelToPlot, res_logbin);
% [DFAobject,DFA_exp] = nbt_Scaling_DFA(DFAobject, Signal, InfoObject,
% FitInterval, CalcInterval, DFA_Overlap, DFA_Plot, ChannelToPlot, res_logbin);
% Detrended Fluctuation Analysis - Part of the NBT - toolbox
%% Input parameters
% DFAobject         : A DFAobject
% Signal            : The signal
% InfoObject        : The InfoObject that belongs to your signal.
% FitInterval(1)	: smallest time scale (window size) to include in power-law fit (in units of seconds!)
% FitInterval(2)	: largest time scale (window size) to include in power-law fit (in units of seconds!).
% CalcInterval(1) 	: minimum time-window size computed (in units of seconds!).
% CalcInterval(2) 	: maximum time-window size computed (in units of seconds!).
% DFA_Overlap		: amount of DFA_Overlap between windows (to obtain higher SNR for the fluctuation estimates).
% DFA_Plot		    : should either be an axeshandle or an integer > 0. If
% no plot should be produce use DFA_plot = 0;
% ChannelToPlot     : The channel you want to plot
% res_logbin        : number of bins pr decade (use 10)
%% output parameters
% DFAobject     : Return the DFAobject with updated information.
% DFA_exp		: The DFA power-law exponent.
%
% Example:
%
% References:
% % Method references...
%
% Peng et al., Mosaic organization of DNA nucleotides, Phys. rev. E (49), 1685-1688 (1994).
% or for a better description: Peng et al., Quantification of scaling exponents and crossover phenomena
% in nonstationary heartbeat time series, Chaos (5), 82-87 (1995).
%
%
% See also:
%   NBT_DFA,

%------------------------------------------------------------------------------------
% Originally created by Klaus Linkenkaer-Hansen (2001), see NBT website (http://www.nbtwiki.net) for current email address
% Improved code - Simon-Shlomo Poil (2008)
% Imported to NBT format. - Simon-Shlomo Poil (2009)
%------------------------------------------------------------------------------------



function [DFAobject,DFA_exp] = nbt_doDFA(Signal, InfoObject, FitInterval, CalcInterval, DFA_Overlap, DFA_Plot, ChannelToPlot, res_logbin);


DFAobject = nbt_DFA(size(Signal,2));
Signal = nbt_RemoveIntervals(Signal,InfoObject);

%% Get or set default parameters...
if (isempty(res_logbin))
    res_logbin = DFAobject.res_logbin;	% number of bins pr decade, i.e., the spacing of the logarithmic scale.
else
    DFAobject.res_logbin = res_logbin;
end

% get parameters from Signalobject
Fs = InfoObject.converted_sample_frequency;
DFAobject.Condition = InfoObject.condition;
% set parameters in DFAobject
DFAobject.FitInterval = FitInterval;
DFAobject.CalcInterval = CalcInterval;
DFAobject.Overlap = DFA_Overlap;

%Set information from InfoObject
DFAobject.ReseacherID = InfoObject.researcherID;
DFAobject.ProjectID = InfoObject.projectID;
DFAobject.SubjectID = InfoObject.subjectID;
DFAobject.Condition = InfoObject.condition;


%******************************************************************************************************************
%% Begin analysis
% Find DFA_x


% Defining window sizes to be log-linearly increasing.
d1 = floor(log10(CalcInterval(1)*Fs));
d2 = ceil(log10(CalcInterval(2)*Fs));
DFA_x_t = round(logspace(d1,d2,(d2-d1)*res_logbin));	% creates vector from 10^d1 to 10^d2 with N log-equidistant points.
DFA_x = DFA_x_t((CalcInterval(1)*Fs <= DFA_x_t & DFA_x_t <= CalcInterval(2)*Fs));	% Only include log-bins in the time range of interest!
DFAobject.DFA_x = DFA_x;


%% Do check of FitInterval
if ((DFA_x(1)/Fs)>FitInterval(1) || (DFA_x(end)/Fs)<FitInterval(2))
    disp([ DFA_x(1) DFA_x(end)]/Fs)
    error('Scaling_DFA:WrongCalcInterval','The CalcInterval is smaller than the FitInterval')
end

%% The DFA algorithm...
ChannelID = 1;

for ChannelID = 1:(size(Signal,2)) % loop over channels
    disp(ChannelID);
    if (isempty(DFAobject.DFA_y{GetChannelID,1}))
        DFA_y = nan(size(DFA_x,2),1);
        %% Do check of CalcInterval
         if (CalcInterval(2) > 0.1*length(Signal(:,GetChannelID))/Fs)
             display('The upper limit of CalcInterval is larger than the recommended 10% of the signal lenght')
         end
        
        y = Signal(:,GetChannelID)./mean(Signal(:,GetChannelID));
        %y = Signalobject(GetChannelID)-mean(Signalobject(GetChannelID),1);		% First we convert the time series to a series of fluctuations y(i) around the mean.
        y = y-mean(y);
        y = cumsum(y);         		% Integrate the above fluctuation time series ('y').
        for i = 1:size(DFA_x,2);				% 'DFA_x(i)' is the window size, which increases uniformly on a log10 scale!
            D = zeros(floor(size(y,1)/(DFA_x(i)*(1-DFA_Overlap))),1);		% initialize vector for temporarily storing the root-mean-square of each detrended window.
            tt = 0;
            for nn = 1:round(DFA_x(i)*(1-DFA_Overlap)):size(y,1)-DFA_x(i);	% we are going to detrend all windows in steps of 'n*(1-DFA_Overlap)'.
                tt=tt+1;
                D(tt) = (mean(fastdetrend(y(nn:nn+DFA_x(i))).^2,1))^(1/2);		% the square of the fluctuation around the local trend (of the window).
            end
            DFA_y(i) = mean(D(1:tt),1);						% the root-mean-square fluctuation of the integrated and detrended time series
        end  					  	       			% -- the F(n) in eq. (1) in Peng et al. 1995.
        DFAobject.DFA_y{GetChannelID,1} = DFA_y;
    end
end


%% Fitting power-law
for ChannelID = 1:(size(Signal,2)) % loop over channels
    DFA_y = DFAobject.DFA_y{GetChannelID,1};
    DFA_SmallTime_LogSample = min(find(DFA_x>=CalcInterval(1)*Fs));		%
    DFA_LargeTime_LogSample = max(find(DFA_x<=CalcInterval(2)*Fs));
    DFA_SmallTimeFit_LogSample = min(find(DFA_x>=FitInterval(1)*Fs));
    DFA_LargeTimeFit_LogSample = max(find(DFA_x<=FitInterval(2)*Fs));
    X = [ones(1,DFA_LargeTimeFit_LogSample-DFA_SmallTimeFit_LogSample+1)' log10(DFA_x(DFA_SmallTimeFit_LogSample:DFA_LargeTimeFit_LogSample))'];
    Y = log10(DFA_y(DFA_SmallTimeFit_LogSample:DFA_LargeTimeFit_LogSample));
    DFA_exp = X\Y; %least-square fit
    DFA_exp = DFA_exp(2);
    DFAobject.MarkerValues(GetChannelID,1) = DFA_exp;
end

DFAobject = nbt_UpdateBiomarkerInfo(DFAobject, InfoObject);


%% Plotting
if (DFA_Plot ~=0)
    if ~ishandle(DFA_Plot)		%see if any figure handle is set
        figure(DFA_Plot)
        DFA_Plot = axes;
    end
    ChannelID = ChannelToPlot;
    DFA_y = DFAobject.DFA_y{GetChannelID,1};
    disp('Plotting Channel')
    disp(GetChannelID)
    try
        axes(DFA_Plot)
    catch
        figure(DFA_Plot)
        axes(gca)
    end
    hold on
    plot(log10(DFA_x(DFA_SmallTimeFit_LogSample:DFA_LargeTimeFit_LogSample)/Fs),log10(DFA_y(DFA_SmallTimeFit_LogSample:DFA_LargeTimeFit_LogSample)),'ro')
    delete(findobj(DFA_Plot,'Type','Line','-not','Marker','o')) % delete any redundant lines
    LineHandle=lsline;
    try % delete any fits to the black points if they exist
        BlackHandle=findobj(DFA_Plot,'Color','k');
        for i=1:length(BlackHandle)
            delete(LineHandle(LineHandle == BlackHandle(i)))
        end
    catch
    end
    plot(log10(DFA_x(DFA_SmallTime_LogSample:DFA_LargeTime_LogSample)/Fs),log10(DFA_y(DFA_SmallTime_LogSample:DFA_LargeTime_LogSample)),'k.')
    grid on
%     zoom on
    axis([log10(min(DFA_x/Fs))-0.1 log10(max(DFA_x/Fs))+0.1 log10(min(DFA_y(3:end)))-0.1 log10(max(DFA_y))+0.1])
    xlabel('log_{10}(time), [Seconds]','Fontsize',12)
    ylabel('log_{10} F(time)','Fontsize',12)
    title(['DFA-exp=', num2str(DFAobject.MarkerValues(GetChannelID,1))],'Fontsize',12)
end

%% Nested functions part
    function ChID = GetChannelID
        % function finds the current ChannelID
        if ( InfoObject.channelID ~= 0)
            ChID = InfoObject.channelID;
        else
            ChID = ChannelID;
        end
    end
end

%% Supporting functions
function signal = fastdetrend(signal)
% A simple and fast detrend, see also the supporting function fastdetrend
% in the supporting functions folder
persistent a
persistent N
if (isempty(a) || size(signal,1) ~= N)
    N = size(signal,1);
    a = [zeros(N,1) ones(N,1)];
    a(1:N) = (1:N)'/N;
end
signal = signal - a*(a\signal);
end


Contact us