olafdimigen / eye-eeg

EYE-EEG toolbox for combining eye-tracking & EEG
https://www.eyetracking-eeg.org
37 stars 12 forks source link

bugreport searchclosest #1

Closed behinger closed 3 years ago

behinger commented 6 years ago

Hi Olaf, the bugfix you had in searchclosest.m: ''' % ------ -------''' is for the bug: searchclosest(1:10,11), thus if the event is larger. But the same bug can appear if the to-be-searched timeis smaller: searchclosest(1:10,0) i.e. you need to add:

if to< 1
to= 1;
end

searchlcosest(1:10,0) should not fail.

Maybe you can drop the dependency and directly use:

[~,I] = min(abs(timelist,t)); this will not make use of the sortedness of the list, but uses inbuild functions (the lists are not that large) Best, Bene

anomalosepia commented 6 years ago

I'm having some troubles here too. Just to make sure that i'm understanding the code correctly. The functionality here is to change the latency of the synchronization event to be the same as the temporally closest eye-tracking data sample? What if the synchronization event is a few seconds away, as can happen if the recording is paused? will the synchronization event latency be moved that much?

olafdimigen commented 6 years ago

@anomalosepia Synchronization needs to work despite the fact that (1) triggers of the same type are often send close to each other during experiments and (2) even if some proportion of triggers are lost in each of the recordings. To do the synchronization, you first need to specify two events that were correctly transmitted near the beginning and end of the recording. We call this the "start" and "end" trigger. They define the overall synchronization time range. Based on this "rough" synchronization information, EYE-EEG can then search for other common ("shared") events/triggers in both recordings based on their trigger codes and their temporal proximity (i.e. we search for a ET event of the same type around each EEG event, with some tolerance set to a default of 5 samples). In a next step, to optimize the estimation of the clock error, all identified shared events are then entered into a regression to compute a more exact clock error between both systems. This clock error information is then simply used to linearly interpolate the ET samples at the latencies of the recorded EEG samples. This also means that the ET is always resampled to the sampling rate of the "master clock" of the EEG. Function searchclosest() is currently used to find the ET event which is temporally closest to each EEG event.

For synchronization to work, you can pause the eye-tracker as often as you want, but you must not pause the EEG. The reason for this is that eye-trackers do have a unique time stamp (usually in ms or microseconds) assigned to each sample in the raw data, meaning that we can easily detect pauses in the recording. EEG systems usually do not have such a time stamp for each sample. We have to rely on the fact that the temporal spacing between EEG samples corresponds to the sampling rate (e.g. 500 Hz) and recording pauses are also not always coded in raw EEG data (depends on the amplifier system).

olafdimigen commented 6 years ago

@behinger Thanks for the bug report. searchclosest() is indeed suboptimal and will be replaced. Below a quick benchmark for a realistic EEG dataset (2.7 million points) and 1000 events. Search times are:

quick benchmark % create some realistic EEG data x = randn(1,2700000); % = time stamp of 1.5 hours of cont. recording at 500 Hz SR x = sort(x); y = randn(1000,1); % = 1000 values ("triggers") to search for

%% searchclosest tic for j = 1:length(y) z1(j) = searchclosest(x,y(j)); end toc % Elapsed time is 0.036124 seconds.

%% nearestpoint tic z2 = nearestpoint(y,x); toc % Elapsed time is 0.220410 seconds.

%% dsearchn tic z3 = dsearchn(x',y); toc % Elapsed time is 26.365907 seconds.

%% abs(x-y) tic for j = 1:length(y) d = abs(x-y(j)); [z4(j)] = find(min(d)==d); end toc % Elapsed time is 12.097356 seconds. % I could take out the find() here.

benchmark = [z1' z2 z3 z4'];

anomalosepia commented 6 years ago

Got it, I was worried it was looking for the closest ET SAMPLE, not the event. This makes perfect sense now. We started to have some bugs after updating to the most recent update and I was having some trouble tracking things down.

Thank you!

-A

From: Olaf Dimigen notifications@github.com Reply-To: olafdimigen/eye-eeg reply@reply.github.com Date: Sunday, January 14, 2018 at 2:11 AM To: olafdimigen/eye-eeg eye-eeg@noreply.github.com Cc: adam naples adamnaples@me.com, Comment comment@noreply.github.com Subject: Re: [olafdimigen/eye-eeg] bugreport searchclosest (#1)

@ anomalosepia Synchronization needs to work despite the fact that (1) triggers of the same type are often send close to each other during experiments and (2) even if some proportion of triggers are lost in each of the recordings. To do the synchronization, you first need to specify two events that were correctly transmitted near the beginning and end of the recording. We call this the "start" and "end" trigger. They define the overall synchronization time range. Based on this "rough" synchronization information, EYE-EEG can then search for other common ("shared") events/triggers in both recordings based on their trigger codes and their temporal proximity (i.e. we search for a ET event of the same type around each EEG event, with some tolerance set to a default of 5 samples). In a next step, to optimize the estimation of the clock error, all identified shared events are then entered into a regression to compute a more exact clock error between both systems. This clock error information is then simply used to linearly interpolate the ET samples at the latencies of the recorded EEG samples. This also means that the ET is always resampled to the sampling rate of the "master clock" of the EEG. Function searchclosest() is currently used to find the ET event which is temporally closest to each EEG event.

For synchronization to work, you can pause the eye-tracker as often as you want, but you must not pause the EEG. The reason for this is that eye-trackers do have a unique time stamp (usually in ms or microseconds) assigned to each sample in the raw data, meaning that we can easily detect pauses in the recording. EEG systems usually do not have such a time stamp for each sample. We have to rely on the fact that the temporal spacing between EEG samples corresponds to the sampling rate (e.g. 500 Hz) and recording pauses are also not always coded in raw EEG data (depends on the amplifier system).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

olafdimigen commented 6 years ago

Issue has been fixed by substituting "searchclosest()" with "nearestpoint()" which is more stable and (almost) as fast in newest EYE-EEG version (0.85).

olafdimigen commented 3 years ago

Closing this as issue seems fixed