Skip to content

Blinks, fixations & saccades

Neon +2.9.0 +1.5.0

Using the device.receive_eye_events method, you can receive eye events such as blinks, saccades or fixations. The data returned is either an instance of:

Warning

Requires the "Compute fixations" setting to be enabled in the Companion Device.

FixationEventData

Defines a complete fixation or saccade event. The data returned are structured as follows, with event_type being either 0 for saccades or 1 for fixations.

FixationEventData(
    event_type=0,
    start_time_ns=1744625900502677306,
    end_time_ns=1744625900562676306,
    start_gaze_x=768.2272338867188,
    start_gaze_y=685.6964721679688,
    end_gaze_x=716.1095581054688,
    end_gaze_y=493.5322570800781,
    mean_gaze_x=747.7811279296875,
    mean_gaze_y=597.7672119140625,
    amplitude_pixels=199.10633850097656,
    amplitude_angle_deg=12.716423988342285,
    mean_velocity=3318.313232421875,
    max_velocity=7444.6396484375,
    rtp_ts_unix_seconds=1744626471.955861
)
FixationEventData(
    event_type=1,
    start_time_ns=1744625967695094306,
    end_time_ns=1744625968135465306,
    start_gaze_x=870.0199584960938,
    start_gaze_y=311.0625,
    end_gaze_x=730.7664794921875,
    end_gaze_y=264.4870300292969,
    mean_gaze_x=839.43115234375,
    mean_gaze_y=280.5098876953125,
    amplitude_pixels=146.83596801757812,
    amplitude_angle_deg=9.18490982055664,
    mean_velocity=272.82110595703125,
    max_velocity=1415.25048828125,
    rtp_ts_unix_seconds=1744626539.528702
)
FixationEventData

FixationEventData

Bases: NamedTuple

Data for a fixation or saccade event.

Represents a completed fixation or saccade event with detailed information.

Methods:

  • from_raw

    Create a FixationEventData instance from raw RTSP data.

Attributes:

amplitude_angle_deg instance-attribute

amplitude_angle_deg: float

Amplitude in degrees.

amplitude_pixels instance-attribute

amplitude_pixels: float

Amplitude in pixels.

datetime property

datetime: datetime

Get the timestamp as a datetime object.

end_gaze_x instance-attribute

end_gaze_x: float

End gaze x-coordinate in pixels.

end_gaze_y instance-attribute

end_gaze_y: float

End gaze y-coordinate in pixels.

end_time_ns instance-attribute

end_time_ns: int

End time of the event in nanoseconds.

event_type instance-attribute

event_type: int

Type of event (0 for saccade, 1 for fixation).

max_velocity instance-attribute

max_velocity: float

Maximum velocity in pixels per degree.

mean_gaze_x instance-attribute

mean_gaze_x: float

Mean gaze x-coordinate in pixels.

mean_gaze_y instance-attribute

mean_gaze_y: float

Mean gaze y-coordinate in pixels.

mean_velocity instance-attribute

mean_velocity: float

Mean velocity in pixels per degree.

rtp_ts_unix_seconds instance-attribute

rtp_ts_unix_seconds: float

RTP timestamp in seconds since Unix epoch.

start_gaze_x instance-attribute

start_gaze_x: float

Start gaze x-coordinate in pixels.

start_gaze_y instance-attribute

start_gaze_y: float

Start gaze y-coordinate in pixels.

start_time_ns instance-attribute

start_time_ns: int

Start time of the event in nanoseconds.

timestamp_unix_ns property

timestamp_unix_ns: int

Get the timestamp in nanoseconds since the Unix epoch.

from_raw classmethod

from_raw(data: RTSPData) -> FixationEventData

Create a FixationEventData instance from raw RTSP data.

Source code in src/pupil_labs/realtime_api/streaming/eye_events.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@classmethod
def from_raw(cls, data: RTSPData) -> "FixationEventData":
    """Create a FixationEventData instance from raw RTSP data."""
    (
        event_type,
        start_time_ns,
        end_time_ns,
        start_gaze_x,
        start_gaze_y,
        end_gaze_x,
        end_gaze_y,
        mean_gaze_x,
        mean_gaze_y,
        amplitude_pixels,
        amplitude_angle_deg,
        mean_velocity,
        max_velocity,
    ) = struct.unpack("!iqqffffffffff", data.raw)
    return cls(
        event_type,
        start_time_ns,
        end_time_ns,
        start_gaze_x,
        start_gaze_y,
        end_gaze_x,
        end_gaze_y,
        mean_gaze_x,
        mean_gaze_y,
        amplitude_pixels,
        amplitude_angle_deg,
        mean_velocity,
        max_velocity,
        data.timestamp_unix_seconds,
    )

FixationOnsetEventData

This defines a fixation or saccade onset event. The data returned are structured as follows:

FixationOnsetEventData(event_type=2, start_time_ns=1744626187872119306, rtp_ts_unix_seconds=1744626759.2655792)
FixationOnsetEventData(event_type=3, start_time_ns=1744626187872119306, rtp_ts_unix_seconds=1744626759.2655792)
FixationOnsetEventData

FixationOnsetEventData

Bases: NamedTuple

Data for a fixation or saccade onset event.

Represents the beginning of a fixation or saccade event.

Attributes:

datetime property

datetime: datetime

Get the timestamp as a datetime object.

event_type instance-attribute

event_type: int

Type of event (2 for saccade onset, 3 for fixation onset).

rtp_ts_unix_seconds instance-attribute

rtp_ts_unix_seconds: float

RTP timestamp in seconds since Unix epoch.

start_time_ns instance-attribute

start_time_ns: int

Start time of the event in nanoseconds.

timestamp_unix_ns property

timestamp_unix_ns: int

Get the timestamp in nanoseconds since the Unix epoch.

BlinkEventData

Finally, BlinkEventData determines a blink event.

BlinkEventData(
    event_type=4,
    start_time_ns=1744626029708811306,
    end_time_ns=1744626029919061306,
    rtp_ts_unix_seconds=1744626601.1020627
)
BlinkEventData

BlinkEventData

Bases: NamedTuple

Data for a blink event.

Represents a detected blink event with timing information.

Methods:

  • from_raw

    Create a BlinkEventData instance from raw RTSP data.

Attributes:

datetime property

datetime: datetime

Get the timestamp as a datetime object.

end_time_ns instance-attribute

end_time_ns: int

End time of the blink in nanoseconds.

event_type instance-attribute

event_type: int

Type of event (4 -> blink events).

rtp_ts_unix_seconds instance-attribute

rtp_ts_unix_seconds: float

RTP timestamp in seconds since Unix epoch.

start_time_ns instance-attribute

start_time_ns: int

Start time of the blink in nanoseconds.

timestamp_unix_ns property

timestamp_unix_ns: int

Get the timestamp in nanoseconds since the Unix epoch.

from_raw classmethod

from_raw(data: RTSPData) -> BlinkEventData

Create a BlinkEventData instance from raw RTSP data.

Source code in src/pupil_labs/realtime_api/streaming/eye_events.py
27
28
29
30
31
32
33
34
35
@classmethod
def from_raw(cls, data: RTSPData) -> "BlinkEventData":
    """Create a BlinkEventData instance from raw RTSP data."""
    (
        event_type,
        start_time_ns,
        end_time_ns,
    ) = struct.unpack("!iqq", data.raw)
    return cls(event_type, start_time_ns, end_time_ns, data.timestamp_unix_seconds)

Example

If you run the example you will get an output like this:

[FIXATION] event with duration of 3.93 seconds.
[SACCADE] event with 43° amplitude.
[BLINK] blinked at 10:35:07 UTC
Check the whole example code here
stream_eye_events
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from datetime import datetime, timezone

from pupil_labs.realtime_api.simple import discover_one_device
from pupil_labs.realtime_api.streaming.eye_events import (
    BlinkEventData,
    FixationEventData,
)

# Look for devices. Returns as soon as it has found the first device.
print("Looking for the next best device...")
device = discover_one_device(max_search_duration_seconds=10)
if device is None:
    print("No device found.")
    raise SystemExit(-1)

# device.streaming_start()  # optional, if not called, stream is started on-demand

try:
    while True:
        eye_event = device.receive_eye_events()
        if isinstance(eye_event, BlinkEventData):
            time_sec = eye_event.start_time_ns // 1e9
            blink_time = datetime.fromtimestamp(time_sec, timezone.utc)
            print(f"[BLINK] blinked at {blink_time.strftime('%H:%M:%S')} UTC")

        elif isinstance(eye_event, FixationEventData) and eye_event.event_type == 0:
            angle = eye_event.amplitude_angle_deg
            print(f"[SACCADE] event with {angle:.0f}° amplitude.")

        elif isinstance(eye_event, FixationEventData) and eye_event.event_type == 1:
            duration = (eye_event.end_time_ns - eye_event.start_time_ns) / 1e9
            print(f"[FIXATION] event with duration of {duration:.2f} seconds.")

        # print(eye_event) # This will print all the fields of the eye event

except KeyboardInterrupt:
    pass

finally:
    print("Stopping...")
    # device.streaming_stop()  # optional, if not called, stream is stopped on close
    device.close()  # explicitly stop auto-update