Source code for gazelib.models.saccade

# -*- coding: utf-8 -*-
'''
Find a linear saccade from the data.
'''
from gazelib.containers import CommonV1
from gazelib.preprocessing import fill_gaps, ExtrapolationError
import scipy.signal
import saccademodel


[docs]def fit(g): ''' Parameter: g: Gaze data as CommonV1 object Require streams: gazelib/gaze/left_eye_x_relative gazelib/gaze/left_eye_y_relative gazelib/gaze/right_eye_x_relative gazelib/gaze/right_eye_y_relative Raise: InsufficientDataException: if streams are missing or they are empty. Return:: { 'type': 'gazelib/gaze/saccade', 'start_time_relative': <int microseconds> 'end_time_relative': <int microseconds> 'mean_squared_error': <float> } ''' g.assert_has_streams([ 'gazelib/gaze/left_eye_x_relative', 'gazelib/gaze/left_eye_y_relative', 'gazelib/gaze/right_eye_x_relative', 'gazelib/gaze/right_eye_y_relative' ]) # Timeline names l_tl_name = g.get_stream_timeline_name('gazelib/gaze/left_eye_x_relative') r_tl_name = g.get_stream_timeline_name('gazelib/gaze/right_eye_x_relative') lx = g.raw['streams']['gazelib/gaze/left_eye_x_relative']['values'] ly = g.raw['streams']['gazelib/gaze/left_eye_y_relative']['values'] rx = g.raw['streams']['gazelib/gaze/right_eye_x_relative']['values'] ry = g.raw['streams']['gazelib/gaze/right_eye_y_relative']['values'] # Forward fill try: lx_fill = fill_gaps(lx) ly_fill = fill_gaps(ly) rx_fill = fill_gaps(rx) ry_fill = fill_gaps(ry) except ExtrapolationError: # Only nones or empty msg = 'Cannot find saccade from empty data.' raise CommonV1.InsufficientDataException(msg) # Median filter # Required to remove non-Gaussian noise i.e. random outliers # Saccademodel handles Gaussian noise. lx_filt = scipy.signal.medfilt(lx_fill, 5) ly_filt = scipy.signal.medfilt(ly_fill, 5) rx_filt = scipy.signal.medfilt(rx_fill, 5) ry_filt = scipy.signal.medfilt(ry_fill, 5) # Pointlists for saccademodel lpl = [[x, y] for x, y in zip(lx_filt, ly_filt)] rpl = [[x, y] for x, y in zip(rx_filt, ry_filt)] # Results try: lresults = saccademodel.fit(lpl) rresults = saccademodel.fit(rpl) except saccademodel.interpolate.InterpolationError: msg = 'Cannot find saccade from empty data.' raise CommonV1.InsufficientDataException(msg) # Pick one with smallest error lerr = lresults['mean_squared_error'] rerr = rresults['mean_squared_error'] if lerr < rerr: results = lresults tl_name = l_tl_name else: results = rresults tl_name = r_tl_name # Convert measured saccade end and start to times. lensource = len(results['source_points']) lensaccade = len(results['saccade_points']) start_index = max(0, lensource - 1) # do not let below zero end_index = max(0, lensource + lensaccade - 1) # do not let above length start = g.get_relative_time_by_index(tl_name, start_index) end = g.get_relative_time_by_index(tl_name, end_index) return { 'type': 'gazelib/gaze/saccade', 'start_time_relative': start, # microseconds 'end_time_relative': end, 'mean_squared_error': results['mean_squared_error'] }