def get_angle_of_saccade(trajec, sac_range, method='integral', smoothed=True): if method != 'integral': f0 = sac_range[0] f1 = sac_range[-1] obj_ori_0 = trajec.velocities[f0] / np.linalg.norm(trajec.velocities[f0]) obj_ori_1 = trajec.velocities[f1] / np.linalg.norm(trajec.velocities[f1]) obj_ori_0_3vec = np.hstack( ( obj_ori_0, 0) ) obj_ori_1_3vec = np.hstack( (obj_ori_1, 0 ) ) sign_of_angle_of_saccade = np.sign( np.sum(np.cross( obj_ori_0, obj_ori_1 ) ) ) cosangleofsaccade = np.dot(obj_ori_0, obj_ori_1) angleofsaccade = np.arccos(cosangleofsaccade) signed_angleofsaccade = -1*angleofsaccade*sign_of_angle_of_saccade return floris_math.fix_angular_rollover(signed_angleofsaccade) else: if smoothed: return floris_math.fix_angular_rollover(np.sum(trajec.heading_smooth_diff[sac_range]/100.)) else: raise ValueError('need to do smoothed')
def calc_heading(trajec): trajec.heading_norollover = floris_math.remove_angular_rollover(np.arctan2(trajec.velocities[:,1], trajec.velocities[:,0]), 3) ## kalman data = trajec.heading_norollover.reshape([len(trajec.heading_norollover),1]) ss = 3 # state size os = 1 # observation size F = np.array([ [1,1,0], # process update [0,1,1], [0,0,1]], dtype=np.float) H = np.array([ [1,0,0]], # observation matrix dtype=np.float) Q = np.eye(ss) # process noise Q[0,0] = .01 Q[1,1] = .01 Q[2,2] = .01 R = 1*np.eye(os) # observation noise initx = np.array([data[0,0], data[1,0]-data[0,0], 0], dtype=np.float) initv = 0*np.eye(ss) xsmooth,Vsmooth = kalman_math.kalman_smoother(data, F, H, Q, R, initx, initv, plot=False) trajec.heading_norollover_smooth = xsmooth[:,0] trajec.heading_smooth_diff = xsmooth[:,1]*trajec.fps trajec.heading = floris_math.fix_angular_rollover(trajec.heading_norollover) trajec.heading_smooth = floris_math.fix_angular_rollover(trajec.heading_norollover_smooth)
def calc_heading_for_axes(trajec, axis='xy'): if axis == 'xy': axes = [1,0] elif axis == 'xz': axes = [2,0] elif axis == 'yz': axes = [2,1] heading_norollover_for_axes = floris_math.remove_angular_rollover(np.arctan2(trajec.velocities[:,axes[0]], trajec.velocities[:,axes[1]]), 3) ## kalman data = heading_norollover_for_axes.reshape([len(heading_norollover_for_axes),1]) ss = 3 # state size os = 1 # observation size F = np.array([ [1,1,0], # process update [0,1,1], [0,0,1]], dtype=np.float) H = np.array([ [1,0,0]], # observation matrix dtype=np.float) Q = np.eye(ss) # process noise Q[0,0] = .01 Q[1,1] = .01 Q[2,2] = .01 R = 1*np.eye(os) # observation noise initx = np.array([data[0,0], data[1,0]-data[0,0], 0], dtype=np.float) initv = 0*np.eye(ss) xsmooth,Vsmooth = kalman_math.kalman_smoother(data, F, H, Q, R, initx, initv, plot=False) heading_norollover_smooth_for_axes = xsmooth[:,0] heading_smooth_diff_for_axes = xsmooth[:,1]*trajec.fps heading_for_axes = floris_math.fix_angular_rollover(heading_norollover_for_axes) heading_smooth_for_axes = floris_math.fix_angular_rollover(heading_norollover_smooth_for_axes) if axis == 'xy': trajec.heading_norollover_smooth_xy = heading_norollover_smooth_for_axes trajec.heading_smooth_diff_xy = heading_smooth_diff_for_axes trajec.heading_xy = heading_for_axes trajec.heading_smooth_xy = heading_smooth_for_axes if axis == 'xz': trajec.heading_norollover_smooth_xz = heading_norollover_smooth_for_axes trajec.heading_smooth_diff_xz = heading_smooth_diff_for_axes trajec.heading_xz = heading_for_axes trajec.heading_smooth_xz = heading_smooth_for_axes if axis == 'yz': trajec.heading_norollover_smooth_yz = heading_norollover_smooth_for_axes trajec.heading_smooth_diff_yz = heading_smooth_diff_for_axes trajec.heading_yz = heading_for_axes trajec.heading_smooth_yz = heading_smooth_for_axes
def calc_airheading(trajec, flip=True): trajec.airheading_norollover = calc_heading_from_velocities(trajec.airvelocities) ## kalman data = trajec.airheading_norollover.reshape([len(trajec.airheading_norollover),1]) ss = 3 # state size os = 1 # observation size F = np.array([ [1,1,0], # process update [0,1,1], [0,0,1]], dtype=np.float) H = np.array([ [1,0,0]], # observation matrix dtype=np.float) Q = np.eye(ss) # process noise Q[0,0] = .01 Q[1,1] = .01 Q[2,2] = .01 R = 1*np.eye(os) # observation noise initx = np.array([data[0,0], data[1,0]-data[0,0], 0], dtype=np.float) initv = 0*np.eye(ss) xsmooth,Vsmooth = kalman_math.kalman_smoother(data, F, H, Q, R, initx, initv, plot=False) trajec.airheading_smooth = floris_math.fix_angular_rollover(xsmooth[:,0]) if flip: ip = np.where(trajec.airheading_smooth>0) im = np.where(trajec.airheading_smooth<=0) trajec.airheading_smooth[ip] -= np.pi trajec.airheading_smooth[im] += np.pi
def get_angle_of_saccade_z(trajec, sac): return floris_math.fix_angular_rollover(np.sum(trajec.heading_altitude_smooth_diff[sac]/100.))
def calc_saccades_z(trajec, threshold_lo=200, threshold_hi=100000000, min_angle=10, plot=False): # thresholds in deg/sec # min_angle = minimum angle necessary to count as a saccade, deg fps = 100. heading_norollover_for_axes = floris_math.remove_angular_rollover(np.arctan2(trajec.speed_xy[:], trajec.velocities[:,2]), 3) ## kalman data = heading_norollover_for_axes.reshape([len(heading_norollover_for_axes),1]) ss = 3 # state size os = 1 # observation size F = np.array([ [1,1,0], # process update [0,1,1], [0,0,1]], dtype=np.float) H = np.array([ [1,0,0]], # observation matrix dtype=np.float) Q = np.eye(ss) # process noise Q[0,0] = .01 Q[1,1] = .01 Q[2,2] = .01 R = 1*np.eye(os) # observation noise initx = np.array([data[0,0], data[1,0]-data[0,0], 0], dtype=np.float) initv = 0*np.eye(ss) xsmooth,Vsmooth = kalman_math.kalman_smoother(data, F, H, Q, R, initx, initv, plot=False) heading_norollover_smooth_for_axes = xsmooth[:,0] heading_smooth_diff_for_axes = xsmooth[:,1]*trajec.fps heading_for_axes = floris_math.fix_angular_rollover(heading_norollover_for_axes) heading_smooth_for_axes = floris_math.fix_angular_rollover(heading_norollover_smooth_for_axes) trajec.heading_altitude_smooth = heading_smooth_for_axes trajec.heading_altitude_smooth_diff = heading_smooth_diff_for_axes ## saccades possible_saccade_array = (np.abs(trajec.heading_altitude_smooth_diff)*180/np.pi > threshold_lo)*(np.abs(trajec.heading_altitude_smooth_diff)*180/np.pi < threshold_hi) possible_saccades = nim.find_blobs(possible_saccade_array, [3,100]) if len(possible_saccades) == 1: if np.sum(possible_saccades[0]) == 0: possible_saccades = [] trajec.saccades_z = [] if len(possible_saccades) > 0: for sac in possible_saccades: indices = np.where(sac==1)[0].tolist() if len(indices) > 0: # expand saccade range to make sure we get full turn #lo = np.max([indices[0]-5, 0]) #hi = np.min([indices[-1]+5, len(trajec.speed)-2]) #new_indices = np.arange(lo, hi).tolist() #tmp = np.where( np.abs(trajec.heading_diff_window[new_indices])*180/np.pi > 350 )[0].tolist() #indices = np.array(new_indices)[ tmp ].tolist() angle_of_saccade = np.abs(get_angle_of_saccade_z(trajec, indices)*180./np.pi) mean_speed = np.mean(trajec.speed[indices]) if len(indices) > 3 and angle_of_saccade > 10: # and mean_speed > 0.005: trajec.saccades_z.append(indices) if plot: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(trajec.positions[:,0], trajec.positions[:,2], color='black') for sac in trajec.saccades_z: ax.plot(trajec.positions[sac,0], trajec.positions[sac,2], color='red')