diff --git a/detecteyemovements.m b/detecteyemovements.m index b32dfa5..78bbf12 100644 --- a/detecteyemovements.m +++ b/detecteyemovements.m @@ -1,12 +1,12 @@ -% detecteyemovements() - detect saccades & fixations in eye tracking data. -% Saccade detection is based on the algorithm by -% Engbert & Mergenthaler (2006). Saccades are defined as +% detecteyemovements() - detect saccades & fixations in eye tracking data. +% Saccade detection is based on the algorithm by +% Engbert & Mergenthaler (2006). Saccades are defined as % (monocular or binocular) outliers in 2D velocity space. -% Velocity thresholds for saccade detection are determined -% adaptively as a multiple of the (median-based) SD of all -% data samples in the epoch. Fixations are defined as -% intervals in-between saccades. Eye movements can be added -% as new events to EEGLAB's event structure. For various +% Velocity thresholds for saccade detection are determined +% adaptively as a multiple of the (median-based) SD of all +% data samples in the epoch. Fixations are defined as +% intervals in-between saccades. Eye movements can be added +% as new events to EEGLAB's event structure. For various % other options, see below. % % Usage: @@ -15,41 +15,41 @@ % plotfig,writesac,writefix) % % Required inputs: -% EEG - [string] EEG struct, also containing synchronized eye +% EEG - [string] EEG struct, also containing synchronized eye % tracking data (see pop_importeyetracker) -% left_eye_xy - [vector of two channel indices], -% specifying channel indices of X- (first value) and +% left_eye_xy - [vector of two channel indices], +% specifying channel indices of X- (first value) and % Y-component (second value) of left eye. Leave empty [] % if the left eye was not recorded. -% right_eye_xy - [vector of two channel indices], -% specifying channel indices of X- (first value) and +% right_eye_xy - [vector of two channel indices], +% specifying channel indices of X- (first value) and % Y-component (second value) of right eye. Leave empty [] % if the right eye was not recorded. -% vfac - [double] velocity factor ("lambda") to determine -% the velocity threshold for saccade detection +% vfac - [double] velocity factor ("lambda") to determine +% the velocity threshold for saccade detection % (cf. Engbert & Mergenthaler, 2006) % mindur - [integer] minimum saccade duration (in samples) % (cf. Engbert & Mergenthaler, 2006) % degperpixel - [double] visual angle of one screen pixel -% if this value is left empty [], saccade characteristics -% are reported in the original data metric (pixel?) +% if this value is left empty [], saccade characteristics +% are reported in the original data metric (pixel?) % instead of in degrees of visual angle -% smooth - [0/1] if set to 1, the raw data is smoothed over a +% smooth - [0/1] if set to 1, the raw data is smoothed over a % 5-sample window to suppress noise % noise. Recommended for high native ET sampling rates. -% globalthresh - [0/1]. Use the same thresholds for all epochs? -% 0: Adaptive velocity thresholds are computed -% individually for each data epoch. -% 1: Adaptive velocity thresholds are first computed for -% each epoch, but then the mean thresholds are applied to +% globalthresh - [0/1]. Use the same thresholds for all epochs? +% 0: Adaptive velocity thresholds are computed +% individually for each data epoch. +% 1: Adaptive velocity thresholds are first computed for +% each epoch, but then the mean thresholds are applied to % each epochs (i.e. same detection parameters are used for -% all epochs). Setting is irrelevant if the input data is +% all epochs). Setting is irrelevant if the input data is % still continuous (= only one data epoch). % clusterdist - [integer] value in sampling points that defines the -% minimum allowed fixation duration between two saccades. -% If the off- and onsets of two temp. adjacent sacc. are -% closer together than 'clusterdist' samples, these -% saccades are regarded as a "cluster" and treated +% minimum allowed fixation duration between two saccades. +% If the off- and onsets of two temp. adjacent sacc. are +% closer together than 'clusterdist' samples, these +% saccades are regarded as a "cluster" and treated % according to the 'clustermode' setting (see below). % clusterdist is irrelevant if clustermode == 1. % clustermode - [1,2,3,4]. Integer between 1 and 4. @@ -57,16 +57,16 @@ % 2: keep only first saccade of each cluster % 3: keep only largest sacc. of each cluster % 4: combine all movements into one (longer) saccade -% this new saccade is defined as the movement that +% this new saccade is defined as the movement that % occurs between the onset of the 1st saccade in the % cluster and the offset of the last sacc. in cluster -% WARNING: CLUSTERMODE 4 is experimental and untested! +% WARNING: CLUSTERMODE 4 is experimental and untested! % plotfig - [0/1] Show a figure with eye movement properties? -% 0: do not plot a figure. -% 1: plot a figure displaying properties of detected +% 0: do not plot a figure. +% 1: plot a figure displaying properties of detected % saccades & fixations % writesac - [0/1]: Add saccades to EEG.event? -% 0: detect saccades, but do not store them in EEG.event. +% 0: detect saccades, but do not store them in EEG.event. % 1: add detected saccades as new events to EEG.event. % writefix - [0/1]: Add fixations to EEG.event? % 0: detect fixations, but do not add them to EEG.event. @@ -76,37 +76,37 @@ % For this, set writesac and writefix to 0. % % Outputs: -% EEG - EEG structure. If writesac or writefix were set to 1, +% EEG - EEG structure. If writesac or writefix were set to 1, % the EEG structure (EEG.event/EEG.urevent/EEG.epoch) % will contain additional "saccade" and "fixation" events % with their respective properties % -% See also: vecvel, velthresh, microsacc_plugin, binsacc, saccpar, +% See also: vecvel, velthresh, microsacc_plugin, binsacc, saccpar, % mergesacc, addevents % % % MAJOR UPDATE 03/2018: bad ET intervals, as marked by "bad_ET" events -% in EEG.event (see function pop_rej_contin.m) are excluded from eye movement +% in EEG.event (see function pop_rej_contin.m) are excluded from eye movement % detection. Bad intervals are now ignored when estimating velocity thresholds % and saccade/fixation events overlapping with these intervals are removed % -% An example call of the function might look like this: +% An example call of the function might look like this: % >> EEG = detecteyemovements(EEG,[],[33 34],6,4,0.037,1,0,25,4,1,1,0) % -% In this example, the eye position data for the right eye is stored in -% channels 33 (horiz.) and 34 (vertical). The left eye was not recorded. -% The velocity threshold is set to 6 times the (median-based) +% In this example, the eye position data for the right eye is stored in +% channels 33 (horiz.) and 34 (vertical). The left eye was not recorded. +% The velocity threshold is set to 6 times the (median-based) % SD of all velocity samples in the epoch. The minimum duration of -% saccades to be detected is 4 samples. In the experiment, one screen -% pixel corresponded to 0.037 degrees of visual angle. -% The raw data is smoothed prior to saccade detection (smooth: 1). -% Adaptive velocity thresholds (X and Y-threshold for each eye) are -% determined individually for each data epoch (globalthresh: 0). For saccades -% separated by fixations of less than 25 samples, only the first saccade -% is kept (clusterdist: 25, clustermode: 2). A figure with the -% results is plotted. Detected saccades are stored as new events in +% saccades to be detected is 4 samples. In the experiment, one screen +% pixel corresponded to 0.037 degrees of visual angle. +% The raw data is smoothed prior to saccade detection (smooth: 1). +% Adaptive velocity thresholds (X and Y-threshold for each eye) are +% determined individually for each data epoch (globalthresh: 0). For saccades +% separated by fixations of less than 25 samples, only the first saccade +% is kept (clusterdist: 25, clustermode: 2). A figure with the +% results is plotted. Detected saccades are stored as new events in % EEG.event, but fixations are not stored. -% +% % The eye movement detection is based on: % % Engbert, R., & Kliegl, R. (2003). Microsaccades uncover the orientation @@ -114,7 +114,7 @@ % % Author: od % Copyright (C) 2009-2021 Olaf Dimigen, HU Berlin -% olaf.dimigen@hu-berlin.de +% olaf.dimigen@hu-berlin.de % 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 @@ -141,7 +141,7 @@ rdata = false; if length(right_eye_xy) == 2, rdata = true; end -if length(left_eye_xy) == 1 || length(right_eye_xy) == 1 +if length(left_eye_xy) == 1 || length(right_eye_xy) == 1 error('%s(): For each recorded eye, horizontal (X) and vertical (Y) gaze channel must be specified.',mfilename); end @@ -185,7 +185,7 @@ fprintf('\nDetecting saccades after Engbert & Mergenthaler (2006)\n') fprintf('\nVelocity threshold factor (vfac): %.2f SD',vfac); fprintf('\nMinimum saccade duration (mindur): %.2f samples (%.2f ms)',mindur,mindur*1000/EEG.srate); - if ~isempty(degperpixel) | isnan(degperpixel) % bugfix 2016-11-12 by OD: added case if degperpixel = NaN (from GUI input) + if ~isempty(degperpixel) | isnan(degperpixel) % bugfix 2016-11-12 by OD: added case if degperpixel = NaN (from GUI input) fprintf('\nVisual angle per screen pixel: %f°',degperpixel); metric = 'deg'; else @@ -193,8 +193,8 @@ degperpixel = 1; metric = 'pix'; end - if nepochs < 2, fprintf('\n-- Using continuous data.'), else fprintf('\n-- Using epoched data.'); end - if ldata && rdata, fprintf('\n-- Using binocular data:'); else fprintf('\n-- Using monocular data:'); end + if nepochs < 2, fprintf('\n-- Using continuous data.'), else, fprintf('\n-- Using epoched data.'); end + if ldata && rdata, fprintf('\n-- Using binocular data:'); else, fprintf('\n-- Using monocular data:'); end if ldata fprintf('\n\tLeft horiz.: \"%s\"',EEG.chanlocs(left_eye_xy(1)).labels); fprintf('\n\tLeft verti.: \"%s\"',EEG.chanlocs(left_eye_xy(2)).labels); @@ -202,8 +202,8 @@ if rdata fprintf('\n\tRight horiz.: \"%s\"',EEG.chanlocs(right_eye_xy(1)).labels); fprintf('\n\tRight verti.: \"%s\"',EEG.chanlocs(right_eye_xy(2)).labels); - end - if smooth, fprintf('\n-- Raw data is smoothed in 5-sample window.'); else fprintf('\n-- Raw data is not smoothed.'); end + end + if smooth, fprintf('\n-- Raw data is smoothed in 5-sample window.'); else, fprintf('\n-- Raw data is not smoothed.'); end if nepochs > 1 if globalthresh fprintf('\n-- Velocity thresholds computed globally across all %i epochs',nepochs); @@ -212,7 +212,7 @@ end end fprintf('\n-- Treatment of saccade clusters:'); - switch clustermode + switch clustermode case 1 fprintf('\n\tAll saccades are kept'); case 2 @@ -227,7 +227,7 @@ otherwise error('%s(): Unknown input for clustermode, should be: 1,2,3,4.',mfilename) end - if plotfig, fprintf('\n-- A figure with eye movement properties is plotted.'); end + if plotfig, fprintf('\n-- A figure with eye movement properties is plotted.'); end if writesac && writefix, fprintf('\n-- Saccades and fixations will be added to EEG.event.'); elseif writesac, fprintf('\n-- Saccades will be added to EEG.event.'); elseif writefix, fprintf('\n-- Fixations will be added to EEG.event.'); @@ -293,21 +293,21 @@ if globalthresh % use precomputed velocity thresholds (mean of all epochs) sacL = microsacc_plugin(l,vl,vfac,mindur,mean(l_msdx),mean(l_msdy)); else % compute velocity thresholds from this epoch only - sacL = microsacc_plugin(l,vl,vfac,mindur,l_msdx(e),l_msdy(e)); + sacL = microsacc_plugin(l,vl,vfac,mindur,l_msdx(e),l_msdy(e)); end end %% saccades of right eye if rdata r = EEG.data([right_eye_xy(1) right_eye_xy(2)],:,e)'; % bad/missing samples in eye track? - badsmp = sum(sum(r<=0)); if badsmp > 0, badepochs(e) = 1; nbadsmp = nbadsmp + badsmp; end + badsmp = sum(sum(r<=0)); if badsmp > 0, badepochs(e) = 1; nbadsmp = nbadsmp + badsmp; end vr = vecvel(r,EEG.srate,smoothlevel); % get eye velocities % detect monocular saccades if globalthresh % use precomputed velocity thresholds (mean of all epochs) sacR = microsacc_plugin(r,vr,vfac,mindur,mean(r_msdx),mean(r_msdy)); - else + else % compute velocity thresholds from this epoch only - sacR = microsacc_plugin(r,vr,vfac,mindur,r_msdx(e),r_msdy(e)); + sacR = microsacc_plugin(r,vr,vfac,mindur,r_msdx(e),r_msdy(e)); end end @@ -315,7 +315,7 @@ if ldata && rdata [sac, tmp, tmp] = binsacc(sacL,sacR); clear tmp sac = saccpar(sac); % average saccade characteristics of both eyes - sac = mergesacc(sac,(l+r)./2,clusterdist,clustermode); % merge nearby saccades (e.g. glissades) + sac = mergesacc(sac,(l+r)./2,clusterdist,clustermode); % merge nearby saccades (e.g., post-saccadic oscillations) elseif ldata sac = sacL; clear sacL; sac = saccpar([sac sac]); @@ -323,7 +323,7 @@ elseif rdata sac = sacR; clear sacR; sac = saccpar([sac sac]); - sac = mergesacc(sac,r,clusterdist,clustermode); + sac = mergesacc(sac,r,clusterdist,clustermode); end %% update various saccade metrics @@ -354,10 +354,13 @@ elseif rdata gazexy = r; end + % get position immediatly before sacc. onset and after sacc. offset startsmp = sac(:,1)-1; endsmp = sac(:,2)+1; if startsmp(1) < 1, startsmp(1,1) = 1; end - if endsmp(end) > size(gazexy,2), endsmp(end) = size(gazexy,2); end + if endsmp(end) > size(gazexy,1) % major bugfix, 2022-06-02, https://github.com/olafdimigen/eye-eeg/issues/24 + endsmp(end) = size(gazexy,1); % major bugfix, 2022-06-02, https://github.com/olafdimigen/eye-eeg/issues/24 + end sac(:,11) = gazexy(startsmp,1); sac(:,12) = gazexy(startsmp,2); sac(:,13) = gazexy(endsmp ,1); @@ -382,33 +385,33 @@ %% remove saccades that occured during "bad_ET" intervals [*] - % Delete all saccades whos onset or offset occurs during a - % bad_ET interval (signal jumps to blinks are otherwise detected as + % Delete all saccades whos onset or offset occurs during a + % bad_ET interval (signal jumps to blinks are otherwise detected as % saccades) % - % [*] Note: It is not clear/trivial how to treat blinks in the context + % [*] Note: It is not clear/trivial how to treat blinks in the context % of EM detection, since we do not know what really happened during a - % blink or loss of the signal. For example, is a long fixation with a - % blink in the middle really two fixations? Or should it be treated as - % one long fixation? Or should all fixations that are ended or started + % blink or loss of the signal. For example, is a long fixation with a + % blink in the middle really two fixations? Or should it be treated as + % one long fixation? Or should all fixations that are ended or started % by blinks or are interrupted by them be completely removed? - % The solution here is preliminary: I first remove all saccades that - % started or ended during a blink interval. The remaining saccades are - % used to define fixatinos. Finally, all fixations are removed that - % overlap with "bad_ET" intervals in EEG.event. So this approach - % removes any eye movement event that overlaps with a bad_ET interval. + % The solution here is preliminary: I first remove all saccades that + % started or ended during a blink interval. The remaining saccades are + % used to define fixatinos. Finally, all fixations are removed that + % overlap with "bad_ET" intervals in EEG.event. So this approach + % removes any eye movement event that overlaps with a bad_ET interval. % OD, 2018-03-08 - + %% delete saccades starting/ending during "bad_ET" intervals badETsmp = find(badvector(:,:,e)); if ~isempty(sac) ix_fakesac = find(ismember(sac(:,1),badETsmp) | ismember(sac(:,2),badETsmp)); sac(ix_fakesac,:) = []; - % if ~isempty(ix_fakesac) - % fprintf('\n\n-- Removed %i saccades that occured during "bad_ET" intervals',length(ix_fakesac)) - % end + % if ~isempty(ix_fakesac) + % fprintf('\n\n-- Removed %i saccades that occured during "bad_ET" intervals',length(ix_fakesac)) + % end end - + %% get fixations nsac = size(sac,1); fix = []; @@ -418,8 +421,8 @@ fix(f,1) = sac(f,2)+1; fix(f,2) = sac(f+1,1)-1; - - % catch special case: if Engbert algorithms are applied + + % catch special case: if Engbert algorithms are applied % without any saccade clustering [>> mergesacc()] there can % be back-to-back saccades with intervening "fixations" of % zero sample duration. Catch this by setting the duration @@ -451,7 +454,7 @@ fix(f,14) = sac(f,11); % sac_startpos_x fix(f,15) = sac(f,12); % sac_startpos_y fix(f,16) = sac(f,13); % sac_endpos_y - fix(f,17) = sac(f,14); % sac_endpos_y + fix(f,17) = sac(f,14); % sac_endpos_y end end % if epoch does not begin with saccade, add first fixation @@ -461,12 +464,12 @@ startfix(1) = 1; startfix(2) = sac(1,1)-1; % no incoming sacc. properties if data begins with fix, add "NaN" - startfix(11:17) = NaN; + startfix(11:17) = NaN; fix = [startfix; fix]; end % if epoch does not end with saccade, add last fixation if sac(end,2) < nsample - + % fix = [fix;[sac(end,2)+1 nsample]]; % update 09/2021: add properties of incoming sacc. to each fixation @@ -512,12 +515,12 @@ end fix(:,10) = e; % add index of corresp. data epoch - % recompute latencies of eye movement events + % recompute latencies of eye movement events % (only necessary for epoched data) offset = (e-1)*nsample; sac(:,[1 2]) = sac(:,[1 2])+offset; % special case: single sacc. lasts entire epoch - if ~isempty(fix) + if ~isempty(fix) fix(:,[1 2]) = fix(:,[1 2])+offset; end end @@ -553,7 +556,7 @@ % fprintf('\n-- Removed %i fixations that overlapped with "bad_ET" intervals',sum(badfix)) % end end - + % slow, but simple: allsac = [allsac;sac]; allfix = [allfix;fix]; @@ -562,11 +565,11 @@ %% remove artificial eye movements caused by boundaries (data breaks) -% Remove all EMs whose onset is detected in temporal proximity to boundary. +% Remove all EMs whose onset is detected in temporal proximity to boundary. % Otherwise, data breaks will likely result in additional fake sacc./fix. % Applies only if eye movements are detected in the continuous data if nepochs == 1 - + ix_bnd = find(cellfun(@(x) strcmp(x,'boundary'),{EEG.event.type})); % bug fix: now robust against numeric types % any data breaks? @@ -575,10 +578,10 @@ % minimum distance from data break in milliseconds (hard-coded) BOUNDDIST_MS = 50; - BOUNDDIST = round(BOUNDDIST_MS / (1000/EEG.srate)); + BOUNDDIST = round(BOUNDDIST_MS / (1000/EEG.srate)); % data break latencies - bound_lats = round([EEG.event(ix_bnd).latency]); - + bound_lats = round([EEG.event(ix_bnd).latency]); + % mark all samples close to data break boundvector = zeros(1,EEG.pnts); for b = 1:length(bound_lats) @@ -588,23 +591,23 @@ if uppr > EEG.pnts, uppr = EEG.pnts; end boundvector(lowr:uppr) = 1; end -% % nearboundsmp = find(boundvector); -% % -% % % option 1: event onset is close to boundary -% % % fakesac = find(ismember(allsac(:,1),nearboundsmp)); -% % % fakefix = find(ismember(allfix(:,1),nearboundsmp)); -% % -% % % option 2: event on- or offset is close to boundary -% % fakesac = find(ismember(allsac(:,1),nearboundsmp) | ismember(allsac(:,2),nearboundsmp)); -% % fakefix = find(ismember(allfix(:,1),nearboundsmp) | ismember(allfix(:,2),nearboundsmp)); -% % -% % allsac(fakesac,:) = []; -% % allfix(fakefix,:) = []; -% fprintf('\n--------------------------------------------------------------------'); -% fprintf('\nFound %i data breaks (boundary events) in the continuous data',length(ix_bnd)); -% fprintf('\nRemoving eye movements that might be artifacts of data breaks:'); -% fprintf('\nRemoved %i saccades < %i ms away from a boundary',length(fakesac),BOUNDDIST_MS); -% fprintf('\nRemoved %i fixations < %i ms away from a boundary',length(fakefix),BOUNDDIST_MS); + % % nearboundsmp = find(boundvector); + % % + % % % option 1: event onset is close to boundary + % % % fakesac = find(ismember(allsac(:,1),nearboundsmp)); + % % % fakefix = find(ismember(allfix(:,1),nearboundsmp)); + % % + % % % option 2: event on- or offset is close to boundary + % % fakesac = find(ismember(allsac(:,1),nearboundsmp) | ismember(allsac(:,2),nearboundsmp)); + % % fakefix = find(ismember(allfix(:,1),nearboundsmp) | ismember(allfix(:,2),nearboundsmp)); + % % + % % allsac(fakesac,:) = []; + % % allfix(fakefix,:) = []; + % fprintf('\n--------------------------------------------------------------------'); + % fprintf('\nFound %i data breaks (boundary events) in the continuous data',length(ix_bnd)); + % fprintf('\nRemoving eye movements that might be artifacts of data breaks:'); + % fprintf('\nRemoved %i saccades < %i ms away from a boundary',length(fakesac),BOUNDDIST_MS); + % fprintf('\nRemoved %i fixations < %i ms away from a boundary',length(fakefix),BOUNDDIST_MS); end end @@ -618,7 +621,7 @@ %% user feedback if bad eye-tracking data (values <= 0) but no bad_ET events if sum(badepochs)>0 & isempty(ix_badETevent) warning('\nI found bad or missing data (i.e. values <= 0) in the ET channels but no \"bad_ET" events!'); - fprintf('\nDetails:'); + fprintf('\nDetails:'); fprintf('\n-- %i of %i epochs contained gaze position values <= 0',sum(badepochs),nepochs); fprintf('\n-- Total number of bad samples <= 0: %i',nbadsmp); fprintf('\n-- Did you detect or reject bad intervals with out-of-range values (''Reject data based on eyetrack'')?'); @@ -645,7 +648,7 @@ fprintf('\n%i fixations detected:',size(allfix,1)); fprintf('\n\tMedian duration: %.2f ms',median(allfix(:,3))*1000/EEG.srate); if ldata,fprintf('\n\tMedian fix. pos. left eye: Horiz.: %.2f px. Vert.: %.2f px',median(allfix(:,4)),median(allfix(:,5))); end - if rdata,fprintf('\n\tMedian fix. pos. right eye: Horiz.: %.2f px. Vert.: %.2f px',median(allfix(:,6)),median(allfix(:,7))); end + if rdata,fprintf('\n\tMedian fix. pos. right eye: Horiz.: %.2f px. Vert.: %.2f px',median(allfix(:,6)),median(allfix(:,7))); end end @@ -668,7 +671,7 @@ %% write eye movements to EEG.event & EEG.urevent if writefix || writesac - + % check: are there already eye movements events in EEG.event? em_types = {'saccade','fixation','L_saccade','R_saccade','L_fixation','R_fixation'}; if any(cellfun(@(x) any(strcmp(x,em_types)),{EEG.event.type})) % updated [v.0.337] @@ -695,7 +698,7 @@ EEG = addevents(EEG,allfix(:,[1 3 8 9 10 11 12 13 14 15 16 17]),{'latency','duration','fix_avgpos_x','fix_avgpos_y','epoch', 'sac_vmax','sac_amplitude','sac_angle','sac_startpos_x','sac_startpos_y','sac_endpos_x','sac_endpos_y'},'fixation'); %EEG = addevents(EEG,allfix(:,[1 3 4 5 6 7 10]),{'latency','duration','fixposition_ly','fixposition_lx','fixposition_ry','fixposition_rx','epoch'},'fixation'); elseif ldata % left eye recorded - EEG = addevents(EEG,allfix(:,[1 3 4 5 10 11 12 13 14 15 16 17]),{'latency','duration','fix_avgpos_x','fix_avgpos_y','epoch', 'sac_vmax','sac_amplitude','sac_angle','sac_startpos_x','sac_startpos_y','sac_endpos_x','sac_endpos_y'},'fixation'); + EEG = addevents(EEG,allfix(:,[1 3 4 5 10 11 12 13 14 15 16 17]),{'latency','duration','fix_avgpos_x','fix_avgpos_y','epoch', 'sac_vmax','sac_amplitude','sac_angle','sac_startpos_x','sac_startpos_y','sac_endpos_x','sac_endpos_y'},'fixation'); elseif rdata % right eye recorded EEG = addevents(EEG,allfix(:,[1 3 6 7 10 11 12 13 14 15 16 17]),{'latency','duration','fix_avgpos_x','fix_avgpos_y','epoch', 'sac_vmax','sac_amplitude','sac_angle','sac_startpos_x','sac_startpos_y','sac_endpos_x','sac_endpos_y'},'fixation'); end