Skip to content
Snippets Groups Projects
twinsurr.m 5.58 KiB
function [y nTw] = twinsurr(varargin)
% TWINSURR   Creates twin surrogates for statistical tests.
%    Y=TWINSURR(X) creates twin surrogates Y based on the vector X
%    using recurrences. The matrix Y contains 100 columns of
%    100 twin surrogates. If X is a PxQ matrix, the resulting
%    surrogate matrix is Px100xQ.
%
%    Y=TWINSURR(X,M,T,E,...) creates twin surrogates using
%    embedding dimension M, delay T, recurrence threshold E. The
%    input arguments are similar to those of the command CRP.
%
%    Y=TWINSURR(X,M,T,E,...,N) creates N surrogates (default is 100).
%
%    [Y,NTWINS]=TWINSURR(...) where NTWINS is the total number
%    of twins in the RP.
%
%    Example: x = rand(3,1);
%             a = [.8 .3 -.25 .9]';
%             for i = 4:1000,
%                x(i) = sum(a(1:3) .* x(i-1:-1:i-3)) + a(end) * randn;
%             end
%             xs = twinsurr(x,1,1,.1,'euc',10);
%
%    See also CRP, RECONS.
%
%    References: 
%    Thiel, M., Romano, M. C., Kurths, J., Rolfs, M., Kliegl, R.: 
%    Twin Surrogates to Test for Complex Synchronisation, 
%    Europhys. Lett., 75, 2006.

% Copyright (c) 2008-2009
% Norbert Marwan, Potsdam Institute for Climate Impact Research, Germany
% http://www.pik-potsdam.de
%
% Copyright (c) 2008
% Norbert Marwan, Potsdam University, Germany
% http://www.agnld.uni-potsdam.de
%
% $Date$
% $Revision$
%
% $Log$
% Revision 5.3  2009/03/17 09:18:17  marwan
% serious bug fix, zero columns were also considered as twins!
%
% Revision 5.2  2008/07/02 12:00:48  marwan
% silent ability added, minor bug fixes
%
% Revision 5.1  2008/07/01 13:09:27  marwan
% initial import
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% programme properties

global errcode props

init_properties
nsur_init = 100;
sil = 0;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% check the input

error(nargchk(1,7,nargin));
if nargout>2, error('Too many output arguments'), end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% read the input

% transform any int to double
intclasses = {'uint8';'uint16';'uint32';'uint64';'int8';'int16';'int32';'int64'};
flagClass = [];
for i = 1:length(intclasses)
    i_int=find(cellfun('isclass',varargin,intclasses{i}));
    if ~isempty(i_int)
        for j = 1:length(i_int)
            varargin{i_int(j)} = double(varargin{i_int(j)});
        end
        flagClass = [flagClass; i_int(:)];
    end
end
if ~isempty(flagClass)
    disp(['Warning: Input arguments at position [',num2str(flagClass'),'] contain integer values']);
    disp(['(now converted to double).'])
end


varargin{8}=[];
i_double=find(cellfun('isclass',varargin,'double'));
i_char=find(cellfun('isclass',varargin,'char'));
check_meth={'ma','eu','mi','nr','rr','fa','in','om','op','di'}; 	% maxnorm, euclidean, nrmnorm,  fan, distance
check_norm={'non','nor'};                        % nonormalize, normalize
check_sil={'ve','si'};                         % verbose, silent

if isnumeric(varargin{1}) 		% read commandline input
   % check the text input parameters for method, gui 
    temp_meth=0;
    temp_norm=0;
    temp_sil=0;
    if ~isempty(i_char)
         for i=1:length(i_char), 
            varargin{i_char(i)}(4)='0';
            temp_norm=temp_norm+strcmpi(varargin{i_char(i)}(1:3),check_norm'); 
            temp_meth=temp_meth+strcmpi(varargin{i_char(i)}(1:2),check_meth'); 
            temp_sil=temp_sil+strcmpi(varargin{i_char(i)}(1:2),check_sil'); 
         end
         method_n=min(find(temp_meth));
         nonorm=min(find(temp_norm))-1;
         sil=min(find(temp_sil))-1;
         for i=1:length(i_char); temp2(i,:)=varargin{i_char(i)}(1:3); end

         if isempty(sil), sil=0; end
         if isempty(nonorm), nonorm=1; end
         if nonorm>1, nonorm=1; end
         if isempty(method_n), method_n=1; end
         if method_n>length(check_meth), method0=length(check_meth); end
         method=check_meth{method_n};
         norm_str = check_norm{nonorm+1};
    else
         method = 'max'; norm_str = 'non';
    end

    % get the parameters for creating RP
    if max(size(varargin{1}))<=3
        disp('Error using ==> twinsurr')
        disp('To less values in data X.')
        return
    end
    x=double(varargin{1});

    if ~isempty(varargin{i_double(2)}), m=varargin{i_double(2)}(1); else m=1; end
    if ~isempty(varargin{i_double(3)}), t=varargin{i_double(3)}(1); else t=1; end
    if ~isempty(varargin{i_double(4)}), e=varargin{i_double(4)}(1); else e=.1; end
    if ~isempty(varargin{i_double(5)}), nsur=varargin{i_double(5)}(1); else nsur=nsur_init; end
else
    disp('Error using ==> twinsurr')
    disp('No valid arguments.')
    return
end

if size(x,1) < size(x,2), x = x'; end
m0 = size(x,2);
N = length(x); 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% make surrogates

X = crp(x,m,t,e,method,norm_str,'sil');
X = double(X) .* (1-eye(size(X)));
NX = length(X);
%% find twins
if ~sil, h = waitbar(0,'Searching Twins'); end
for i = 1:NX, if ~sil, waitbar(i/NX); end
    A = repmat(X(:,i),1,NX);
%    S{i} = find(all(X == A & X == 1));
    S{i} = [i find(all(X == A) & any(X(:,i)))];
    nTwins(i) = numel(S{i});
end
if ~sil, delete(h); end

nTwins = sum(nTwins) - NX;

if nTwins < 1
    warning(['No twins found!',10,'The derived surrogates are identical with the original data.']')
end


for k = 1:nsur
    %% chose randomly first point
    i = ceil(NX * rand);
    xs = x(i,:);

    %% jump randomly between twins until length of surrogate is reached
    while length(xs) < N
        j = S{i};
        j_i = ceil(length(j) * rand);
        i = j(j_i);
        i = i + 1;
        if i > NX
            i = ceil(NX * rand);
            continue 
        end
        xs = [xs; x(i,:)];
    end
    y(:,k,1:m0) = reshape(xs(:),N,1,m0);
end

if nargout == 2;
    nTw = nTwins;
end