detect_gaze_shifts_jld_size.m 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. function [num_shifts, shift_directions, sizeGa] = detect_gaze_shifts_jld_size(data)
  2. % Input:
  3. % - data: a 2 x N matrix containing the eye movements in the vertical
  4. % and horizontal axes, respectively, over time.
  5. % Output:
  6. % - num_shifts: the total number of gaze shifts detected in the data.
  7. % - shift_directions: a 1 x num_shifts vector containing the direction of
  8. % each gaze shift, where 1 indicates a rightward shift,
  9. % -1 indicates a leftward shift, 2 indicates an upward
  10. % shift, and -2 indicates a downward shift.
  11. % NaN indicates that no direction was detected.
  12. sizeGa=[];
  13. % Set parameters
  14. sampling_rate = 500; % in Hz
  15. vel_threshold = 5 * median(sqrt(sum(diff(data,1,2).^2,1)))/ sampling_rate; %5 is the original values
  16. min_saccade_interval = 100 / 1000 * sampling_rate; % in samples
  17. smooth_window_size = 7 / 1000 * sampling_rate; % in samples
  18. % Euclidean distance between succesives time points
  19. edP=sqrt(sum(diff(data,1,2).^2,1));
  20. edP=edP/sampling_rate;
  21. % Smooth the data
  22. data_smooth = smoothdata(edP', 'gaussian', smooth_window_size)'; %Euclidean D smooth
  23. ori_data_smooth = smoothdata(data', 'gaussian', smooth_window_size)'; %Original data smooth
  24. % data_vel = diff(data_smooth, 1, 2);
  25. data_vel = data_smooth;
  26. % Find saccade onsets
  27. % vel_norm = sqrt(sum(data_vel.^2, 1));
  28. saccade_onsets = find(data_vel > vel_threshold);
  29. if isempty(saccade_onsets)
  30. num_shifts = 0;
  31. shift_directions = [];
  32. return;
  33. end
  34. % Remove saccades that are too close in time
  35. saccade_diff = diff(saccade_onsets);
  36. toremove=find(saccade_diff < min_saccade_interval)+1; %index to remove
  37. saccade_onsets(toremove)=[];
  38. % Find saccade offset (defined as velocity smaller than threshold)
  39. all_saccade_offsets = find(data_vel < vel_threshold);
  40. % Finding the next offset to each onset
  41. saccade_offsets=[];
  42. for i=1:length(saccade_onsets)
  43. found=find(all_saccade_offsets>saccade_onsets(i)); %Find the next closet offset
  44. if isempty(found) %only when the epoch finish
  45. saccade_offsets(i)=length(data_vel);
  46. else
  47. saccade_offsets(i)=all_saccade_offsets(found(1));
  48. end
  49. end
  50. % Determine the direction of each gaze shift
  51. num_shifts = length(saccade_onsets);
  52. shift_directions = nan(1, num_shifts);
  53. sizeGa = nan(1, num_shifts);
  54. for i = 1:num_shifts
  55. saccade_start = saccade_onsets(i);
  56. saccade_end = saccade_offsets(i);
  57. posOnset=ori_data_smooth(:,saccade_onsets);
  58. posOffset=ori_data_smooth(:,saccade_end);
  59. dx = posOffset(1) - posOnset(1);
  60. dy = posOffset(2) - posOnset(2);
  61. angle = atan2(dy, dx); %Calculating the distance in radians
  62. shift_directions(i) = angle;
  63. sizeGa(i) = norm(posOnset - posOffset);
  64. end
  65. end