Eyelink timing inconsistent

Hello,

I work in Nicole Rust’s lab at the University of Pennsylvania. We recently developed an interest in looking at the pupil diameter data that is being saved from our EyeLink 1000 through MWorks. When we looked at the associated eye_time variable we noticed that the samples are not being collected at regular intervals. The size of the intervals between timepoints is very small early in a trial and stabilizes at ~1000 Hz but occasionally blips to ~2000 Hz or ~50 Hz throughout the trial. These “blips” aren’t happening in regular places and are inconsistent across trials from the same session. I shared plots from a couple sample trials showing the interval between each set of two timepoints across all eye_time values in a given trial. One is zoomed in on the start of the trial to show the “ramping up” of intervals that is observed in all trials.

The result is that it’s very difficult to align/average pupil diameter across trials, as each diameter measure occurs at a different time point relative to stimulus onset. This issue is present as far back as the original .mwk2 file (we use the extraction functions that you provide to pull the eye_time variable out of these files). We have tried to record and save .edf files directly from the eye tracker while running the experiment to compare the values, but the samples are empty in the file saved directly from the eye tracker. Do you have any ideas about what might be happening here? I found a similar post on the forums that has since closed but wasn’t able to find a solution posted there. Please let me know if you need any additional information.

Thanks!

Attachments:

Hi Catrina,

Every time MWorks receives new sample or event data from the EyeLink, it assigns the associated sample/event time (on the EyeLink clock) to the variable indicated by eye_time. If there are gaps in the values assigned to eye_time, it means there are gaps in the timing of the samples/events MWorks receives from the EyeLink. (If you want to see exactly where and how the assignment happens, take a look at this code.)

Given this, I’m a little confused by your plots. The units of EyeLink clock times (i.e. the values assigned to eye_time) are milliseconds, but your plots show typical intervals of 1000. Since you probably aren’t sampling eye position only once per 1000ms, I have to assume that the deltas in your plots are between the MWorks times associated with each assignment to eye_time. MWorks times are in microseconds, so a typical delta of 1000us would indicate a sampling rate of 1000Hz, which makes sense.

Another noteworthy feature of your plots is that each 2000us interval is always immediately followed by a 50us interval. If you are indeed comparing MWorks time stamps, then all this indicates is that MWorks periodically receives a sample “late” and ends up processing it at the same time as the next sample. For example, if you’ve set data_interval to 1ms, and the EyeLink is acquiring samples at 1000Hz, then MWorks may occasionally ask for a sample just before it’s available. It then waits 1ms before asking again, at which point both the just-missed sample and the subsequent sample are available. MWorks then processes these samples back to back, resulting in a very short interval (on the MWorks clock) between them. I see that the description of data_interval (which I did not write) says that it should be “faster than [the] tracker’s sampling rate”, perhaps to avoid just this sort of doubling-up of samples.

The fact that you’re comparing MWorks time stamps can also explain the “ramp up” you see at the start of the trial. When you start I/O on the EyeLink device, MWorks first tells the EyeLink to start recording and then spawns a new thread that periodically polls the EyeLink for new data. All the samples that the EyeLink records before the data-polling thread becomes active are received and processed together, so the MWorks time interval between them is very small.

A corollary to all this is that if, instead of comparing the MWorks time stamps of adjacent eye_time events, you were to compare the values of those events (which, again, are times on the EyeLink clock), you would see a consistent delta. If you didn’t, it would indicate that some samples were being lost.

All that said…

The result is that it’s very difficult to align/average pupil diameter across trials, as each diameter measure occurs at a different time point relative to stimulus onset.

I don’t know how you’re measuring stimulus onset time, but it’s very unlikely that it’s accurate to within less than a couple of milliseconds. As such, if you’re trying to determine the pupil diameter at stimulus onset, it would make sense to average several milliseconds worth of samples around the stimulus onset time. You might even want to average over the first full frame (or more) of the stimulus. Given this, I don’t see how an occasional delta of 1ms in the time stamp for an eye_time value matters to your analysis.

Cheers,
Chris Stawarz

Hi Chris,

Apologies that it has been ridiculously long since I picked up this conversation. Due to several external factors we had to put down this project for a bit, but we’re working on it again and I’m still having some issues with the pupil data from our EyeLink and would appreciate your insight.

As a reminder, we were having issues with inconsistent time stamps associated with our pupil data. You had directed me toward the “eye_time” variable which should save the time stamps from the EyeLink device. Thank you! There is a (mostly) consistent delta in the eye_time values even though there wasn’t in the associated MWorks times.

I have now recorded a data file that saves both pupil_size_l and eye_time from the EyeLink device. When I retrieve these variables from our .mwk2 file using the getEvents() function they have a different number of values. For example, in one session there are 2,490,013 pupil_size_l values and 2,559,101 eye_time values even though both come from the same EyeLink device. Do you have any suggestions for what might be causing this? We have tried accessing raw edf files from the EyeLink to see if the inconsistency is present in the EyeLink files themselves, but all of the files from the experimental sessions have no saved events so I haven’t been able to check. Your advice for next steps troubleshooting would be much appreciated!

Thanks,

Catrina

Hi Catrina,

I suspect the eye_time values without corresponding pupil_size_l values represent times when there was no eye-position data, presumably because the subject was looking away from the display. I would expect that the number of pupil_size_l values would be the same as the number of other eye-position values (e.g. eye_lx). All the variable values from a single EyeLink sample will have the same MWorks timestamp (time_us in MATLAB), so you can match each pupil_size_l value to its corresponding eye_time value via the timestamp.

Cheers,
Chris

Hi Chris,

I’m a bit confused by your suggestion, although I did look at the number of samples in two of the eye-position variables and they do match the number of pupil samples. My understanding is that the EyeLink inputs missing data values (-32768) when there is no data (as mentioned in the MWorks documentation). There are many of these values present in our data so this seems to be working properly. What condition would cause us to miss some samples altogether without filling in the missing value?

Best,

Catrina

Hi Catrina,

My understanding is that the EyeLink inputs missing data values (-32768) when there is no data (as mentioned in the MWorks documentation). There are many of these values present in our data so this seems to be working properly. What condition would cause us to miss some samples altogether without filling in the missing value?

MWorks assigns the “missing data” value to a given output variable only if it’s not already set to that value. It does this simply to avoid filling up your event file with redundant events. It’s certainly possible that, for a given EyeLink sample, only eye_time will be updated, as all other values were missing in one or more previous samples, so the corresponding variables are already set to “missing data”. It’s debatable whether eye_time should be set in this case, but that’s how it works at present.

Cheers,
Chris