def filterEyeSamples(filter_type, xpix, ypix, pupil, invalid_data_mask, **kwargs): processSampleEventGaps(xpix, ypix, pupil, invalid_data_mask, 'linear') vac = VisualAngleCalc(**calibration_area_info) xdeg, ydeg = vac.pix2deg(xpix, ypix) if filter_type == 'butter': wn = kwargs.get('wn', 0.2) order = kwargs.get('order', 2) b, a = butter(order, wn, 'low') x_filtered = filtfilt(b, a, xdeg) y_filtered = filtfilt(b, a, ydeg) elif filter_type == 'gauss': sigma = kwargs.get('sigma', 2) x_filtered = gaussian_filter1d(xdeg, sigma) y_filtered = gaussian_filter1d(ydeg, sigma) elif filter_type == 'median': size = kwargs.get('size', 5) x_filtered = medfilt(xdeg, size) y_filtered = medfilt(ydeg, size) elif filter_type == 'sg': size = kwargs.get('size', 7) order = kwargs.get('order', 2) x_filtered = savitzky_golay(xdeg, window_size=size, order=order) y_filtered = savitzky_golay(ydeg, window_size=size, order=order) elif filter_type == 'average': weights = np.asarray(kwargs.get('weights', [1., 2., 3., 2., 1.])) weights = weights / np.sum(weights) x_filtered = np.convolve(xdeg, weights, 'same') y_filtered = np.convolve(ydeg, weights, 'same') else: raise ValueError( 'Unknown Filter Type: %s. Must be one of %s' % (filter_type, str(['sg', 'butter', 'gauss', 'median']))) xdeg[invalid_data_mask] = np.NaN ydeg[invalid_data_mask] = np.NaN x_filtered[invalid_data_mask] = np.NaN y_filtered[invalid_data_mask] = np.NaN return (xdeg, ydeg), (x_filtered, y_filtered)
def createTrialDataStreams(): trial_data_streams=[] # Get the filtered event data. # We will use right eye data only for the testing.. # dataAccessUtil=ExperimentDataAccessUtility('../hdf5_files','remote_data.hdf5', experimentCode=None,sessionCodes=[]) event_type=EventConstants.BINOCULAR_EYE_SAMPLE retrieve_attributes=('time','right_gaze_x','right_gaze_y','right_pupil_measure1','status') trial_event_data=dataAccessUtil.getEventAttributeValues(event_type, retrieve_attributes, conditionVariablesFilter=None, startConditions={'time':('>=','@TRIAL_START@')}, endConditions={'time':('<=','@TRIAL_END@')}, ) dataAccessUtil.close() for t,trial_data in enumerate(trial_event_data): #Create a mask to be used to define periods of missing data in a data trace (eye tracker dependent) # invalid_data_mask=trial_data.status%10>=2 time=trial_data.time pupil=trial_data.right_pupil_measure1 # Get x, y eye position traces (in pixels), setting sample positions where there is track loss # to NaN. xpix_cleared=trial_data.right_gaze_x.copy() ypix_cleared=trial_data.right_gaze_y.copy() processSampleEventGaps(xpix_cleared,ypix_cleared,pupil,invalid_data_mask,'clear') # Get x, y eye position traces (in pixels), setting sample positions # where there is track loss to be linearly interpolated using each # missing_sample_start-1 and missing_sample_end+1 as the points to # interpolate between. # xpix_linear=trial_data.right_gaze_x.copy() ypix_linear=trial_data.right_gaze_y.copy() # valid_data_periods is a list of array slice objects giving the start,end index of each non missing # period of in the data stream. # valid_data_periods=processSampleEventGaps(xpix_linear,ypix_linear,pupil,invalid_data_mask,'linear') # Convert from pixels to visual angle coordinates calibration_area_info=dict(display_size_mm=(340,280.0), display_res_pix=(1280.0,1024.0), eye_distance_mm=590.0) vac=VisualAngleCalc(**calibration_area_info) xdeg,ydeg=vac.pix2deg(xpix_linear,ypix_linear) # Create Filtered versions of the x and y degree data traces # We'll use the Median Filter... # xdeg_filtered = scipy.signal.medfilt(xdeg,SPATIAL_FILTER_WINDOW_SIZE) ydeg_filtered = scipy.signal.medfilt(ydeg,SPATIAL_FILTER_WINDOW_SIZE) # Create the velocity stream # xvel=calculateVelocity(time,xdeg_filtered) yvel=calculateVelocity(time,ydeg_filtered) # Filter the velocity data # FILTER_ORDER=2 Wn=0.3 b, a = scipy.signal.butter(FILTER_ORDER, Wn, 'low') ffunc=scipy.signal.filtfilt xvel_filtered = ffunc(b, a, xvel) yvel_filtered = ffunc(b, a, yvel) # xvel_filtered=savitzky_golay(xvel,window_size=VELOCITY_FILTER_WINDOW_SIZE,order=2) # yvel_filtered=savitzky_golay(yvel,window_size=VELOCITY_FILTER_WINDOW_SIZE,order=2) # xvel_filtered=gaussian_filter1d(xvel,VELOCITY_FILTER_WINDOW_SIZE) # yvel_filtered=gaussian_filter1d(yvel,VELOCITY_FILTER_WINDOW_SIZE) # xvel_filtered=scipy.signal.medfilt(xvel,VELOCITY_FILTER_WINDOW_SIZE) # yvel_filtered=scipy.signal.medfilt(yvel,VELOCITY_FILTER_WINDOW_SIZE) velocity=np.sqrt(xvel*xvel+yvel*yvel) velocity_filtered=np.sqrt(xvel_filtered*xvel_filtered+yvel_filtered*yvel_filtered) # Create a data trace dictionary for all the different types # of data traces created for the trial # trial_data={} trial_data['time']=time trial_data['xpix_cleared']=xpix_cleared trial_data['ypix_cleared']=ypix_cleared trial_data['xpix_linear']=xpix_linear trial_data['xpix_linear']=xpix_linear trial_data['xdeg']=xdeg trial_data['ydeg']=ydeg trial_data['xdeg_filtered']=xdeg_filtered trial_data['ydeg_filtered']=ydeg_filtered trial_data['pupil']=pupil trial_data['velocity']=velocity trial_data['velocity_filtered']=velocity_filtered trial_data['valid_data_periods']=valid_data_periods trial_data['missing_data_mask']=invalid_data_mask # Add the data trace dictionary to a list # trial_data_streams.append(trial_data) return trial_data_streams
else: pix_x=trial_data.left_gaze_x pix_y=trial_data.left_gaze_y pupil=trial_data.left_pupil_measure1 invalid_data_mask=trial_data.status//10>=2 # No need to keep the hdf5 file open anymore... # dataAccessUtil.close() ##### STEP B. ##### # Use the VisualAngleCalc class defined in the common_workshop_functions to # generate an object that can convert data from pixels to visual angles based # on the supplied calibration / display surface geometry and eye distance. # vac=VisualAngleCalc(**calibration_area_info) # Calculate the visual degree position in x and y for the given pixel position arrays. # degree_x,degree_y=vac.pix2deg(pix_x,pix_y) # Process the eye fields using the processSampleEventGaps function defined # in the common_workshop_functions.py file. The last argument of 'clear' # tells the function to set any x or y position missing data samples to NaN # and to set the pupil size field to 0. The operations are preformed in-place # on the numpy arrays passed to the function. # The returned valid_data_periods is a list of each group of temporally adjacent # samples that are valid, each element of the list is the (start, stop) # index for a given period of valid data. # valid_data_periods=processSampleEventGaps(pix_x,pix_y,pupil,invalid_data_mask, 'clear')