class Game(object): def __init__(self): ############### # load config # ############### with open('config.yaml') as f: CONFIG = yaml.load(f) with open('mvc.yaml') as f: MVC = yaml.load(f) self.subj_id = CONFIG['subject-id'] self.subj_dir = 'datasets/' + self.subj_id self.loc = CONFIG['location'] ################# # set constants # ################# if self.loc == 'lab': self.FRAME_RATE = 120 elif self.loc == 'scanner': self.FRAME_RATE = 60 self.SCREEN_WIDTH, self.SCREEN_HEIGHT = 1024, 768 self.BG_COLOR_REG = 70,70,70 self.BG_COLOR_REG_2 = 110,110,110 self.BG_COLOR_REG_3 = 40,40,40 self.SUCCESS_COLOR = 70,170,70 self.FAIL_COLOR = 170,70,70 self.INDICATOR_COLOR = 40,60,40 self.INDICATOR_COLOR_2 = 30,100,30 self.GOOD_MSG_COLOR = 160,255,160 self.BAD_MSG_COLOR = 255,160,160 self.A_MSG_COLOR = 160,160,255 self.B_MSG_COLOR = 230,230,160 self.REG_FIXATION_COLOR = 200,200,200 self.GOOD_FIXATION_COLOR = self.SUCCESS_COLOR self.BAD_FIXATION_COLOR = 240,140,140 self.BAD_SCORE_COLOR = 200,100,100 self.GOOD_SCORE_COLOR = 100,200,100 self.HIGHLIGHT_SCORE_COLOR = 20,255,20 self.NORM_SCORE_COLOR = 180,180,100 self.SENSOR_INPUT_OFFSET = np.array([0.5*self.SCREEN_WIDTH, 0.75*self.SCREEN_HEIGHT]) self.BORDER_COLOR_DICT = {'incomplete':(50,0,0), 'ready':(0,0,50), 'complete':(0,50,0), 'disconnected':(50,0,0), 'idle':(50,50,50), 'rai':(0,50,0), 'rfi':(0,50,0), 'loc':(0,50,0), 'nfb':(0,50,0)} self.BG_COLOR_DICT = {'incomplete':(100,0,0), 'ready':(0,0,100), 'complete':(0,100,0), 'disconnected':(100,0,0), 'idle':(100,100,100), 'rai':(0,100,0), 'rfi':(0,100,0), 'loc':(0,100,0), 'nfb':(0,100,0)} # dict entry for current timer set to use self.PRE_REST_TIME = {'trial':0} self.INTRO_TIME = {'trial':0} self.FEEDBACK_TIME = {'trial':0} self.ACTIVE_TIME = {'trial':0} self.TRIALS = {'trial':0} self.TRIAL_TIME = {'trial':0} self.INTRO_TRIGGER_TIME = {'trial':0} self.ACTIVE_TRIGGER_TIME = {'trial':0} self.FEEDBACK_TRIGGER_TIME = {'trial':0} # self-paced times self.PRE_REST_TIME['s_p'] = 3 self.INTRO_TIME['s_p'] = 1 self.FEEDBACK_TIME['s_p'] = 2 self.ACTIVE_TIME['s_p'] = -1 self.TRIALS['s_p'] = 5 self.TRIAL_TIME['s_p'] = (self.PRE_REST_TIME['s_p'] + self.INTRO_TIME['s_p'] + self.FEEDBACK_TIME['s_p']) self.INTRO_TRIGGER_TIME['s_p'] = self.PRE_REST_TIME['s_p'] self.ACTIVE_TRIGGER_TIME['s_p'] = self.PRE_REST_TIME['s_p'] + self.INTRO_TIME['s_p'] self.FEEDBACK_TRIGGER_TIME['s_p'] = -1 self.TRIAL_TYPES = 9 self.trial_type_count = 0 # localizer times # 40 seconds per trial # 480s per run self.PRE_REST_TIME['loc'] = 17 self.INTRO_TIME['loc'] = 1 self.ACTIVE_TIME['loc'] = 20 self.FEEDBACK_TIME['loc'] = 2 self.TRIALS['loc'] = 12 # neurofeedback times # 60 seconds per trial # 480s per run self.PRE_REST_TIME['nfb'] = 27 self.INTRO_TIME['nfb'] = 1 self.ACTIVE_TIME['nfb'] = 30 self.FEEDBACK_TIME['nfb'] = 2 self.TRIALS['nfb'] = 8 self.NFB_INFO_TIME = 0.5 self.NFB_INFO_HEIGHT = 28 self.MVC_TIME = 19 self.INTRO_TRIGGER_TIME['loc'] = self.PRE_REST_TIME['loc'] self.ACTIVE_TRIGGER_TIME['loc'] = self.PRE_REST_TIME['loc'] + self.INTRO_TIME['loc'] self.FEEDBACK_TRIGGER_TIME['loc'] = self.ACTIVE_TRIGGER_TIME['loc'] + self.ACTIVE_TIME['loc'] self.INTRO_TRIGGER_TIME['nfb'] = self.PRE_REST_TIME['nfb'] self.ACTIVE_TRIGGER_TIME['nfb'] = self.PRE_REST_TIME['nfb'] + self.INTRO_TIME['nfb'] self.FEEDBACK_TRIGGER_TIME['nfb'] = self.ACTIVE_TRIGGER_TIME['nfb'] + self.ACTIVE_TIME['nfb'] self.CONTROL_TRIGGER_TIME = 1000*int(0.5*self.INTRO_TRIGGER_TIME['nfb']) self.BASELINE_CALC_SHIFT = self.PRE_REST_TIME['nfb']-10 self.TRIAL_TIME['loc'] = (self.PRE_REST_TIME['loc'] + self.INTRO_TIME['loc'] + self.ACTIVE_TIME['loc'] + self.FEEDBACK_TIME['loc']) self.TRIAL_TIME['nfb'] = (self.PRE_REST_TIME['nfb'] + self.INTRO_TIME['nfb'] + self.ACTIVE_TIME['nfb'] + self.FEEDBACK_TIME['nfb']) ##################### # control variables # ##################### self.TR = 1. self.ADD_CONTROL_TRS = 5 self.TF_CONTROL = self.ACTIVE_TIME['nfb']+self.ADD_CONTROL_TRS self.N_ACTIVE_TIME = self.ACTIVE_TIME['nfb']/self.TR+1 self.N_CONTROL_STEPS = self.TF_CONTROL/self.TR+1 self.CONTROL_MVC_MIN = 0.1 self.CONTROL_MVC_MAX = 0.4 self.u_vec = np.zeros((1,self.N_CONTROL_STEPS)) self.y_vec = np.zeros(self.N_CONTROL_STEPS) gc.set_system(self) ########################## # force sensor variables # ########################## self.MVC_IN_PIXEL = 900 self.MVC_MIN = 0#0.05 self.ANGLE_ADD_DEG = 20 self.ANGLE_ADD = np.deg2rad(self.ANGLE_ADD_DEG) self.ANGLE_MULT = 1+2*self.ANGLE_ADD/np.pi self.set_mvc(MVC['mvc']) self.DAQ_LPF_CUTOFF = 8 self.DAQ_LPF_ORDER = 3 self.CALIBRATE_BOOL = False # False or True if self.CALIBRATE_BOOL: fu.write_cal_header(self) if SENSOR_ACTIVE: if self.CALIBRATE_BOOL: self.daq = Pydaq('Dev3/ai0:2', self.FRAME_RATE, lp_filt_freq=14, lp_filt_order=3, force_params='force_params_cal.txt') else: self.daq = Pydaq('Dev3/ai0:1', self.FRAME_RATE, lp_filt_freq=self.DAQ_LPF_CUTOFF, lp_filt_order=self.DAQ_LPF_ORDER, force_params='force_params_lab.txt') self.scanner_daq = Pydaq('Dev1/ai2:3', self.FRAME_RATE, lp_filt_freq=self.DAQ_LPF_CUTOFF, lp_filt_order=self.DAQ_LPF_ORDER, force_params='force_params_scanner.txt') ######################## # networking variables # ######################## IP = CONFIG['server-ip'] PORT = CONFIG['server-port'] self.SERVER_TARGET = 'http://{ip}:{port}/'.format(ip=IP, port=PORT) self.requests_running_bool = mp.Value('i', 1) self.last_volume_received = mp.Value('i', 0) self.pool = mp.Pool() self.insta_mode = 'disconnected' # idle, rai, rfi, loc, nfb self.roi_name = 'm1_left_a' self.next_run_msg = '' self.insta_complete = OrderedDict() self.insta_complete['roi'] = 'incomplete' self.insta_complete['rai'] = 'incomplete' self.insta_complete['rfi'] = 'incomplete' self.insta_complete['warp2rfi'] = 'incomplete' self.insta_complete['glm'] = 'incomplete' self.insta_complete['loc'] = 'incomplete' self.raw_betas = {'active':0., 'force':0., 'complexity':0., 'constant':0.} self.psc_betas = {'active':0.5, 'force':1.5, 'complexity':1.0} self.MAX_CONTROL = 3 self.MIN_CONTROL = 0.5 self.PSC_TARGET_LIST = [1.5,1.5,1.5,1.5] self.RUN_TYPE_LIST = CONFIG['run-type-list'] self.NFB_TRS = int(self.TRIAL_TIME['nfb'] *self.TRIALS['nfb']/self.TR) self.bold_rois_array = [] self.bold_rois_array.append(mp.Array('d',self.NFB_TRS)) self.REQUEST_WAIT_TIME = 0.1 self.requests_process = mp.Process(target = gn.requests_loop, args = (self.SERVER_TARGET, self.REQUEST_WAIT_TIME, self.requests_running_bool, self.last_volume_received, self.bold_rois_array,)) #################################################### # start pygame and initialize default game objects # #################################################### pygame.init() pygame.mouse.set_visible(not pygame.mouse.set_visible) self.clock = pygame.time.Clock() if CONFIG['fullscreen']: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.FULLSCREEN) else: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) ################################## # initialize custom game objects # ################################## self.CURSOR_RAD = 75 self.FIXATION_WIDTH = 1.5*self.CURSOR_RAD self.FIXATION_HEIGHT = 8 self.cursor = Cursor(self.screen, self.CURSOR_RAD) self.timers = {} self.init_timers() self.TARGET_SUCCESS_TIME = .15 self.TARGET_MIN_TIME = .5 self.TARGET_RAD_MIN = -25 self.TARGET_RAD_MAX = 45 ##################### # target lists here # ##################### # function to generate x length, all same mvc, # all same phase # and do {20s length} x {.1, .2, .4} x {0, 180} self.MVC_LIST = [] self.PHASE_LIST = [] self.MVC_LIST.append(np.array([.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1])) self.MVC_LIST.append(np.array([.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2,.2])) self.MVC_LIST.append(np.array([.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4,.4])) self.PHASE_LIST.append(np.array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])) self.PHASE_LIST.append(np.array([180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180])) self.TRAINING_TARGET_LOC_LIST = [] self.loc_target_order = [0,3,1,4,2,5,1,4,0,5,3,2] for mvc in self.MVC_LIST: for phase in self.PHASE_LIST: self.TRAINING_TARGET_LOC_LIST.append(self.gen_target_list(mvc,phase)) self.next_mvc_list = [] self.next_phase_list = [] self.next_target_loc_list = [] # auto-generate 1, 1.5, and 2 psc from dummy data for psc_target in (1.,1.5,2.): new_targets = self.gen_control_targets(psc_target) self.TRAINING_TARGET_LOC_LIST.append(new_targets) self.SAMPLE_MVC_LIST = np.array([.4,.1,.2,.1,.2,.4]) self.SAMPLE_PHASE_LIST = np.array([0,0,0,180,180,180]) self.SAMPLE_TARGET_LOC_LIST = self.gen_target_list(self.SAMPLE_MVC_LIST, self.SAMPLE_PHASE_LIST) self.set_targets(self.SAMPLE_TARGET_LOC_LIST) ###################### # set game variables # ###################### self.screen_mid = np.array([0.5*self.screen.get_width(), 0.5*self.screen.get_height()]) self.bg_color = self.BG_COLOR_REG_3 self.fixation_color = self.REG_FIXATION_COLOR self.input_mode = 'mouse' self.input_pos = np.array([0.0,0.0]) self.input_force = np.array([0.0,0.0]) self.cal_force = 0. self.debug_bool = False self.nfb_info_bool = False self.run_mode = 'idle' # idle, mvc, trials self.run_type = 's_p' self.self_paced_bool = True self.controller_active_bool = False self.controller_calc_bool = False self.nfb_run_count = 0 self.calc_score_bool = False self.trial_time_array = np.array(()) self.set_timer_mode('s_p') self.current_score = 0 self.score_color = self.GOOD_SCORE_COLOR self.score_fixation_status = 'norm' self.max_rec_mvc_both = 0 self.max_rec_mvc_x = 0 self.max_rec_mvc_y = 0 self.MVC_DISPLAY_CEIL = 100. def gen_target_list(self, mvc_list, phase_list): mvc_list = np.ravel(mvc_list) phase_list = np.ravel(phase_list) target_list = np.zeros((2,2*len(mvc_list))) for idx in range(len(mvc_list)): if phase_list[idx] == 0: target_list[0][2*idx] = 0 target_list[1][2*idx] = -self.MVC_IN_PIXEL*mvc_list[idx] target_list[0][2*idx+1] = 0 target_list[1][2*idx+1] = -self.MVC_IN_PIXEL*self.MVC_MIN elif phase_list[idx] == 180: target_list[0][2*idx] = self.MVC_IN_PIXEL*mvc_list[idx] target_list[1][2*idx] = -self.MVC_IN_PIXEL*self.MVC_MIN target_list[0][2*idx+1] = -self.MVC_IN_PIXEL*mvc_list[idx] target_list[1][2*idx+1] = -self.MVC_IN_PIXEL*self.MVC_MIN return np.transpose(target_list) def set_mvc(self, mvc): self.newtons_2_pixel_both = self.MVC_IN_PIXEL/(.5*mvc['both']) self.newtons_2_pixel_x = self.MVC_IN_PIXEL/(mvc['x']) self.newtons_2_pixel_y = self.MVC_IN_PIXEL/(mvc['y']) def set_targets(self, target_list): self.targets = [] # set targets for target_loc in target_list: target_rad = (self.TARGET_RAD_MAX - (self.TARGET_RAD_MAX - self.TARGET_RAD_MIN) * np.sqrt(target_loc[0]**2 + target_loc[1]**2) /float(self.MVC_IN_PIXEL)) self.targets.append(Target(self.screen, target_loc, self.SENSOR_INPUT_OFFSET, target_rad, self.CURSOR_RAD, self.TARGET_SUCCESS_TIME, self.TARGET_MIN_TIME)) # link targets self.current_target = self.targets[0] self.targets[0].prev_target = None self.targets[-1].next_target = None for idx in range(len(self.targets)-1): self.targets[idx].next_target = self.targets[idx+1] self.targets[idx+1].prev_target = self.targets[idx] def get_pos(self): if self.input_mode=='mouse' or not(SENSOR_ACTIVE): return pygame.mouse.get_pos() else: if self.loc == 'lab': f_in_x, f_in_y = self.daq.get_force() elif self.loc == 'scanner': f_in_x, f_in_y = self.scanner_daq.get_force() self.input_force = f_in_x, f_in_y f_mag = max(f_in_x, f_in_y) f_ang = np.arctan2(f_in_x, f_in_y) f_out_x = f_mag*np.cos(2*self.ANGLE_MULT*f_ang-self.ANGLE_ADD) f_out_y = f_mag*np.sin(2*self.ANGLE_MULT*f_ang-self.ANGLE_ADD) ang_blend = (f_ang-.25*np.pi)/(.25*np.pi) ang_blend_both = (max(0,(1-abs(ang_blend))) *self.newtons_2_pixel_both) if ang_blend < 0: ang_blend_side = abs(ang_blend)*self.newtons_2_pixel_y else: ang_blend_side = abs(ang_blend)*self.newtons_2_pixel_x newtons_2_pixel = ang_blend_both + ang_blend_side pos_x = (self.SENSOR_INPUT_OFFSET[0] +newtons_2_pixel*f_out_x) pos_y = (self.SENSOR_INPUT_OFFSET[1] -newtons_2_pixel*f_out_y) return (pos_x, pos_y) def init_timers(self): self.timers['loc'] = Timer(self.TRIAL_TIME['loc'], self.TRIALS['loc']) self.timers['nfb'] = Timer(self.TRIAL_TIME['nfb'], self.TRIALS['nfb']) self.timers['s_p'] = Timer(self.TRIAL_TIME['s_p'], self.TRIALS['s_p']) self.timers['trial'] = self.timers['loc'] self.timers['move'] = Timer(sys.maxint) self.timers['mvc'] = Timer(self.MVC_TIME) self.timers['nfb_info'] = Timer(self.NFB_INFO_TIME) def set_timer_mode(self, mode): self.timers['trial'] = self.timers[mode] self.PRE_REST_TIME['trial'] = self.PRE_REST_TIME[mode]*1000 self.INTRO_TIME['trial'] = self.INTRO_TIME[mode]*1000 self.FEEDBACK_TIME['trial'] = self.FEEDBACK_TIME[mode]*1000 self.ACTIVE_TIME['trial'] = self.ACTIVE_TIME[mode]*1000 self.TRIALS['trial'] = self.TRIALS[mode]*1000 self.TRIAL_TIME['trial'] = self.TRIAL_TIME[mode]*1000 self.INTRO_TRIGGER_TIME['trial'] = self.INTRO_TRIGGER_TIME[mode]*1000 self.ACTIVE_TRIGGER_TIME['trial'] = self.ACTIVE_TRIGGER_TIME[mode]*1000 self.FEEDBACK_TRIGGER_TIME['trial'] = self.FEEDBACK_TRIGGER_TIME[mode]*1000 def reset_all_timers(self): for k,t in self.timers.iteritems(): t.reset() def check_input(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.quit() elif event.key == pygame.K_0: if self.loc == 'lab': self.daq.set_volts_zero() elif self.loc == 'scanner': self.scanner_daq.set_volts_zero() elif event.key == pygame.K_m: if self.input_mode == 'mouse': self.input_mode = 'sensor' elif self.input_mode == 'sensor': self.input_mode = 'mouse' elif event.key == pygame.K_d: self.debug_bool = not self.debug_bool elif event.key == pygame.K_s: self.nfb_info_bool = not self.nfb_info_bool elif event.key == pygame.K_SPACE: self.run_type = 's_p' gr.reset_for_next_run(self) self.run_mode = 'trials' elif event.key == pygame.K_7: self.run_mode = 'mvc' elif event.key == pygame.K_8: gn.set_mode('loc', self.SERVER_TARGET) self.run_type = 'loc' self.next_run_msg = 'Ready for Localizer' elif event.key == pygame.K_9: gn.set_mode('nfb', self.SERVER_TARGET) self.run_type = 'nfb' self.next_run_msg = ('Ready for Run ' + str(game.nfb_run_count + 1) + ' of 4') elif event.key == pygame.K_5: if ((self.run_type == 'loc' or self.run_type == 'nfb') and self.run_mode == 'idle'): self.run_mode = 'trials' self.next_run_msg = '' gr.reset_for_next_run(self) # control of insta_server elif event.key == pygame.K_g: gn.set_mode('idle', self.SERVER_TARGET) elif event.key == pygame.K_h: gn.set_mode('rai', self.SERVER_TARGET) elif event.key == pygame.K_j: gn.set_mode('rfi', self.SERVER_TARGET) elif event.key == pygame.K_k: gn.set_mode('loc', self.SERVER_TARGET) elif event.key == pygame.K_l: gn.set_mode('nfb', self.SERVER_TARGET) # testing controls # elif event.key == pygame.K_z: # # figure out when/where to calculate this (add trigger) # # need baseline calculation # # and y_vec calculation # psc_target = 2. # # self.pool.apply_async(func = gc.calc_control, # # args = (self, # # psc_target, # # self.u_vec, # # self.y_vec), # # callback = self.update_control_targets) # u_vec = gc.calc_control(self, # psc_target, # self.u_vec, # self.y_vec) # self.update_control_targets(u_vec) def run(self): fu.write_trial_s_p_header(self) fu.write_control_file(self) fu.write_all_headers_timed(self) self.requests_process.start() while True: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.input_pos = self.get_pos() self.cursor.update(self.input_pos) if self.current_target != None: self.cursor.update_warn(time_passed, not(self.current_target.success)) else: self.cursor.update_warn(time_passed, False) self.draw_background() if self.run_mode == 'trials': gr.frame_based_updates(game, time_passed) if self.debug_bool: self.draw_debug(time_passed) if self.nfb_info_bool: self.draw_nfb_info(time_passed) if self.run_mode == 'mvc': gr.run_mvc(self, time_passed) else: self.cursor.draw() pygame.display.flip() def draw_targets(self): current_bool = self.current_target != None if current_bool: next_bool = self.current_target.next_target != None else: next_bool = False if next_bool: next_next_bool = self.current_target.next_target.next_target != None else: next_next_bool = False if next_next_bool: self.current_target.next_target.next_target.draw(draw_type='next_next') if next_bool: self.current_target.next_target.draw(draw_type='next') if current_bool: self.current_target.draw(draw_type='current') def draw_debug(self, time_passed): fr = 1000/float(time_passed) fr_msg = 'frame rate: ' + str(fr) x_v_msg = 'x force: ' + str(self.input_force[0]) y_v_msg = 'y force: ' + str(self.input_force[1]) betas_active_msg = 'active beta: ' + str(self.psc_betas['active']) betas_force_msg = 'force beta: ' + str(self.psc_betas['force']) betas_complexity_msg = 'complexity beta: ' + str(self.psc_betas['complexity']) lvr_msg = 'last vol: ' + str(self.last_volume_received.value) gg.draw_msg(self.screen, fr_msg, loc='left', pos=(10,33), size=28) gg.draw_msg(self.screen, x_v_msg, loc='left', pos=(10,66), size=28) gg.draw_msg(self.screen, y_v_msg, loc='left', pos=(10,99), size=28) gg.draw_msg(self.screen, betas_active_msg, loc='left', pos=(10,132), size=28) gg.draw_msg(self.screen, betas_force_msg, loc='left', pos=(10,165), size=28) gg.draw_msg(self.screen, betas_complexity_msg, loc='left', pos=(10,198), size=28) gg.draw_msg(self.screen, lvr_msg, loc='left', pos=(10,231), size=28) if self.CALIBRATE_BOOL: self.cal_force = self.daq.force_transform_cal( self.daq.get_volts_cal()) z_v_msg = 'z lbs: ' + str(self.cal_force) gg.draw_msg(self.screen, z_v_msg, loc='left', pos=(10,231), size=28) fu.cal_record(self, self.f_cal) def draw_nfb_info(self, time_passed): self.timers['nfb_info'].update(time_passed) if self.timers['nfb_info'].time_limit_hit: self.pool.apply_async(func = gn.get_complete, args = (self.SERVER_TARGET, self.insta_complete), callback = self.update_complete) self.pool.apply_async(func = gn.get_mode, args = (self.SERVER_TARGET,), callback = self.update_mode) self.pool.apply_async(func = gn.get_betas, args = (self.SERVER_TARGET, self.roi_name, self.raw_betas), callback = self.update_betas) self.timers['nfb_info'].time_limit_hit = False self.timers['nfb_info'].count = 0 # show insta_mode and insta_complete list_count = 0 for k,v in self.insta_complete.iteritems(): gg.draw_info_rect(self.screen, k + ': ' + v, (255,255,255),self.BORDER_COLOR_DICT[v], self.BG_COLOR_DICT[v],350, self.NFB_INFO_HEIGHT,200, 50 + list_count*(8+self.NFB_INFO_HEIGHT)) list_count += 1 gg.draw_info_rect(self.screen, 'mode: ' + self.insta_mode, (255,255,255),self.BORDER_COLOR_DICT[self.insta_mode], self.BG_COLOR_DICT[self.insta_mode],350, self.NFB_INFO_HEIGHT,200, 65 + list_count*(8+self.NFB_INFO_HEIGHT), border_size=12) def update_complete(self, insta_complete): self.insta_complete = insta_complete def update_betas(self, raw_betas): self.raw_betas = raw_betas if self.raw_betas['constant'] != 0: for k,v in self.psc_betas.iteritems(): self.psc_betas[k] = 100*self.raw_betas[k]/self.raw_betas['constant'] gc.set_control_limits(self, self.psc_betas) def update_control_targets(self, u_vec): self.u_vec = self.u_vec + u_vec u_vec_reduced = np.ravel(self.u_vec) u_vec_reduced = u_vec_reduced[0:self.N_ACTIVE_TIME] self.next_mvc_list, self.next_phase_list = gc.betas_to_mvc_phase(self, self.psc_betas, u_vec_reduced) self.next_target_loc_list = self.gen_target_list(self.next_mvc_list, self.next_phase_list) self.set_targets(self.next_target_loc_list) def calc_y_psc(self): trial_num = self.timers['trial'].count-1 begin_rest_idx = trial_num*self.TRIAL_TIME['nfb'] + self.BASELINE_CALC_SHIFT end_rest_idx = begin_rest_idx + self.PRE_REST_TIME['nfb'] - self.BASELINE_CALC_SHIFT + self.INTRO_TIME['nfb'] begin_move_idx = end_rest_idx end_move_idx = begin_move_idx + self.ACTIVE_TIME['nfb'] + 1 rest_mean = 10e-9+np.mean(self.bold_rois_array[0][begin_rest_idx:end_rest_idx]) y_vec_psc = (100*(self.bold_rois_array[0][begin_move_idx:end_move_idx]-rest_mean) /rest_mean) self.y_vec[0:self.N_ACTIVE_TIME] = y_vec_psc[0:self.N_ACTIVE_TIME] self.y_vec[self.N_ACTIVE_TIME:] = np.mean(y_vec_psc[self.N_ACTIVE_TIME - self.ADD_CONTROL_TRS :self.N_ACTIVE_TIME]) def gen_control_targets(self, psc_target): u_vec = gc.calc_control(self, psc_target) u_vec_reduced = u_vec[0:self.N_ACTIVE_TIME] mvc_list, phase_list = gc.betas_to_mvc_phase(self, self.psc_betas, u_vec_reduced) return self.gen_target_list(mvc_list, phase_list) def update_mode(self, mode): self.insta_mode = mode def increment_target(self): self.current_target = self.current_target.next_target def draw_background(self): self.screen.fill(self.bg_color) if self.run_mode == 'idle' and self.loc == 'lab': instr_msg = ('Press Space for Run ' + str(self.trial_type_count+1) + ' of ' + str(self.TRIAL_TYPES)) gg.draw_msg(self.screen, instr_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .5*self.SCREEN_HEIGHT), size=48) if self.next_run_msg != '': gg.draw_msg(self.screen, self.next_run_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .4*self.SCREEN_HEIGHT), size=48) def quit(self): self.requests_running_bool.value = 0 self.requests_process.join() sys.exit()
class SequenceGame(object): def __init__(self): gi.generate_constants(self) gi.generate_variables(self) pygame.init() pygame.mouse.set_visible(not pygame.mouse.set_visible) self.clock = pygame.time.Clock() if SENSOR_ACTIVE: self.daq = Pydaq(self.ANALOG_IN_CHANS, self.DIGITAL_OUT_CHANS, self.FRAME_RATE, self.LP_FILT_FREQ, self.LP_FILT_ORDER, self.FORCE_PARAMS) if self.CONFIG['sensor-type'] == 'optical': self.daq.set_volts_zero_init() if self.CONFIG['fullscreen']: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.FULLSCREEN) else: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) def check_input(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.quit() elif event.key == pygame.K_0: self.daq.set_volts_zero() elif event.key == pygame.K_m: if self.input_mode == 'keyboard': self.input_mode = 'sensor' elif self.input_mode == 'sensor': self.input_mode = 'keyboard' elif event.key == pygame.K_n: self.show_keyboard = not(self.show_keyboard) elif ((event.key == pygame.K_SPACE or event.key == pygame.K_5) and not(self.run_trials)): self.run_trials = True if SENSOR_ACTIVE: self.daq.set_digital_out(1) gr.reset_for_next_run(game) elif event.key == pygame.K_p: self.run_trials = False elif event.key == pygame.K_d: self.debug_bool = not(self.debug_bool) elif event.key == pygame.K_LEFT: self.set_run('debug') elif event.key == pygame.K_RIGHT: self.set_run('test') elif event.key == pygame.K_UP: self.set_run('train') elif event.key == pygame.K_DOWN: self.set_run('scan') if self.input_mode == 'keyboard': if event.key == self.key_codes[0]: self.keydown[0] = True elif event.key == self.key_codes[1]: self.keydown[1] = True elif event.key == self.key_codes[2]: self.keydown[2] = True elif event.key == self.key_codes[3]: self.keydown[3] = True elif event.key == self.key_codes[4]: self.keydown[4] = True elif event.type == pygame.KEYUP: if self.input_mode == 'keyboard': if event.key == self.key_codes[0]: self.keydown[0] = False elif event.key == self.key_codes[1]: self.keydown[1] = False elif event.key == self.key_codes[2]: self.keydown[2] = False elif event.key == self.key_codes[3]: self.keydown[3] = False elif event.key == self.key_codes[4]: self.keydown[4] = False if self.input_mode == 'sensor': self.force_array[:] = self.daq.get_force() self.keydown[:] = self.force_array > self.KEYPRESS_FORCE self.keepunder[:] = self.force_array < self.KEEP_UNDER_FORCE def check_key_status(self): if self.keydown.count(True) == 0: self.current_key = 'none' self.last_key_pressed = -1 elif self.keydown.count(True) == 1 and self.keepunder.count(True) >= 4: self.current_key = self.keydown.index(True)+1 def set_run(self, mode): self.run_count = 0 self.mode = mode self.sequences_per_trial = self.SEQUENCES_PER_TRIAL[mode] self.trials_per_run = self.TRIALS_PER_RUN[mode] self.runs_per_experiment = self.RUNS_PER_EXPERIMENT[mode] self.timers['score'] = Timer(self.FEEDBACK_TIME, self.sequences_per_trial) if self.mode == 'scan': self.self_paced_bool = False else: self.self_paced_bool = True if game.mode == 'debug' or game.mode == 'train': game.sequence_set = game.TRAIN_SEQUENCES elif game.mode == 'test' or game.mode == 'scan': game.sequence_set = game.TEST_SEQUENCES def set_sequences(self): if self.mode == 'scan': self.sequence_list = [] temp_sequence_set = game.sequence_set for block in range(4): np.random.shuffle(temp_sequence_set) for sequence in temp_sequence_set: self.sequence_list.append(sequence) elif self.mode == 'test': self.sequence_list = self.sequence_set[:-1] np.random.shuffle(game.sequence_list) else: self.sequence_list = self.sequence_set np.random.shuffle(game.sequence_list) def run(self): while True: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.check_key_status() self.draw_background() if self.show_keyboard: gg.draw_keyboard(self) if self.run_trials: fu.frame_record(game, game.f_frame, time_passed) gg.draw_frame_rectangle(self) if not(self.timers['cue'].time_limit_hit): self.timers['cue'].update(time_passed) gr.run_sequence_cue(self) elif not(self.current_sequence_complete): self.timers['move'].update(time_passed) if not(self.self_paced_bool): self.timers['move_limit'].update(time_passed) if self.timers['move_limit'].time_limit_hit: self.current_sequence_complete = True gr.run_sequence_move(self) elif (not(self.self_paced_bool) and not(self.timers['move_limit'].time_limit_hit)): self.timers['move_limit'].update(time_passed) gg.draw_sequence_progress(self) elif not(self.timers['score'].time_limit_hit): self.timers['score'].update(time_passed) if game.current_sequence == game.REST_SEQUENCE: gr.run_sequence_score_rest(self) else: gr.run_sequence_score(self) elif not(self.timers['score'].count_limit_hit): gr.reset_for_next_sequence_execution(self) elif self.trial_count < self.trials_per_run: gr.reset_for_next_sequence_trial(self) else: self.run_trials = False if SENSOR_ACTIVE: self.daq.set_digital_out(0) else: self.draw_splash() if self.debug_bool: self.draw_debug(time_passed) pygame.display.flip() def draw_background(self): self.screen.fill(self.BG_COLOR) def draw_splash(self): if game.run_count < game.runs_per_experiment: splash_msg = ('Ready for Run ' + str(game.run_count+1) + ' of ' + str(game.runs_per_experiment)) else: splash_msg = ('Done!') gg.draw_msg(self.screen, splash_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .5*self.SCREEN_HEIGHT), size=50) gg.draw_msg(self.screen, ('mode: ' + game.mode), loc='right', pos=(.975*self.SCREEN_WIDTH, .05*self.SCREEN_HEIGHT), size=24) if game.run_count > 0: points_msg = ('Points this run: ' + str(game.points_total)) time_msg = ('Average movement time: ' + str(round(np.mean( game.execution_time_array)/1000.,2)) + ' seconds') error_rate = np.mean(game.error_array) error_msg = ('Percent errors: ' + str(round(100*error_rate,1)) + '%') if game.run_count < game.runs_per_experiment: if error_rate > game.ERROR_CUTOFF: advice_msg = 'For the next run, try slowing down.' else: advice_msg = 'For the next run, try going faster.' else: advice_msg = '' if game.mode != 'scan': gg.draw_msg(self.screen, points_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .6*self.SCREEN_HEIGHT), size=35) gg.draw_msg(self.screen, time_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .7*self.SCREEN_HEIGHT), size=35) gg.draw_msg(self.screen, error_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .8*self.SCREEN_HEIGHT), size=35) gg.draw_msg(self.screen, advice_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .9*self.SCREEN_HEIGHT), size=35) def draw_debug(self, time_passed): fr = 1000/float(time_passed) fr_msg = 'frame rate: ' + str(fr) gg.draw_msg(self.screen, fr_msg, loc='left', pos=(10,33), size=28) force = self.daq.get_force() volt_msg_1 = 'out_volt_1: ' + str(force[0]) volt_msg_2 = 'out_volt_2: ' + str(force[1]) gg.draw_msg(self.screen, volt_msg_1, loc='left', pos=(10,66), size=28) gg.draw_msg(self.screen, volt_msg_2, loc='left', pos=(10,99), size=28) def quit(self): sys.exit()
class Game(object): def __init__(self): gi.generate_constants(self) gi.generate_variables(self) pygame.init() pygame.mouse.set_visible(not pygame.mouse.set_visible) self.clock = pygame.time.Clock() if SENSOR_ACTIVE: self.daq = Pydaq(self.DEVICE_NAME, self.FRAME_RATE, self.LP_FILT_FREQ, self.LP_FILT_ORDER, self.FORCE_PARAMS) if self.CONFIG['fullscreen']: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.FULLSCREEN) else: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) def check_input(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.quit() elif ((event.key == pygame.K_SPACE or event.key == pygame.K_5) and not(self.run_trials)): self.run_trials = True gr.reset_for_next_run(game) elif event.key == pygame.K_p: self.run_trials = False elif event.key == pygame.K_q: if not(SENSOR_ACTIVE): self.force_array[0] = self.PRESS_FORCE_THRESHOLD elif event.key == pygame.K_w: if not(SENSOR_ACTIVE): self.force_array[1] = self.PRESS_FORCE_THRESHOLD elif event.key == pygame.K_e: if not(SENSOR_ACTIVE): self.force_array[2] = self.PRESS_FORCE_THRESHOLD elif event.key == pygame.K_r: if not(SENSOR_ACTIVE): self.force_array[3] = self.PRESS_FORCE_THRESHOLD elif event.key == pygame.K_m: self.show_thermometer_keyboard_bool = not( self.show_thermometer_keyboard_bool) elif event.key == pygame.K_LEFT: self.set_run('debug') elif event.key == pygame.K_RIGHT: self.set_run('test') elif event.key == pygame.K_UP: self.set_run('train') elif event.key == pygame.K_DOWN: self.set_run('scan') elif event.type == pygame.KEYUP: if event.key == pygame.K_q: if not(SENSOR_ACTIVE): self.force_array[0] = self.MIN_KEY_FORCE elif event.key == pygame.K_w: if not(SENSOR_ACTIVE): self.force_array[1] = self.MIN_KEY_FORCE elif event.key == pygame.K_e: if not(SENSOR_ACTIVE): self.force_array[2] = self.MIN_KEY_FORCE elif event.key == pygame.K_r: if not(SENSOR_ACTIVE): self.force_array[3] = self.MIN_KEY_FORCE if SENSOR_ACTIVE: self.check_keys() def check_keys(self): self.force_array[:] = self.daq.get_force() def set_run(self, mode): self.run_count = 0 self.mode = mode self.trials_per_run = self.TRIALS_PER_RUN[mode] self.runs_per_experiment = self.RUNS_PER_EXPERIMENT[mode] gi.init_timers(self) def set_fingers(self): game.finger_list = [] for block in range(game.trials_per_run/len(game.VALID_FINGERS_LIST)): np.random.shuffle(game.VALID_FINGERS_LIST) game.finger_list += game.VALID_FINGERS_LIST def draw_splash(self): if game.run_count < game.runs_per_experiment: splash_msg = ('Ready for Run ' + str(game.run_count+1) + ' of ' + str(game.runs_per_experiment)) else: splash_msg = ('Done!') gg.draw_msg(self.screen, splash_msg, loc='center', pos=(.5*self.SCREEN_WIDTH, .5*self.SCREEN_HEIGHT), size=50) gg.draw_msg(self.screen, ('mode: ' + game.mode), loc='right', pos=(.975*self.SCREEN_WIDTH, .05*self.SCREEN_HEIGHT), size=24) # can add scoring message here # if game.run_count > 0: # points_msg = ('Points this run: ' + str(game.points_total)) # gg.draw_msg(self.screen, points_msg, # loc='center', pos=(.5*self.SCREEN_WIDTH, # .6*self.SCREEN_HEIGHT), size=35) def run(self): while True: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.draw_background() if self.show_thermometer_keyboard_bool: gg.draw_keyboard(game, 'debug') if self.run_trials: if not(self.timers['rest'].time_limit_hit): self.timers['rest'].update(time_passed) gr.run_rest(self) elif not(self.timers['cue'].time_limit_hit): self.timers['cue'].update(time_passed) gr.run_cue(self) elif not(self.current_press_complete): if not(self.ready_for_press): gr.run_rest(self) if (self.force_array[self.current_finger] < self.PRESS_FORCE_KEEP_BELOW): self.ready_for_press = True else: self.timers['press_limit'].update(time_passed) gr.run_press(self) # elif self.mode == 'test': # if not(self.timers['press_limit'].time_limit_hit): # self.timers['press_limit'].update(time_passed) # gr.run_rest(self) # elif not(self.timers['press_limit'].count_limit_hit): # gr.reset_for_next_press(self) # elif self.trial_count < self.trials_per_run: # gr.reset_for_next_trial(self) # else: # self.run_trials = False # elif self.mode == 'train': # if not(self.timers['feedback'].time_limit_hit): # self.timers['feedback'].update(time_passed) # gr.run_feedback(self) # elif not(self.timers['feedback'].count_limit_hit): # gr.reset_for_next_press(self) # elif self.trial_count < self.trials_per_run: # gr.reset_for_next_trial(self) # else: # self.run_trials = False elif not(self.timers['feedback'].time_limit_hit): self.timers['feedback'].update(time_passed) gr.run_feedback(self) elif not(self.timers['feedback'].count_limit_hit): gr.reset_for_next_press(self) elif self.trial_count < self.trials_per_run: gr.reset_for_next_trial(self) else: self.run_trials = False else: self.draw_splash() pygame.display.flip() def draw_background(self): self.screen.fill(self.BG_COLOR) def quit(self): sys.exit()
class Trainer(object): def __init__(self): ############### # load config # ############### with open('trainer_config.yaml') as f: CONFIG = yaml.load(f) self.exp_type = CONFIG['experiment-type'] self.playback_bool = CONFIG['playback-enabled'] self.subj_id = CONFIG['subject-id'] self.subj_dir = 'datasets/' + self.subj_id if self.exp_type == 'timed': fu.write_all_headers_timed(self) elif self.exp_type == 'block': fu.write_all_headers_block(self) ################# # set constants # ################# self.FRAME_RATE = 30 self.SCREEN_WIDTH, self.SCREEN_HEIGHT = 1024, 768 self.BG_COLOR_REG = 70,70,70 self.BG_COLOR_REG_2 = 110,110,110 self.BG_COLOR_REG_3 = 40,40,40 self.SUCCESS_COLOR = 70,170,70 self.INDICATOR_COLOR = 40,60,40 self.INDICATOR_COLOR_2 = 30,100,30 self.GOOD_MSG_COLOR = 160,255,160 self.BAD_MSG_COLOR = 255,160,160 self.A_MSG_COLOR = 160,160,255 self.B_MSG_COLOR = 230,230,160 self.SENSOR_INPUT_OFFSET = np.array([0.5*self.SCREEN_WIDTH, 0.5*self.SCREEN_HEIGHT]) self.NEWTONS_2_PIXEL = 200 self.BLOCK_TIME = CONFIG['block-length'] self.RESET_HOLD_TIME = 0.5 self.REACH_SUCCESS_TIME = 2. self.NOISE_VAR_GOOD = 0.025 if not self.playback_bool: self.NOISE_VAR_BAD = 10*self.NOISE_VAR_GOOD else: self.NOISE_VAR_BAD = self.NOISE_VAR_GOOD self.SAMPLE_PERIOD = 2. self.SAMPLE_FRAMES = self.SAMPLE_PERIOD*self.FRAME_RATE self.TRS_SHOW_UPDATE_RATE = 2 self.TR_LIST = (0.125, .25, 0.5, 1., 2., 4.) self.TRS_SAMPLES_DICT = dict((tr, tr/self.SAMPLE_PERIOD) for tr in self.TR_LIST) self.TRS_SUCCESS_DICT = dict((tr, self.REACH_SUCCESS_TIME/tr) for tr in self.TR_LIST) self.BUFFER_DIST = 0.075*self.SCREEN_HEIGHT self.START_DIST = self.BUFFER_DIST self.GAME_ORIGIN = (0.5*self.SCREEN_WIDTH-0.5*self.SCREEN_HEIGHT, self.SCREEN_HEIGHT) self.START_COORDS = np.array([self.GAME_ORIGIN[0]+self.BUFFER_DIST, self.GAME_ORIGIN[1]-self.BUFFER_DIST]) self.TARGET_DIST = (0.3*self.SCREEN_HEIGHT, 0.8*self.SCREEN_HEIGHT) self.ERROR_CUTOFF = self.TARGET_DIST[0] - self.START_DIST self.MIN_ERROR_METRIC = 0.1 self.SS_ERROR_METRIC = 0.9 self.MIN_SUCCESS_SCORE = 0.7 self.TARGET_RAD = (self.ERROR_CUTOFF* (1-(self.MIN_SUCCESS_SCORE-self.MIN_ERROR_METRIC) /(self.SS_ERROR_METRIC-self.MIN_ERROR_METRIC))) if SENSOR_ACTIVE: self.daq = Pydaq('Dev1/ai0:1', self.FRAME_RATE) self.VISIBLE_TRIALS = CONFIG['visible-trials'] self.INVISIBLE_TRIALS = CONFIG['invisible-trials'] self.NUM_TRIALS = self.VISIBLE_TRIALS self.TRIAL_TYPES = 8 #################################################### # start pygame and initialize default game objects # #################################################### pygame.init() pygame.mouse.set_visible(not pygame.mouse.set_visible) self.clock = pygame.time.Clock() if CONFIG['fullscreen']: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.FULLSCREEN) else: self.screen = pygame.display.set_mode( (self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) ################################## # initialize custom game objects # ################################## self.cursor = Cursor(self.screen) self.target = Target(self.screen, self.FRAME_RATE, self.TARGET_RAD, self.ERROR_CUTOFF, self.MIN_ERROR_METRIC, self.SS_ERROR_METRIC, self.MIN_SUCCESS_SCORE, self.START_COORDS, self.TARGET_DIST) self.therm = Thermometer(self.screen, self.MIN_ERROR_METRIC, self.MIN_SUCCESS_SCORE, self.SS_ERROR_METRIC) self.INDIC_RAD_MAX = self.START_DIST-self.cursor.RAD-2 self.target.target_lims = self.TARGET_DIST self.timers = {} self.init_timers() self.set_tr(2.) self.trial_count = 0 self.trial_type_count = 1 self.next_dof = 1 self.set_dof(self.next_dof) self.next_ir = 'impulse' self.next_visible = True self.set_trial() ###################### # set game variables # ###################### self.screen_mid = np.array([0.5*self.screen.get_width(), 0.5*self.screen.get_height()]) self.bg_color = self.BG_COLOR_REG self.bg_color_alt = self.BG_COLOR_REG_2 self.bg_color_alt_2 = self.BG_COLOR_REG_3 self.indicator_color = self.INDICATOR_COLOR self.indicator_rad = 0*self.START_DIST self.success_color = self.SUCCESS_COLOR self.input_mode = 'mouse' self.input_pos = np.array([0.0,0.0]) self.training_mode = True ####################### # set block variables # ####################### self.NUM_BLOCK_TRIALS = CONFIG['num-block-trials'] self.next_target = 'new' self.first_feedback = CONFIG['first-trial-feedback'] self.first_noise = CONFIG['first-trial-noise'] self.next_feedback = self.first_feedback self.next_noise = self.first_noise self.set_noise() self.BLOCK_TRS = self.BLOCK_TIME/self.tr self.block_nfb_buffer = np.zeros(self.BLOCK_TRS) self.block_tr_count = 0 self.total_block_count = 0 self.trial_block_count = 0 ########################## # set playback variables # ########################## self.TIME_SHIFT = 6 self.PLAYBACK_TRS = self.BLOCK_TRS + self.TIME_SHIFT/self.tr self.EXTRA_TRS = 2 self.playback_buffer_length = (self.BLOCK_TIME + self.EXTRA_TRS)*self.FRAME_RATE self.move_counter = 0 self.reset_playback_buffers() def reset_playback_buffers(self): self.playback_counter = 0 self.playback_time_buffer = np.zeros(self.playback_buffer_length) self.playback_pos_buffer = np.zeros((2,self.playback_buffer_length)) self.playback_nfb_buffer = np.zeros(self.playback_buffer_length) self.playback_nfb_points = np.zeros(self.PLAYBACK_TRS) def get_pos(self): if self.input_mode=='mouse' or not(SENSOR_ACTIVE): return pygame.mouse.get_pos() else: f_out = self.daq.get_force() return (self.SENSOR_INPUT_OFFSET[0]+self.NEWTONS_2_PIXEL*f_out[0], self.SENSOR_INPUT_OFFSET[1]+self.NEWTONS_2_PIXEL*f_out[1]) def set_trial(self): self.set_dof(self.next_dof) self.target.set_fb_mode(self.next_ir) self.set_training_mode(self.next_visible) def set_noise(self): if self.next_noise == 'good': self.noise_var = self.NOISE_VAR_GOOD elif self.next_noise == 'bad': self.noise_var = self.NOISE_VAR_BAD def set_training_mode(self, bool_arg): self.training_mode = bool_arg def set_tr(self, tr): if tr == 0.125: self.tr = 0.125 self.timers['tr'] = self.timers['tr_8hz'] elif tr == 0.25: self.tr = 0.25 self.timers['tr'] = self.timers['tr_4hz'] elif tr == 0.5: self.tr = 0.5 self.timers['tr'] = self.timers['tr_2hz'] elif tr == 1: self.tr = 1. self.timers['tr'] = self.timers['tr_1hz'] elif tr == 2: self.tr = 2. self.timers['tr'] = self.timers['tr_p5hz'] elif tr == 4: self.tr = 4. self.timers['tr'] = self.timers['tr_p25hz'] def init_timers(self): self.timers['signal'] = Timer(self.SAMPLE_PERIOD) self.timers['tr_8hz'] = Timer(self.TR_LIST[0]) self.timers['tr_4hz'] = Timer(self.TR_LIST[1]) self.timers['tr_2hz'] = Timer(self.TR_LIST[2]) self.timers['tr_1hz'] = Timer(self.TR_LIST[3]) self.timers['tr_p5hz'] = Timer(self.TR_LIST[4]) self.timers['tr_p25hz'] = Timer(self.TR_LIST[5]) self.timers['tr'] = self.timers['tr_2hz'] self.timers['reach'] = Timer(0) self.timers['reach_hold'] = Timer(self.REACH_SUCCESS_TIME) self.timers['block'] = Timer(self.BLOCK_TIME) self.timers['reset_hold'] = Timer(self.RESET_HOLD_TIME) def reset_all_timers(self): for k,t in self.timers.iteritems(): t.reset() def check_input(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.quit() elif event.key == pygame.K_0: self.daq.set_volts_zero() elif event.key == pygame.K_f: if self.dof == 1: self.set_dof(2) elif self.dof == 2: self.set_dof(1) elif event.key == pygame.K_b: self.target.set_new_target() elif event.key == pygame.K_v: self.training_mode = not(self.training_mode) elif event.key == pygame.K_c: self.target.set_fb_mode('hrf') elif event.key == pygame.K_x: self.target.set_fb_mode('impulse') elif event.key == pygame.K_m: if self.input_mode == 'mouse': self.input_mode = 'sensor' elif self.input_mode == 'sensor': self.input_mode = 'mouse' def run_timed(self): ########################################### # main loop for time-to-target experiment # ########################################### while True: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.input_pos = self.get_pos() self.cursor.update(self.input_pos) self.target.update(self.cursor.pos) if not(self.timers['reset_hold'].time_limit_hit): gr.check_in_start(self, time_passed) self.target.draw_bool = True elif not(self.cursor.has_left): gr.check_if_left(self) self.target.draw_bool = False elif self.training_mode: self.target.draw_bool = True else: self.target.draw_bool = False if self.cursor.has_left: gr.frame_based_updates_timed(self) self.timers['signal'].update(time_passed) self.timers['tr'].update(time_passed) if self.timers['signal'].time_limit_hit: gr.signal_based_updates(self) if self.timers['tr'].time_limit_hit: gr.tr_based_updates(self) self.draw_background() self.therm.draw(self.cursor.has_left, self.target.error_metric) self.target.draw() if (self.trial_count == 0 and not self.cursor.has_left): self.draw_instructions_timed() self.cursor.draw() pygame.display.flip() def run_block(self): ########################################### # main loop for block feedback experiment # ########################################### self.target.draw_bool = False if self.playback_bool: self.set_dof(2) else: self.set_dof(1) self.target.set_fb_mode('hrf') while True: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.input_pos = self.get_pos() self.cursor.update(self.input_pos) self.target.update(self.cursor.pos) if not(self.timers['reset_hold'].time_limit_hit): gr.check_in_start(self, time_passed) if self.next_target == 'new': self.target.draw_bool = True elif not(self.cursor.has_left): gr.check_if_left(self) self.target.draw_bool = False # debugging # self.target.draw_bool = True if self.cursor.has_left: gr.frame_based_updates_block(self) self.timers['signal'].update(time_passed) self.timers['tr'].update(time_passed) self.timers['block'].update(time_passed) if self.timers['signal'].time_limit_hit: gr.signal_based_updates(self) if self.timers['tr'].time_limit_hit: gr.tr_based_updates(self) if self.timers['block'].time_limit_hit: gr.block_based_updates(self) self.draw_background() therm_draw_bool = ((self.cursor.has_left and self.next_feedback == 'continuous') or (self.total_block_count > 0 and not self.cursor.has_left)) score = self.target.error_metric self.therm.draw(therm_draw_bool, score) self.target.draw() if not self.cursor.has_left: self.draw_instructions_block() else: self.therm.set_score_color('norm') self.cursor.draw() pygame.display.flip() def run_playback(self): while self.move_counter > 0: time_passed = self.clock.tick_busy_loop(self.FRAME_RATE) self.check_input() self.cursor.update(self.playback_pos_buffer[:, self.playback_counter]) self.indicator_rad = int(self.INDIC_RAD_MAX*( self.playback_time_buffer[self.playback_counter] /float(self.timers['block'].MAX_TIME))) self.draw_background() self.therm.draw(True, self.playback_nfb_buffer[self.playback_counter]) # debugging # self.target.draw() self.cursor.draw() pygame.display.flip() self.move_counter -= 1 self.playback_counter += 1 def set_dof(self, dof): self.dof = dof self.cursor.set_dof(dof) self.target.set_dof(dof) def draw_background(self): self.screen.fill(self.bg_color_alt_2) gr.cap_indicator_rad(self) self.draw_play_area() if self.indicator_rad > 0: self.draw_indicator() def draw_instructions_block(self): if self.next_target == 'new': top_msg = 'New target' top_color = self.GOOD_MSG_COLOR else: top_msg = 'Same target' top_color = self.BAD_MSG_COLOR if self.next_feedback == 'continuous': mid_msg = 'Continuous feedback' mid_color = self.A_MSG_COLOR else: mid_msg = 'Intermittent feedback' mid_color = self.B_MSG_COLOR if self.next_noise == 'good': btm_msg = 'Good signal' btm_color = self.A_MSG_COLOR else: btm_msg = 'Bad signal' btm_color = self.B_MSG_COLOR gg.draw_msg(self.screen, top_msg, color=top_color, center=(self.screen_mid[0], self.screen_mid[1]-75)) gg.draw_msg(self.screen, mid_msg, color=mid_color, center=(self.screen_mid[0], self.screen_mid[1])) if not self.playback_bool: gg.draw_msg(self.screen, btm_msg, color=btm_color, center=(self.screen_mid[0], self.screen_mid[1]+75)) def draw_instructions_timed(self): if self.next_visible: top_msg = 'Target visible' top_color = self.GOOD_MSG_COLOR else: top_msg = 'Target invisible' top_color = self.BAD_MSG_COLOR if self.next_ir == 'impulse': btm_msg = 'Instant feedback' btm_color = self.GOOD_MSG_COLOR else: btm_msg = 'Delayed feedback' btm_color = self.BAD_MSG_COLOR gg.draw_msg(self.screen, top_msg, color=top_color, center=(self.screen_mid[0], self.screen_mid[1]-50)) gg.draw_msg(self.screen, btm_msg, color=btm_color, center=(self.screen_mid[0], self.screen_mid[1]+50)) def draw_play_area(self): if self.dof == 1: gg.draw_center_rect(self.screen, self.SCREEN_HEIGHT, self.SCREEN_HEIGHT, self.bg_color, self.screen_mid[0], self.screen_mid[1]) gg.draw_center_rect(self.screen, self.TARGET_DIST[1]-self.TARGET_DIST[0], self.SCREEN_HEIGHT, self.bg_color_alt, (self.TARGET_DIST[0] +0.5*(self.TARGET_DIST[1] -self.TARGET_DIST[0]) + self.START_COORDS[0]), self.screen_mid[1]) gg.draw_center_rect(self.screen, 2*(self.START_DIST-self.cursor.RAD), self.SCREEN_HEIGHT, self.bg_color_alt_2, self.START_COORDS[0], self.screen_mid[1]) elif self.dof == 2: gg.draw_center_rect(self.screen, self.SCREEN_HEIGHT, self.SCREEN_HEIGHT, self.bg_color, self.screen_mid[0], self.screen_mid[1]) gg.draw_filled_aacircle(self.screen, self.TARGET_DIST[1], self.bg_color_alt, self.START_COORDS[0], self.START_COORDS[1]) gg.draw_filled_aacircle(self.screen, self.TARGET_DIST[0], self.bg_color, self.START_COORDS[0], self.START_COORDS[1]) gg.draw_center_rect(self.screen, self.SCREEN_HEIGHT, 2*self.BUFFER_DIST, self.bg_color, self.screen_mid[0], self.GAME_ORIGIN[1]) gg.draw_center_rect(self.screen, 2*self.BUFFER_DIST, self.SCREEN_HEIGHT, self.bg_color, self.GAME_ORIGIN[0], self.screen_mid[1]) gg.draw_filled_aacircle(self.screen, self.START_DIST-self.cursor.RAD, self.bg_color_alt_2, self.START_COORDS[0], self.START_COORDS[1]) def draw_indicator(self): if self.dof == 1: gg.draw_center_rect(self.screen, 2*self.indicator_rad, self.SCREEN_HEIGHT, self.indicator_color, self.START_COORDS[0], self.screen_mid[1]) elif self.dof == 2: gg.draw_filled_aacircle(self.screen, self.indicator_rad, self.indicator_color, self.START_COORDS[0], self.START_COORDS[1]) def quit(self): sys.exit()