https://github.com/alexandre-zenon/pupil
Raw File
Tip revision: 0a2c14c5d1e17b1bbfb08439165b5dccd573e50a authored by zenonal on 12 July 2023, 10:01:13 UTC
more general blink detection
Tip revision: 0a2c14c
read_pupilLabs.m
function [pupilLabsTrial, pupilLabsBlock] = read_pupilLabs(data)

% This function takes as input a structure containing the matlab data from
% an experiment using COSYgraphics and the pupilLabs eyetracker. It outputs the
% data trial by trial in pupilLabsTrial, and as single continuous vectors in
% pupilLabsBlock.
%
% A. Zťnon, Decembre 9, 2016

SRO = 30;% Default pupilLabs sampling rate

trialOnsets=[data.response(:).trialOnset];
TrialNumber=length(trialOnsets);
allPupilVector=[data.pupilData(:).pupil_diameter_px];
allEyeTimeVector=[data.pupilData(:).timestamp];
allEyeTimeVector=1000*(allEyeTimeVector-allEyeTimeVector(1))+data.pupilRecordStart;
allEyeXVector=[data.pupilData(:).gaze_norm_pos_x];
allEyeYVector=[data.pupilData(:).gaze_norm_pos_y];
pupilConfidence=[data.pupilData(:).pupil_confidence];

ti=round((allEyeTimeVector-allEyeTimeVector(1))/SRO)+1;
pupilVect(ti)=allPupilVector;
pupilConf(ti)=pupilConfidence;
eyeX(ti)=allEyeXVector;
eyeY(ti)=allEyeYVector;
timeVector=linspace(allEyeTimeVector(1),allEyeTimeVector(end),length(pupilVect));
vectZeros=find(pupilVect==0 & [0 diff(pupilVect)~=0]);
for vz = vectZeros
    if pupilVect(vz+1)~=0
        pupilVect(vz)=(pupilVect(vz-1)+pupilVect(vz+1))/2;
        pupilConf(vz)=(pupilConf(vz-1)+pupilConf(vz+1))/2;
        eyeX(vz)=(eyeX(vz-1)+eyeX(vz+1))/2;
        eyeY(vz)=(eyeY(vz-1)+eyeY(vz+1))/2;
    end
end

params.dataZ=4;
params.derivZ=2;
params.accelZ=2;

dataY = log(pupilVect);
out = excludeWrongDataFromPupilLabs( dataY , params);
dataY=interp1(find(~out),dataY(~out),[1:length(dataY)]);

disp(' Processing blink data');
error = pupilVect-exp(dataY);
RMS = log(fastSmooth(error.^2,5));
RMS(isinf(RMS))=NaN;
[ks,x]=ksdensity(RMS,'width',.8);
zer=find(abs(x)==min(abs(x)));
outlierThresh=x(zer+find(diff(ks(zer:end))>0,1)-1);
blinks=RMS>outlierThresh;

for trial = 1:TrialNumber
    pupilLabsTrial(trial).syncTime = trialOnsets(trial);
    pupilLabsTrial(trial).startTime = trialOnsets(trial);
    pupilLabsTrial(trial).events = NaN;
    if trial==TrialNumber
        pupilLabsTrial(trial).stopTime = allEyeTimeVector(end);
    else
        pupilLabsTrial(trial).stopTime = trialOnsets(trial+1)-1;
    end
    [z,beg]=min(abs(timeVector-pupilLabsTrial(trial).startTime));
    [z,eend]=min(abs(timeVector-pupilLabsTrial(trial).stopTime));
    bl=blinks(beg:eend);
    
    pupilLabsTrial(trial).blinks = blinks(beg:eend);
    pupilLabsTrial(trial).eyeX = eyeX(beg:eend);
    pupilLabsTrial(trial).eyeY = eyeY(beg:eend);
    pupilLabsTrial(trial).pupilSize = dataY(beg:eend);
    pupilLabsTrial(trial).eyeTime = timeVector(beg:eend);
end


allBlinkVector=blinks;
allPupilVector=dataY;
allEyeXVector=eyeX;
allEyeYVector=eyeY;

allBlinkVector=logical(allBlinkVector);

pupilLabsBlock.pupilSize=allPupilVector;
pupilLabsBlock.blinks=allBlinkVector;
pupilLabsBlock.eyeX=allEyeXVector;
pupilLabsBlock.eyeY=allEyeYVector;
pupilLabsBlock.time=timeVector;

end


%%%%%%%%%%%%%%%%%%%%%
function out = excludeWrongDataFromPupilLabs( dataY , params )

dataZ = params.dataZ;
derivZ = params.derivZ;
accelZ = params.accelZ;

pupilDeriv = [0 diff(dataY)];
pupilAccel = [0 diff(dataY)];
dataD = pupilDeriv;
dataA = pupilAccel;

out = dataY==0 | isinf(dataY) | isnan(dataY) | isinf(dataD);

dout=Inf;
MAXITER = 10;
iter=0;
while dout>0 & iter < MAXITER
    iter=iter+1;
    my= mode(round(dataY(~out)*10)/10);
    md= mode(round(dataD(~out)*10)/10);
    ma= mode(round(dataA(~out)*10)/10);
    athreshUp = ma+accelZ*std(dataA(~out));
    athreshDown = ma-accelZ*std(dataA(~out));
    dthreshUp = md+derivZ*std(dataD(~out));
    dthreshDown = md-derivZ*std(dataD(~out));
    ythresh = my-dataZ*std(dataY(~out));
    nout = out | dataD<dthreshDown | dataD>dthreshUp | dataY<ythresh | dataA<athreshDown | dataA>athreshUp;
    dout = sum(nout)-sum(out);
    out=nout;
end

end

back to top