REM Concurrent Random Interval schedule REM REM Nathaniel Daw REM daw@cs.cmu.edu REM REM 16 July 1998 REM Run two different random interval schedules; one on each lever REM Each lever can have a different reinforcer and there is a REM changeover delay. REM Most of the complexity of this program comes from tracking REM lots and lots of statistics. REM Also, there is some trickiness involved when the two (more or REM less) independent programs running in each box contend for REM shared resources, like the tray flap. REM 3 Nov 99 - some sort of modification by RNC for RHQ REM - pump to be assoc. with magazine light OR clicker OR neither REM - dipper to be independently assoc. with m.l. OR clicker OR neither REM - pump/dipper are counterbalanced L/R already REM At present, pump=clicker and dipper=stimulus light (stim light not equal to mag light!) REM So let's define ... REM PROCpump_on and PROCdipper_on do the business REM magazine_light%(,) is new REM REM SWITCHING REM * p(A | B) denotes p(A) given that B has just happened REM * we already know how long a slice is REM * we already know how many L and R presses per slice -> responses/time (L, R, or total) REM * want # switches L->R (when L not reinforced) -> 1. switches/time (L->R, R->L or total) REM * want # switches R->L (when R not reinforced) 2. p(R | L unreinf) = (#L->R switches) / (#L responses - #L reinf) REM and p(L | R unreinf) REM 3. p(L | L unreinf) = 1 - p(R | L unreinf) REM and p(R | R unreinf) REM REM and those probabilities give you #switches/resp or #resp/(switch+1) (chain length) REM REM N.B. If you have 40 responses and 3 switches, you have 4 chains (av. chain length 10). REM So chain length = #resp / (#switches + 1). REM p(switch) = 3/40. (Meets an end-of-session problem; you can't know if the rat would have kept on switching.) REM REM One v. both levers: REM chain length on L lever = (#responses on L lever) / (#switches(L->R) + 1) REM chain length on average = (#responses on both) / (#switches(L->R + R->L) + 1) REM REM * We ignore session ends... REM * We hope ND has handled slice ends for latency purposes... REM REM * want # L resp after L reinf -> gives p(L | L reinf), etc. REM # R L REM # R R REM # L R REM REM WHAT HAPPENS WHEN TIMESLICE (OR SESSION) ENDS: REM The recording continues into the next timeslice. REM So if you get reinf -> //slice// -> leverpress, REM that leverpress (be it chain or switch) is recorded in the second timeslice, REM even though the reinforcer is recorded in the first. REM Bear this in mind if you want to be finicky about p(switch | reinf). REM i.e. this error makes every switch measure +/- 1 at worst. REM ************************************************************** REM ******************** Declare some arrays ********************* REM ************************************************************** @%="g6.6" REM get the number of timeslices right away, because we can't REM initialize any of the arrays till we know how big it is! default_num_timeslices% = 10 CLS PRINT "Number of timeslices: ("; default_num_timeslices%; ") "; num_timeslices% = FNread_input(default_num_timeslices%, 30, 0) num_boxes% = 6 num_levers% = 2 num_rewards% = 2 DIM subject$(num_boxes%) DIM session%(num_boxes%) REM config information DIM session_length%(num_boxes%) DIM random_interval%(num_boxes%, num_levers%) DIM collection_duration%(num_boxes%, num_rewards%) DIM reinf_duration%(num_boxes%, num_rewards%) DIM max_reinfs%(num_boxes%, num_levers%) DIM changeover_delay%(num_boxes%) DIM reinforcer%(num_boxes%, num_levers%) DIM stimulus%(num_boxes%, num_rewards%) :REM ******* RNC REM default configurations DIM default_collection_duration%(num_rewards%) DIM default_reinf_duration%(num_rewards%) DIM default_stimulus%(num_rewards%) :REM ******* RNC DIM default_reinforcer%(num_levers%) DIM default_random_interval%(num_levers%) DIM default_max_reinfs%(num_levers%) REM arrays to track state of experiment REM all of these are broken down by box REM many of these are broken down by side REM and many are also broken down by timeslice REM whether boxes and levers are running or done DIM lever_state%(num_boxes%, num_levers%) DIM state%(num_boxes%) REM which of the stat timeslices are we in DIM timeslice%(num_boxes%) REM time of last reinforcement and earliest REM possible time of next reinforcement DIM last_reinf_time%(num_boxes%, num_levers%, num_timeslices%) DIM next_reinf_time%(num_boxes%, num_levers%) REM reinforcement is available if this flag is true REM and the current time is after next_reinf_time% REM (this flag will be false between trials to REM block further reinforced lever presses while REM the previous lever press is still being reinforced) DIM reinf_available%(num_boxes%, num_levers%) REM time of last press DIM last_press_time%(num_boxes%, num_levers%, num_timeslices%) REM switches to a different lever DIM switch_press%(num_boxes%, num_levers%) REM time experiment ends DIM timeout_time%(num_boxes%) REM are we waiting for collection of reward? DIM waiting_for_collection%(num_boxes%, num_levers%, num_timeslices%) REM whether the next press interval will be counted REM toward post-reward response intervals on the REM same or any lever. DIM waiting_any_response%(num_boxes%, num_levers%, num_timeslices%) DIM waiting_same_response%(num_boxes%, num_levers%, num_timeslices%) REM are we using the pump or dipper? DIM running_pump%(num_boxes%, num_levers%) DIM running_dipper%(num_boxes%, num_levers%) REM arrays to collect stats: one is a running REM sum of values to be averaged, the other the REM count of values to divide by. REM latency to response on any lever after reward DIM summed_any_rews%(num_boxes%, num_levers%, num_timeslices%) DIM num_any_rews%(num_boxes%, num_levers%, num_timeslices%) REM latency to response on same lever after reward DIM summed_same_rews%(num_boxes%, num_levers%, num_timeslices%) DIM num_same_rews%(num_boxes%, num_levers%, num_timeslices%) REM latency to collection DIM summed_coll_latencies%(num_boxes%, num_levers%, num_timeslices%) DIM num_collected%(num_boxes%, num_levers%, num_timeslices%) REM iris on same lever DIM summed_same_iris%(num_boxes%, num_levers%, num_timeslices%) DIM num_same_iris%(num_boxes%, num_levers%, num_timeslices%) REM iris on any lever DIM summed_any_iris%(num_boxes%, num_timeslices%) DIM num_any_iris%(num_boxes%, num_timeslices%) REM l/r presses per l/r reinforcement DIM summed_same_pprs%(num_boxes%, num_levers%, num_timeslices%) REM total presses per reinforcement DIM summed_any_pprs%(num_boxes%, num_timeslices%) REM the number of same-side presses or any presses since last reinforcement DIM num_same_pslrs%(num_boxes%, num_levers%, num_timeslices%) DIM num_any_pslrs%(num_boxes%, num_timeslices%) REM number of presses, reinforcements, omissions DIM num_presses%(num_boxes%, num_levers%, num_timeslices%) DIM num_reinfs%(num_boxes%, num_levers%, num_timeslices%) DIM num_omissions%(num_boxes%, num_levers%, num_timeslices%) DIM sl_num_presses%(num_boxes%, num_levers%, num_timeslices%) DIM sl_num_reinfs%(num_boxes%, num_levers%, num_timeslices%) DIM reinf_press%(num_boxes%) DIM house_light%(num_boxes%) DIM clicker%(num_boxes%) DIM dipper%(num_boxes%) DIM tray_flap%(num_boxes%) DIM lever%(num_boxes%, num_levers%) DIM press%(num_boxes%, num_levers%) DIM stimulus_light%(num_boxes%) DIM magazine_light%(num_boxes%) DIM pump%(num_boxes%) REM RNC: 3 Nov 99 DIM switches_after_unreinf%(num_boxes%, num_levers%, num_timeslices%) DIM chains_after_unreinf%(num_boxes%, num_levers%, num_timeslices%) DIM switches_after_reinf%(num_boxes%, num_levers%, num_timeslices%) DIM chains_after_reinf%(num_boxes%, num_levers%, num_timeslices%) REM -- for internal use: DIM last_press_was_reinforced%(num_boxes%) DIM lever_of_last_press%(num_boxes%) DIM havent_pressed_yet_so_fuck_off%(num_boxes%) REM ******************* Define some constants ****************** inactive% = 0 active% = 1 active_boxes% = 0 right% = 0 left% = 1 false% = 0 true% = 1 total% = 0 pump% = 0 dipper% = 1 random% = 2 stim_none% = 0 :REM ************ RNC stim_maglight% = 1 stim_clicker% = 2 undefined% = -1 clock_timer% = 50 REM defaults default_session_length% = 120000 default_random_interval%(right%) = 10 default_random_interval%(left%) = 10 default_max_reinfs%(right%) = 10 default_max_reinfs%(left%) = 10 default_collection_duration%(pump%) = 500 :REM max time from reinf delivery to magazine nosepoke (otherwise classed as omission) default_collection_duration%(dipper%) = 500 :REM default_reinf_duration%(pump%) = 150: REM the time reinf is avail, once rat has poked default_reinf_duration%(dipper%) = 150: REM default_reinforcer%(right%) = pump% default_reinforcer%(left%) = dipper% default_changeover_delay% = 0 default_stimulus%(pump%) = stim_clicker% :REM ************ RNC default_stimulus%(dipper%) = stim_maglight% burst_cutoff% = 50 REM ************************************************************** REM *********************** main program ************************* REM ************************************************************** PROCinit PROCkill_all PROCdefine_switches PROCcontrol_switches PROCset_config PROCrecord_config PROCprint_all PROCstart_program END REM ************************************************************** REM *********************** utility fns ************************** REM ************************************************************** REM ************************ min and max ************************ DEF FNmax(a%, b%) IF (a% > b%) THEN =a% ELSE =b% DEF FNmin(a%, b%) IF (a% > b%) THEN =b% ELSE =a% REM ***** given a side, return the index of the other side ****** DEF FNother_side(side%) IF side% = left% THEN =right% ELSE =left% ENDIF REM *** compute a unique timer id for a particular reinforcer *** DEF FNreinf_timer(box%, side%) = (side% + 1) * 10 + box% REM *** compute a unique timer id for a box's timeslice reset *** DEF FNslice_timer(box%) = 30 + box% REM ******* compute a unique timer id for a box's clicker ******* DEF FNclick_timer(box%) = 40 + box% REM *********** input a numeric value with default ************** DEF FNread_input(default%, x%, y%) INPUT TAB(x%, y%); "" temp$ IF temp$ = "" THEN PRINT TAB(x%, y%) default% = default% ELSE = VAL(temp$) ENDIF REM **************** print pump, dipper, or random ************** DEF PROCprint_reinforcer(index%) PRINT MID$("pdr", index% + 1, 1); ENDPROC DEF PROCprint_stimulus(index%) :REM ********** RNC PRINT MID$("nlc", index% + 1, 1); :REM (stim_none, stim_maglight, stim_clicker in order) ENDPROC REM ************ read in a reinforcer with default ************** DEF FNread_reinforcer(default%, x%, y%) INPUT TAB(x%, y%) "" temp$ CASE temp$ OF WHEN "p","P": = pump% WHEN "d","D": = dipper% WHEN "r","R": = random% WHEN "": PRINT TAB(x%, y%); PROCprint_reinforcer(default%) = default% OTHERWISE: PRINT TAB(x%, y%); PROCprint_reinforcer(default%) = default% ENDCASE REM ************ RNC RNC RNC RNC RNC RNC RNC RNC read in a stimulus with default ************** DEF FNread_stimulus(default%, x%, y%) INPUT TAB(x%, y%) "" temp$ CASE temp$ OF WHEN "l","L": = stim_maglight% WHEN "c","C": = stim_clicker% WHEN "n","N": = stim_none% WHEN "": PRINT TAB(x%, y%); PROCprint_stimulus(default%) = default% OTHERWISE: PRINT TAB(x%, y%); PROCprint_stimulus(default%) = default% ENDCASE REM *********** print a statistic ('n/a' for undefined) ********** DEF PROCprint_stat(x%, stat%) PRINT TAB(x%); IF stat% = undefined% THEN PRINT " (n/a)"; ELSE PRINT stat%; ENDIF ENDPROC REM *************** format and print a time ********************* DEF PROCoutput_time(cs%) REM yuck! seconds% = cs% / 100 IF seconds% < 0 THEN seconds% = 0 minutes% = seconds% DIV 60 seconds% = seconds% MOD 60 IF (minutes% < 10) THEN time$ = " 0" ELSE time$ = " " ENDIF time$ = time$ + STR$(minutes%) + ":" IF (seconds% < 10) THEN time$ = time$ + "0" ENDIF time$ = time$ + STR$(seconds%) PRINT time$; ENDPROC REM ************************************************************** REM *********************** setup procs ************************** REM ************************************************************** REM ***************** Set up switch indices ********************* DEF PROCdefine_switches REM they mostly follow a pattern FOR box% = 1 TO num_boxes% house_light%(box%) = 0*num_boxes% + box%-1 magazine_light%(box%) = 1*num_boxes% + box%-1 dipper%(box%) = 2*num_boxes% + box%-1 tray_flap%(box%) = 3*num_boxes% + box%-1 lever%(box%, left%) = 4*num_boxes% + box%-1 lever%(box%, right%) = 5*num_boxes% + box%-1 press%(box%, left%) = 6*num_boxes% + box%-1 press%(box%, right%) = 7*num_boxes% + box%-1 REM left light REM right light pump%(box%) = 10*num_boxes% + box%-1 clicker%(box%) = 11*num_boxes% + box%-1 stimulus_light%(box%) = 12*num_boxes% + box%-1 NEXT box% REM there are some exceptions due to bad lines REM house_light%(1) = 61 REM house_light%(2) = 0 REM house_light%(5) = 54 REM stimulus_light%(4) = 62 REM lever%(6, right%) = 63 ENDPROC REM ************ Assert control of switches ********************* DEF PROCcontrol_switches FOR box% = 1 TO num_boxes% PROCgovn_switch(house_light%(box%), E%) PROCgovn_switch(magazine_light%(box%), E%) PROCgovn_switch(clicker%(box%), E%) PROCgovn_switch(dipper%(box%), E%) PROCgovn_switch(lever%(box%, left%), E%) PROCgovn_switch(lever%(box%, right%), E%) PROCgovn_switch(stimulus_light%(box%), E%) PROCgovn_switch(pump%(box%), E%) PROCfree_switch(tray_flap%(box%), E%) PROCfree_switch(press%(box%, left%), E%) PROCfree_switch(press%(box%, right%), E%) NEXT box% PROCpipe_fkey(11, 0, 1, "FNfinish_expt(", 0, E%) ENDPROC REM ******************** display configuration ****************** DEF PROCdisplay_config PRINT TAB(0) "Box:"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); box%; NEXT box% PRINT TAB(0) "Subject:"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); subject$(box%); NEXT box% PRINT TAB(0) "Session:"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); session%(box%); NEXT box% PRINT PRINT TAB(0) "Session length:"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); session_length%(box%); NEXT box% PRINT TAB(0) "Changeover delay:"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); changeover_delay%(box%); NEXT box% PRINT TAB(0) "Collection duration (p):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); collection_duration%(box%, pump%); NEXT box% PRINT TAB(0)"Collection duration (d):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); collection_duration%(box%, dipper%); NEXT box% PRINT TAB(0); "Reinforcement duration (p):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); reinf_duration%(box%, pump%); NEXT box% PRINT TAB(0); "Reinforcement duration (d):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); reinf_duration%(box%, dipper%); NEXT box% PRINT TAB(0); "Max random interval (l):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); random_interval%(box%, left%); NEXT box% PRINT TAB(0); "Max random interval (r):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); random_interval%(box%, right%); NEXT box% PRINT TAB(0); "Max reinforcements (l):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); max_reinfs%(box%, left%); NEXT box% PRINT TAB(0); "Max reinforcements (r):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); max_reinfs%(box%, right%); NEXT box% PRINT TAB(0); "Reinforcer (l):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); PROCprint_reinforcer(reinforcer%(box%, left%)) NEXT box% PRINT TAB(0); "Reinforcer (r):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); PROCprint_reinforcer(reinforcer%(box%, right%)) NEXT box% PRINT TAB(0); "Stimulus (pump):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); PROCprint_stimulus(stimulus%(box%, pump%)) NEXT box% PRINT TAB(0); "Stimulus (dipper):"; FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8); PROCprint_stimulus(stimulus%(box%, dipper%)) NEXT box% PRINT:PRINT ENDPROC REM *************** read configuration manually ***************** DEF PROCread_config save% = @% @% = "g0.0" CLS PRINT TAB(0, 3); "Box:" PRINT TAB(0, 4); "Subject:" PRINT TAB(0, 5); "Session:" PRINT TAB(0, 7); "Session length:" PRINT TAB(0, 8); "Changeover delay:" PRINT TAB(0, 9); "Coll. duration (p):" PRINT TAB(0, 10); "Coll. duration (d):" PRINT TAB(0, 11); "Reinf. duration (p):" PRINT TAB(0, 12); "Reinf. duration (d):" PRINT TAB(0, 13); "Rand. interval (l):" PRINT TAB(0, 14); "Rand. interval (r):" PRINT TAB(0, 15); "Max reinfs. (l):" PRINT TAB(0, 16); "Max reinfs. (r):" PRINT TAB(0, 17); "Reinforcer (l):" PRINT TAB(0, 18); "Reinforcer (r):" PRINT TAB(0, 19); "Stimulus (pump):" PRINT TAB(0, 20); "Stimulus (dipper):" FOR box% = 1 TO num_boxes% PRINT TAB(22 + box% * 8, 3); box% PRINT TAB(22 + box% * 8, 4); subject$(box%) PRINT TAB(22 + box% * 8, 5); session%(box%) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 7); "("; session_length%(box%); ")"; session_length%(box%) = FNread_input(session_length%(box%), 22 + box% * 8, 7) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 8); "("; changeover_delay%(box%); ")"; changeover_delay%(box%) = FNread_input(changeover_delay%(box%), 22 + box% * 8, 8) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 9); "("; collection_duration%(box%, pump%); ")"; collection_duration%(box%, pump%) = FNread_input(collection_duration%(box%, pump%), 22 + box% * 8, 9) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 10); "("; collection_duration%(box%, dipper%); ")"; collection_duration%(box%, dipper%) = FNread_input(collection_duration%(box%, dipper%), 22 + box% * 8, 10) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 11); "("; reinf_duration%(box%, pump%); ")"; reinf_duration%(box%, pump%) = FNread_input(reinf_duration%(box%, dipper%), 22 + box% * 8, 11) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 12); "("; reinf_duration%(box%, dipper%); ")"; reinf_duration%(box%, dipper%) = FNread_input(reinf_duration%(box%, dipper%), 22 + box% * 8, 12) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 13); "("; random_interval%(box%, left%); ")"; random_interval%(box%, left%) = FNread_input(random_interval%(box%, left%), 22 + box% * 8, 13) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 14); "("; random_interval%(box%, right%); ")"; random_interval%(box%, right%) = FNread_input(random_interval%(box%, right%), 22 + box% * 8, 14) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 15); "("; max_reinfs%(box%, left%); ")"; max_reinfs%(box%, left%) = FNread_input(max_reinfs%(box%, left%), 22 + box% * 8, 15) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 16); "("; max_reinfs%(box%, right%); ")"; max_reinfs%(box%, right%) = FNread_input(max_reinfs%(box%, right%), 22 + box% * 8, 16) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 17); "("; PROCprint_reinforcer(reinforcer%(box%, left%)) PRINT ") "; reinforcer%(box%, left%) = FNread_reinforcer(reinforcer%(box%, left%), 22 + box% * 8, 17) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 18); "("; PROCprint_reinforcer(reinforcer%(box%, right%)) PRINT ") "; reinforcer%(box%, right%) = FNread_reinforcer(reinforcer%(box%, right%), 22 + box% * 8, 18) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 19); "("; PROCprint_stimulus(stimulus%(box%, pump%)) PRINT ") "; stimulus%(box%, pump%) = FNread_stimulus(stimulus%(box%, pump%), 22 + box% * 8, 19) NEXT box% FOR box% = 1 TO num_boxes% PRINT TAB(21, 20); "("; PROCprint_stimulus(stimulus%(box%, dipper%)) PRINT ") "; stimulus%(box%, dipper%) = FNread_stimulus(stimulus%(box%, dipper%), 22 + box% * 8, 20) NEXT box% @% = save% ENDPROC REM ******************* set up the configuration **************** DEF PROCset_config CLS PRINT "Concurrent Random Interval Schedule" PRINT "Version 1.0 (13 July 1998)" PRINT PRINT "Press F11 to abort" REM read in names FOR box% = 1 TO num_boxes% PRINT TAB(10,8) "Enter information for box "; box% INPUT TAB(10,10); "Subject: " subject$(box%) INPUT TAB(10,12); "Session: " session%(box%) PRINT TAB(10, 10); SPC(40) PRINT TAB(10, 12); SPC(40) NEXT box% REM load in defaults FOR box% = 1 TO num_boxes% session_length%(box%) = default_session_length% changeover_delay%(box%) = default_changeover_delay% random_interval%(box%, left%) = default_random_interval%(left%) random_interval%(box%, right%) = default_random_interval%(right%) max_reinfs%(box%, left%) = default_max_reinfs%(left%) max_reinfs%(box%, right%) = default_max_reinfs%(right%) reinf_duration%(box%, pump%) = default_reinf_duration%(pump%) reinf_duration%(box%, dipper%) = default_reinf_duration%(dipper%) collection_duration%(box%, pump%) = default_collection_duration%(pump%) collection_duration%(box%, dipper%) = default_collection_duration%(dipper%) reinforcer%(box%, right%) = default_reinforcer%(left%) reinforcer%(box%, left%) = default_reinforcer%(right%) stimulus%(box%, pump%) = default_stimulus%(pump%) stimulus%(box%, dipper%) = default_stimulus%(dipper%) NEXT box% REM maybe change configuration REPEAT conf_done% = 0 CLS PROCdisplay_config REM ask if okay PRINT PRINT "Change configuration? "; REPEAT INPUT "" choice$ CASE choice$ OF WHEN "y", "Y": choice_done% = 1: PROCread_config WHEN "n", "N": choice_done% = 1: conf_done% = 1 OTHERWISE: choice_done% = 0 ENDCASE UNTIL choice_done% = 1 UNTIL conf_done% = 1 CLS INPUT "Filename: " filename$ realfilename$ = filename$ :REM changed by RNC so path no longer hard-coded rnc_filename$ = "X" + filename$ command$ = "SPOOL " + filename$: OSCLI(command$) *FX3,16 REM turn off spooling temporarily ENDPROC REM ********************* Start a box *************************** DEF PROCstart_trial(box%) PROCswitch_on(house_light%(box%), E%) FOR side%= 0 TO 1 IF max_reinfs%(box%, side%)<>0 THEN PROCswitch_on(lever%(box%, side%), E%) REM PROCswitch_on(lever%(box%, left%), E%) ENDIF NEXT PROCpipe_switch(press%(box%, right%), On, 1, "FNprocess_right(", box%, E%) PROCpipe_switch(press%(box%, left%), On, 1, "FNprocess_left(", box%, E%) PROCpipe_timer(box%, session_length%(box%), 0, "FNfinish_trial(", box%, E%) timeout_time%(box%) = TIME + session_length%(box%) IF (num_timeslices% <> 0) THEN slice_size% = session_length%(box%) / num_timeslices% PROCpipe_timer(FNslice_timer(box%), slice_size%, slice_size%, "FNnew_timeslice(", box%, E%) ENDIF active_boxes% += 1 state%(box%) = active% FOR side%=0 TO 1 IF max_reinfs%(box%, side%)<>0 THEN lever_state%(box%, side%) = active% ELSE lever_state%(box%,side%)= inactive% ENDIF NEXT timeslice%(box%) = 1 havent_pressed_yet_so_fuck_off%(box%) = true% PROCset_reinf(box%, left%) PROCset_reinf(box%, right%) ENDPROC REM ************* start all boxes ******************************* DEF PROCstart_program FOR box% = 1 TO num_boxes% PROCstart_trial(box%) NEXT box% PROCpipe_timer(clock_timer%, 100, 100, "FNclock(", 1, E%) PROCwait(E%): *AE ENDPROC REM ************************************************************** REM *********** main loop functions and callbacks **************** REM ************************************************************** REM ************ set the time for next reinforcement ************* DEF PROCset_reinf(box%, side%) REM RNC/RHQ, 28 Aug 99, added the "+sl_num_reinfs%()" bit IF num_reinfs%(box%, side%, total%)+sl_num_reinfs%(box%,side%,total%)0 THEN next_reinf_time%(box%, side%) = FNmax(next_reinf_time%(box%, side%), TIME + RND(2*(random_interval%(box%, side%)))) IF random_interval%(box%, side%)=0 THEN next_reinf_time%(box%, side%)=TIME ENDPROC REM ******************* handle a leverpress ********************** DEF PROCprocess_press(box%, side%) press_time% = TIME REM collect tons of statistics about the leverpress REM RNC, 28 Aug 99 IF FNcheck_concurrent(box%, side%) = true% THEN PROCcollect_press_stats(box%, side%, total%, press_time%) ELSE PROCcollect_single_lever_press_stats(box%, side%, total%, press_time%) ENDIF REM PROCcollect_press_stats(box%, side%, total%, press_time%) REM instead we check first whether both levers are available REM and file data accordingly REM enforce the changeover delay by possibly increasing REM the time of next reinforcement on the other lever other_side% = FNother_side(side%) switch_press%(box%, other_side%)=0 REM this flag will ensure that the first press on the other lever REM cannot be reinforced IF switch_press%(box%, side%)=0 THEN next_reinf_time%(box%, side%)=FNmax(press_time% +changeover_delay%(box%), next_reinf_time%(box%, side%)) REM next_reinf_time%(box%, other_side%) = FNmax(press_time% + changeover_delay%(box%), REMnext_reinf_time%(box%, other_side%)) REM this is replaced by a procedure which implements REM the changeover delay when the first press after a switch is made REM decide whether to reinforce the press IF reinf_available%(box%, side%) AND press_time% >= next_reinf_time%(box%, side%) THEN PROCdeliver_reinf(box%, side%) reinf_press%(box%)=1 REM RNC 3 Nov 99 REM don't think reinf_press is used, so this is probably redundant. Never mind, what follows is a better name last_press_was_reinforced%(box%) = true% ELSE last_press_was_reinforced%(box%) = false% ENDIF REM and reset switch flag so that changeover delay is not recalled for subsequent presses REM in this sequence on this lever switch_press%(box%, side%)=1 REM RNC 3 Nov 99 havent_pressed_yet_so_fuck_off%(box%) = false% lever_of_last_press%(box%) = side% ENDPROC REM ************* wrapper functions for above ****************** DEF FNprocess_left(box%, bogus%) IF bogus% = 0 =0 PROCprocess_press(box%, left%) =0 DEF FNprocess_right(box%, bogus%) IF bogus% = 0 =0 PROCprocess_press(box%, right%) =0 REM *************** deliver a reward **************************** DEF PROCdeliver_reinf(box%, side%) REM RNC, 28 Aug 99 IF FNcheck_concurrent(box%,side%) = true% THEN PROCcollect_reinf_stats(box%, side%, total%, TIME) ELSE PROCcollect_single_lever_reinf_stats(box%, side%, total%, TIME) ENDIF REM collect a bunch of stats REM instead check concurrent status first REM turn off reinforcement on the lever until we are REM done with the current reward cycle reinf_available%(box%, side%) = false% REM offer the reinforcer CASE reinforcer%(box%, side%) OF WHEN pump%: PROCpump_on(box%, side%) WHEN dipper%: PROCdipper_on(box%, side%) WHEN random%: IF (RND(2) = 1) THEN PROCpump_on(box%, side%) ELSE PROCdipper_on(box%, side%) ENDIF ENDCASE REM the pump_on and dipper_on procs handle setting REM timeouts for collection, etc., so we are done ENDPROC REM *************** turn on the pump **************************** DEF PROCpump_on(box%, side%) PROCswitch_on(pump%(box%), E%) REM mark that we're using it (so the other side doesn't turn it off) running_pump%(box%, side%) = true% REM wait for collection PROCpipe_switch(tray_flap%(box%), On, 1, "FNcollection(", box%, E%) REM run the clicker REM RNC -- or start the light, or neither CASE stimulus%(box%, pump%) OF WHEN stim_none%: WHEN stim_maglight%: PROCswitch_on(magazine_light%(box%), E%) :REM*****RNC WHEN stim_clicker%: PROCrun_clicker(box%) ENDCASE REM PROCrun_clicker(box%) -- what ND had REM temp$ stuff is trickery to pass an extra argument to callback temp$ = "FNomission(" + STR$(box%) + "," PROCpipe_timer(FNreinf_timer(box%, side%), collection_duration%(box%, pump%), 0, temp$, side%, E%) ENDPROC REM *************** turn on the dipper ************************** DEF PROCdipper_on(box%, side%) PROCswitch_on(dipper%(box%), E%) REM mark that we're using it (so the other side doesn't turn it off) running_dipper%(box%, side%) = true% REM RNC CASE stimulus%(box%, dipper%) OF WHEN stim_none%: WHEN stim_maglight%: PROCswitch_on(magazine_light%(box%), E%) :REM*****RNC WHEN stim_clicker%: PROCrun_clicker(box%) ENDCASE REM ND had -- PROCswitch_on(stimulus_light%(box%), E%) : REM conditioned rf/cue REM wait for collection PROCpipe_switch(tray_flap%(box%), On, 1, "FNcollection(", box%, E%) REM temp$ stuff is trickery to pass an extra argument to callback temp$ = "FNomission(" + STR$(box%) + "," PROCpipe_timer(FNreinf_timer(box%, side%), collection_duration%(box%, dipper%), 0, temp$, side%, E%) ENDPROC REM ****************** toggle the clicker ************************ DEF FNtoggle_clicker(box%, bogus%) IF bogus% = 0 =0 PROCswitch_over(clicker%(box%), E%) =0 REM ******************** start the clicker *********************** DEF PROCrun_clicker(box%) PROCpipe_timer(FNclick_timer(box%), 10, 10, "FNtoggle_clicker(", box%, E%) ENDPROC REM ******************** kill the clicker ************************ DEF PROCkill_clicker(box%) PROCkill_timer(FNclick_timer(box%), E%) ENDPROC REM ************** handle collection of reinforcer ************** DEF PROCcollection(box%, side%) REM collect some statistics PROCcollect_coll_stats(box%, side%, total%, TIME) REM kill the omission timer PROCkill_timer(FNreinf_timer(box%, side%), E%) :REM RNC 8 Nov 99: note this is now redundant, see below REM RHQ 7 Nov 99 REM this has been moved from PROCcollection REM start a new timer to remove the reinforcement REM temp$ stuff is trickery to pass an extra argument to the callback REM RNC 8 Nov 99 REM This all went horribly wrong so it's going back where it came from. temp_moved$ = "FNkill_reinf(" + STR$(box%) + "," PROCpipe_timer(FNreinf_timer(box%, side%), reinf_duration%(box%, side%), 0, temp_moved$, side%, E%) ENDPROC REM ********** callback for collection of reinforcer ************ REM (basically a wrapper for above procedure) DEF FNcollection(box%, bogus%) IF bogus% = 0 =0 PROCkill_switch(tray_flap%(box%), E%) IF (waiting_for_collection%(box%, right%, total%)) THEN PROCcollection(box%, right%) ENDIF IF (waiting_for_collection%(box%, left%, total%)) THEN PROCcollection(box%, left%) ENDIF =0 REM ****************** callback for omission ******************** DEF FNomission(box%, side%, bogus%) IF bogus% = 0 =0 other_side% = FNother_side(side%) PROCkill_timer(FNreinf_timer(box%, side%), E%) REM kill the tray flap switch, unless the other REM side's reinforcer is also waiting on it IF (waiting_for_collection%(box%, other_side%, total%) = false%) THEN PROCkill_switch(tray_flap%(box%), E%) ENDIF REM collect some statistics PROCcollect_omission_stats(box%, side%, total%) REM turn off the reinforcer and other assorted stuff PROCkill_reinf(box%, side%) =0 REM ********* callback to lower dipper or turn off pump ********* REM (also here we do various setup to start the next trial) DEF PROCkill_reinf(box%, side%) other_side% = FNother_side(side%) PROCkill_timer(FNreinf_timer(box%, side%), E%) IF running_pump%(box%, side%) = true% THEN PROCpump_off(box%, side%) ENDIF IF running_dipper%(box%, side%) = true% THEN PROCdipper_off(box%, side%) ENDIF REM decide time reinforcement next available PROCset_reinf(box%, side%) REM see if we're done with the lever REM if so, shut it off REM IF (num_reinfs%(box%, side%, total%) >= max_reinfs%(box%, side%)) THEN REM PROCkill_switch(press%(box%, side%), E%) REM PROCswitch_off(lever%(box%, side%), E%) IF ((num_reinfs%(box%, side%, total%)+sl_num_reinfs%(box%, side%, total%)) >= max_reinfs%(box%, side%)) THEN PROCkill_switch(press%(box%, side%), E%) PROCswitch_off(lever%(box%, side%), E%) lever_state%(box%, side%) = inactive% REM finally, see if we've killed both levers IF lever_state%(box%, other_side%) = inactive% THEN PROCkill_box(box%) ENDIF ENDIF REM and reset the flag which determines REM whether a press under non-concurrent conditions REM triggers reinforcement reinf_press%(box%)=0 REM RNC, 28 Aug 99, NB reinf_press%() does bugger all. REM Work is done by reinf_available% or whatever it's called. ENDPROC REM ***************** callback wrapper for above *************** DEF FNkill_reinf(box%, side%, bogus%) IF bogus% = 0 =0 PROCkill_reinf(box%, side%) =0 REM ******************* turn off pump ************************** DEF PROCpump_off(box%, side%) other_side% = FNother_side(side%) REM mark the pump unused running_pump%(box%, side%) = false% REM actually turn off the pump only if it's not still REM in use by the other side; otherwise since we've REM marked it unused by us, the other side will turn REM it off when it's done with it. IF running_pump%(box%, other_side%) = false% THEN PROCswitch_off(pump%(box%), E%) REM binned after all -- PROCkill_clicker(box%) :REM ND/RHQ had this happening regardless; now stays on for as long as reinf -- RNC CASE stimulus%(box%, pump%) OF WHEN stim_none%: WHEN stim_maglight%: PROCswitch_off(magazine_light%(box%), E%) WHEN stim_clicker%: PROCkill_clicker(box%) ENDCASE ENDIF ENDPROC REM ******************* turn off dipper ************************** DEF PROCdipper_off(box%, side%) other_side% = FNother_side(side%) REM mark the dipper unused running_dipper%(box%, side%) = false% REM actually turn off the dipper only if it's not still REM in use by the other side; otherwise since we've REM marked it unused by us, the other side will turn REM it off when it's done with it. IF running_dipper%(box%, other_side%) = false% THEN PROCswitch_off(dipper%(box%), E%) REM binned -- PROCswitch_off(stimulus_light%(box%), E%) :REM ND/RHQ had this happening regardless; now stays on for as long as reinf -- RNC CASE stimulus%(box%, dipper%) OF WHEN stim_none%: WHEN stim_maglight%: PROCswitch_off(magazine_light%(box%), E%) WHEN stim_clicker%: PROCkill_clicker(box%) ENDCASE ENDIF ENDPROC REM *************** clock timer callback *********************** DEF FNclock(junk%, bogus%) IF bogus% = 0 =0 FOR box% = 1 TO num_boxes% PROCprint_time(box%) PROCprint_nexttime(box%, left%) PROCprint_nexttime(box%, right%) NEXT box% =0 REM ************************************************************** REM **************** stat collecting functions ******************* REM ************************************************************** REM all this is collected on a timeslice by timeslice basis REM and simultaneously saved as totals for the whole experiment REM so -- all these functions run twice, once to save REM stats for the current timeslice, and once to save REM overall stats. The functions, when called to collect REM timeslice stats, call themselves to collect total stats REM Here's how most of the stats work: we're mostly interested REM in averages, so we track the sum of all the things we're REM averaging, and the total number of them to divide by later. REM e.g. to collect the average same lever inter-response interval, REM with each response we add the response interval to REM summed_same_iris% and increment num_same_iris%; this way REM later on we can divide them to get the average. REM ******************* start a new timeslice ******************** REM this just bumps up the global timeslice indicator, REM and copies over some flags which need to be REM saved from one timeslice to the next DEF FNnew_timeslice(box%, bogus%) IF bogus% =0 =0 IF timeslice%(box%) = num_timeslices% THEN =0 oldslice% = timeslice%(box%) timeslice%(box%) += 1 REM copy over some flags and data to the new timeslice last_reinf_time%(box%, left%, timeslice%(box%)) = last_reinf_time%(box%, left%, oldslice%) last_reinf_time%(box%, right%, timeslice%(box%)) = last_reinf_time%(box%, right%, oldslice%) last_press_time%(box%, left%, timeslice%(box%)) = last_press_time%(box%, left%, oldslice%) last_press_time%(box%, right%, timeslice%(box%)) = last_press_time%(box%, right%, oldslice%) num_same_pslrs%(box%, left%, timeslice%(box%)) = num_same_pslrs%(box%, left%, oldslice%) num_same_pslrs%(box%, right%, timeslice%(box%)) = num_same_pslrs%(box%, right%, oldslice%) num_any_pslrs%(box%, timeslice%(box%)) = num_any_pslrs%(box%, oldslice%) num_any_pslrs%(box%, timeslice%(box%)) = num_any_pslrs%(box%, oldslice%) waiting_any_response%(box%, left%, timeslice%(box%)) = waiting_any_response%(box%, left%, oldslice%) waiting_any_response%(box%, right%, timeslice%(box%)) = waiting_any_response%(box%, right%, oldslice%) waiting_same_response%(box%, left%, timeslice%(box%)) = waiting_same_response%(box%, left%, oldslice%) waiting_same_response%(box%, right%, timeslice%(box%)) = waiting_same_response%(box%, right%, oldslice%) waiting_for_collection%(box%, left%, timeslice%(box%)) = waiting_for_collection%(box%, left%, oldslice%) waiting_for_collection%(box%, right%, timeslice%(box%)) = waiting_for_collection%(box%, right%, oldslice%) =0 REM ***********are both levers available*********************************** REM the program splits collection of data according to whether REM both levers are still available or not REM********************************************************************* REM need to add to this to handle delivery of remaining reinforcers DEF FNcheck_concurrent(box%, side%) REM RNC, 28 Aug 99. REM Redone as function. LOCAL other_side% other_side% = FNother_side(side%) IF lever_state%(box%,other_side%)=active% THEN =true% ELSE =false% REM *********** collect statistics about a leverpress *********** DEF PROCcollect_press_stats(box%, side%, slice%, press_time%) REM the first thing we do is call ourselves again REM in order to collect the timeslice stats if necc IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_press_stats(box%, side%, timeslice%(box%), press_time%) ENDIF other_side% = FNother_side(side%) num_presses%(box%, side%, slice%) += 1 PROCprint_resps(box%, side%) REM update presses since last reinforcement num_same_pslrs%(box%, side%, slice%) += 1 num_any_pslrs%(box%, slice%) += 1 REM if this is the 2nd or subsequent press on this lever, add REM the iri to the running average IF (last_press_time%(box%, side%, slice%) <> 0) THEN summed_same_iris%(box%, side%, slice%) += (press_time% - last_press_time%(box%, side%, slice%)) num_same_iris%(box%, side%, slice%) += 1 ENDIF REM same deal with 2nd or subsequent overall press IF (last_press_time%(box%, side%, slice%) <> 0 OR last_press_time%(box%, other_side%, slice%) <> 0) THEN summed_any_iris%(box%, slice%) += (press_time% - FNmax(last_press_time%(box%, side%, slice%), last_press_time%(box%, other_side%, slice%))) num_any_iris%(box%, slice%) += 1 ENDIF REM if this is the first response after a reinforcement REM on either side then add it to the running average REM if the interval is more than the burst cutoff IF (waiting_any_response%(box%, side%, slice%)) THEN IF (press_time% - last_reinf_time%(box%, side%, slice%)) > burst_cutoff% THEN summed_any_rews%(box%, side%, slice%) += (press_time% - last_reinf_time%(box%, side%, slice%)) num_any_rews%(box%, side%, slice%) += 1 waiting_any_response%(box%, side%, slice%) = false% ENDIF ENDIF IF (waiting_any_response%(box%, other_side%, slice%)) THEN IF (press_time% - last_reinf_time%(box%, other_side%, slice%)) > burst_cutoff% THEN summed_any_rews%(box%, other_side%, slice%) += (press_time% - last_reinf_time%(box%, other_side%, slice%)) num_any_rews%(box%, other_side%, slice%) += 1 waiting_any_response%(box%, other_side%, slice%) = false% ENDIF ENDIF REM and same for first response after a reinforcement REM on the same side, which we track separately IF (waiting_same_response%(box%, side%, slice%)) THEN IF (press_time% - last_reinf_time%(box%, side%, slice%)) > burst_cutoff% THEN summed_same_rews%(box%, side%, slice%) += (press_time% - last_reinf_time%(box%, side%, slice%)) num_same_rews%(box%, side%, slice%) += 1 waiting_same_response%(box%, side%, slice%) = false% ENDIF ENDIF REM update the time of last press indicator last_press_time%(box%, side%, slice%) = press_time% REM RNC 3 Nov 99 - switching IF (havent_pressed_yet_so_fuck_off%(box%) = false%) THEN REM worth doing something IF last_press_was_reinforced%(box%) = true% THEN REM *** following reinforcement IF side% = lever_of_last_press%(box%) THEN chains_after_reinf%(box%, side%, slice%) += 1 ELSE switches_after_reinf%(box%, FNother_side(side%), slice%) += 1 ENDIF ELSE REM *** following unreinforced press IF side% = lever_of_last_press%(box%) THEN chains_after_unreinf%(box%, side%, slice%) += 1 ELSE switches_after_unreinf%(box%, FNother_side(side%), slice%) += 1 REM switches are AWAY from the other side, not to this one ENDIF ENDIF ENDIF ENDPROC REM ********* collect statistics about a reinforcement ********** DEF PROCcollect_reinf_stats(box%, side%, slice%, reinf_time%) IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_reinf_stats(box%, side%, timeslice%(box%), reinf_time%) ENDIF other_side% = FNother_side(side%) REM do some bookkeeping last_reinf_time%(box%, side%, slice%) = reinf_time% num_reinfs%(box%, side%, slice%) += 1 summed_same_pprs%(box%, side%, slice%) += num_same_pslrs%(box%, side%, slice%) summed_any_pprs%(box%, slice%) += num_any_pslrs%(box%, slice%) num_same_pslrs%(box%, side%, slice%) = 0 num_any_pslrs%(box%, slice%) = 0 PROCprint_reinfs(box%, side%) REM set flags to track latency to response after reinf waiting_any_response%(box%, side%, slice%) = true% waiting_same_response%(box%, side%, slice%) = true% REM set flag to track latency to collect reinforcer waiting_for_collection%(box%, side%, slice%) = true% ENDPROC REM ********* collect statistics about reinf collection ********* DEF PROCcollect_coll_stats(box%, side%, slice%, coll_time%) IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_coll_stats(box%, side%, timeslice%(box%), coll_time%) ENDIF summed_coll_latencies%(box%, side%, slice%) += (coll_time% - last_reinf_time%(box%, side%, slice%)) num_collected%(box%, side%, slice%) += 1 waiting_for_collection%(box%, side%, slice%) = false% ENDPROC REM ********* collect statistics about reinf omission *********** DEF PROCcollect_omission_stats(box%, side%, slice%) IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_omission_stats(box%, side%, timeslice%(box%)) ENDIF REM do some bookkeeping REM by the way, bookkeeping is the only word in the english REM language with three double letters in a row, ookkee waiting_for_collection%(box%, side%, slice%) = false% num_omissions%(box%, side%, slice%) += 1 ENDPROC REM ************************************************************** REM ************* statistic computing functions ****************** REM ************************************************************** REM these use the raw stats collected above to compute the REM things we're actually interested in REM total reinforcements, just the sum over left and right DEF FNtotal_num_reinfs(box%, slice%) = num_reinfs%(box%, left%, slice%) + num_reinfs%(box%, right%, slice%) REM total number of presses, just the sum over left and right DEF FNtotal_num_presses(box%, slice%) = num_presses%(box%, left%, slice%) + num_presses%(box%, right%, slice%) REM total number of omissions, just the sum over left and right DEF FNtotal_num_omits(box%, slice%) = num_omissions%(box%, left%, slice%) + num_omissions%(box%, right%, slice%) REM total number of collectionss, just the sum over left and right DEF FNtotal_num_colls(box%, slice%) = num_collected%(box%, left%, slice%) + num_collected%(box%, right%, slice%) REM number of responses per reinforcement -- straightforward division DEF FNtotal_resp_per_reinf(box%, slice%) IF FNtotal_num_reinfs(box%, slice%) = 0 THEN = undefined% ELSE = summed_any_pprs%(box%, slice%) / FNtotal_num_reinfs(box%, slice%) ENDIF DEF FNresp_per_reinf(box%, side%, slice%) IF num_reinfs%(box%, side%, slice%) = 0 THEN = undefined% ELSE = summed_same_pprs%(box%, side%, slice%) / num_reinfs%(box%, side%, slice%) ENDIF REM average inter-response-time, also straightforward division DEF FNtotal_avg_irt(box%, slice%) IF num_any_iris%(box%, slice%) = 0 THEN = undefined% ELSE = summed_any_iris%(box%, slice%) / num_any_iris%(box%, slice%) ENDIF DEF FNavg_irt(box%, side%, slice%) IF num_same_iris%(box%, side%, slice%) = 0 THEN = undefined% ELSE = summed_same_iris%(box%, side%, slice%) / (num_same_iris%(box%, side%, slice%)) ENDIF REM average latency to collect reward DEF FNavg_coll_lat(box%, side%, slice%) IF num_collected%(box%, side%, slice%) = 0 THEN = undefined% ELSE = summed_coll_latencies%(box%, side%, slice%) / num_collected%(box%, side%, slice%) ENDIF DEF FNtotal_avg_coll_lat(box%, slice%) IF FNtotal_num_colls(box%, slice%) = 0 THEN = undefined% ELSE = (summed_coll_latencies%(box%, right%, slice%) + summed_coll_latencies%(box%, left%, slice%)) / FNtotal_num_colls(box%, slice%) ENDIF REM average response on either lever after reward DEF FNavg_any_resp(box%, side%, slice%) IF num_any_rews%(box%, side%, slice%) = 0 THEN = undefined% ELSE = summed_any_rews%(box%, side%, slice%) / num_any_rews%(box%, side%, slice%) REM average response on same lever after reward DEF FNavg_same_resp(box%, side%, slice%) IF num_same_rews%(box%, side%, slice%) = 0 THEN = undefined% ELSE = summed_same_rews%(box%, side%, slice%) / num_same_rews%(box%, side%, slice%) REM bias (positive is left bias, negative right) DEF FNbias(box%, slice%) IF FNtotal_num_presses(box%, slice%) = 0 THEN = undefined% ELSE = 100 * (num_presses%(box%, left%, slice%) / FNtotal_num_presses(box%, slice%) - .5) ENDIF REM ************************************************************** REM **************** finishing up functions ********************** REM ************************************************************** REM ***************** kill a box ******************************** DEF PROCkill_box(box%) IF (state%(box%) = inactive%) THEN ENDPROC PROCkill_timer(box%, E%) PROCkill_timer(FNreinf_timer(box%, left%), E%) PROCkill_timer(FNreinf_timer(box%, right%), E%) PROCkill_timer(FNslice_timer(box%), E%) PROCkill_timer(FNclick_timer(box%), E%) PROCkill_switch(press%(box%, left%), E%) PROCswitch_off(lever%(box%, left%), E%) PROCkill_switch(press%(box%, right%), E%) PROCswitch_off(lever%(box%, right%), E%) PROCswitch_off(clicker%(box%), E%) PROCswitch_off(house_light%(box%), E%) PROCkill_switch(tray_flap%(box%), E%) PROCswitch_off(pump%(box%), E%) PROCswitch_off(dipper%(box%), E%) state%(box%) = inactive% lever_state%(box%, right%) = inactive% lever_state%(box%, left%) = inactive% active_boxes% -= 1 IF (active_boxes% = 0) THEN PROCend_program ENDPROC REM ************** handle the trial's end ************************ DEF FNfinish_trial(box%, bogus%) IF bogus% = 0 =0 PROCkill_box(box%) =0 REM ************** called to clean up when program ends ********** DEF PROCend_program PROCkill_fkey(11, E%) PROCkill_timer(clock_timer%, E%) PROCrecord_results *SPOOL PROCrnc_record_results ENDPROC REM ************** aborts the experiment ************************* DEF FNfinish_expt(junk%, bogus%) IF bogus% = 0 =0 FOR box% = 1 TO num_boxes% PROCkill_box(box%) NEXT box% =0 REM ************************************************************** REM ********** routines for printing info on the screen ********** REM ************************************************************** REM ************* move cursor to correct position **************** DEF PROCpos_cursor(box%, line%) PRINT TAB(22 + box% * 8, line%); ENDPROC REM ******** print various items in their proper location ********* DEF PROCprint_subject(box%) PROCpos_cursor(box%, 4) PRINT subject$(box%); ENDPROC DEF PROCprint_resps(box%, side%) IF side% = left% THEN PROCpos_cursor(box%, 6) ELSE PROCpos_cursor(box%, 7) ENDIF REM RNC 8 Nov 99: this function only does on-screen display, so may as well be unified with single-lever stats PRINT num_presses%(box%, side%, total%) + sl_num_presses%(box%, side%, total%); ENDPROC DEF PROCprint_reinfs(box%, side%) IF side% = left% THEN PROCpos_cursor(box%, 9) ELSE PROCpos_cursor(box%, 10) ENDIF REM RNC 8 Nov 99: this function only does on-screen display, so may as well be unified with single-lever stats PRINT num_reinfs%(box%, side%, total%) + sl_num_reinfs%(box%, side%, total%); ENDPROC DEF PROCprint_nexttime(box%, side%) IF side% = left% THEN PROCpos_cursor(box%, 14) ELSE PROCpos_cursor(box%, 15) ENDIF CASE lever_state%(box%, side%) OF WHEN inactive%: PRINT " inact"; WHEN active%: PROCoutput_time(next_reinf_time%(box%, side%) - TIME) ENDCASE ENDPROC DEF PROCprint_time(box%) PROCpos_cursor(box%, 20) CASE state%(box%) OF WHEN inactive%: PRINT " inact"; WHEN active%: PROCoutput_time(timeout_time%(box%) - TIME) ENDCASE ENDPROC REM ******************** print field labels ******************** DEF PROClabel_fields CLS PRINT TAB(0, 0); "Box:" PRINT TAB(0, 4); "Subject:" PRINT TAB(0, 6); "L presses:" PRINT TAB(0, 7); "R presses:" PRINT TAB(0, 9); "L reinforcements:" PRINT TAB(0, 10); "R reinforcements:" PRINT TAB(0, 12); "Reinf rule (LR):" PRINT TAB(0, 13); "Stim rule (LR):" PRINT TAB(0, 14); "Next L reinf:" PRINT TAB(0, 15); "Next R reinf:" PRINT TAB(0, 20); "Time left:" FOR box% = 1 TO num_boxes% PROCpos_cursor(box%, 0) PRINT box% PROCpos_cursor(box%, 12) PRINT " "; PROCprint_reinforcer(reinforcer%(box%, left%)) PRINT ","; PROCprint_reinforcer(reinforcer%(box%, right%)) PROCpos_cursor(box%, 13) PRINT " "; PROCprint_stimulus(stimulus%(box%, reinforcer%(box%, left%))) PRINT ","; PROCprint_stimulus(stimulus%(box%, reinforcer%(box%, right%))) NEXT box% ENDPROC REM *************** print a box's status ************************* DEF PROCprint_box(box%) PROCprint_subject(box%) PROCprint_time(box%) FOR side% = 0 TO 1 PROCprint_resps(box%, side%) PROCprint_reinfs(box%, side%) PROCprint_nexttime(box%, side%) NEXT side% ENDPROC REM *************** print all boxes' status ********************* DEF PROCprint_all PROClabel_fields FOR box% = 1 TO num_boxes% PROCprint_box(box%) NEXT box% ENDPROC REM ************************************************************** REM **** routines for printing info to the file and printer ****** REM ************************************************************** DEF PROCprinter_on VDU 2 ENDPROC DEF PROCprinter_off VDU 3 ENDPROC DEF PROCscript_on script_save% = @% @% = "g0.0" *FX 3,0 ENDPROC DEF PROCscript_off @% = script_save% *FX 3,16 ENDPROC REM maybe later we will have records of every leverpress REM ************ record configuration information **************** DEF PROCrecord_config PROCprinter_on PRINT "Concurrent random interval schedule" PRINT "Filename: "; filename$ PROCdisplay_config PROCprinter_off PROCscript_on FOR box% = 1 TO num_boxes% PROCrnc_config_line(box%) PRINT NEXT box% PROCscript_off ENDPROC REM RNC DEF PROCrnc_config_line(box%) PRINT box%; ","; subject$(box%); ","; session%(box%);","; PRINT session_length%(box%); ","; PRINT changeover_delay%(box%); ","; PRINT random_interval%(box%, left%); ","; random_interval%(box%, right%);","; PRINT max_reinfs%(box%, left%); ","; max_reinfs%(box%, right%); ","; PROCprint_reinforcer(reinforcer%(box%, left%)) PRINT ","; PROCprint_reinforcer(reinforcer%(box%, right%)) PRINT ","; PRINT reinf_duration%(box%, left%); ","; reinf_duration%(box%, right%); ","; PRINT collection_duration%(box%, left%); ","; collection_duration%(box%, right%); ","; PROCprint_stimulus(stimulus%(box%, reinforcer%(box%, left%))) :REM more RNC PRINT ","; PROCprint_stimulus(stimulus%(box%, reinforcer%(box%, right%))) ENDPROC REM ***************** record the experiment results ************* DEF PROCrecord_results PROCprinter_on IF num_timeslices% > 1 THEN FOR slice% = 1 TO num_timeslices% PRINT "Timeslice: "; slice% PROCprint_slice_data(slice%) PRINT NEXT slice% ENDIF PRINT "Totals: " PROCprint_slice_data(total%) PRINT PROCprinter_off PROCscript_on FOR box% = 1 TO num_boxes% PRINT box% FOR slice% = 0 TO num_timeslices% PRINT slice%;","; PROCrecord_slice_data(box%, slice%) NEXT slice% NEXT box% PROCscript_off ENDPROC DEF PROCrnc_record_results REM RNC 3 Nov 99 REM slightly inelegant, but alternative is rewriting loads REM program HAS ENDED otherwise by now, and previous spool file IS CLOSED. OSCLI("SPOOL "+rnc_filename$) PROCscript_on PROCrnc_header_line FOR box% = 1 TO num_boxes% FOR slice% = 0 TO num_timeslices% PROCrnc_config_line(box%) PRINT ",";slice%;","; PROCrecord_slice_data(box%, slice%) NEXT NEXT OSCLI("SPOOL") ENDPROC REM ************* print the data for a time slice ************** DEF PROCprint_slice_data(slice%) PRINT "Box:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 +box% * 8, box%) NEXT box% PRINT: PRINT "Left responses:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_presses%(box%, left%, slice%)) NEXT box% PRINT: PRINT "Right responses:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_presses%(box%, right%, slice%)) NEXT box% PRINT: PRINT "Left reinforcements:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_reinfs%(box%, left%, slice%)) NEXT box% PRINT: PRINT "Right reinforcements:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_reinfs%(box%, right%, slice%)) NEXT box% PRINT: PRINT "Bias:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNbias(box%, slice%)) NEXT box% PRINT: PRINT "Avg resps per L reinf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNresp_per_reinf(box%, left%, slice%)) NEXT box% PRINT: PRINT "Avg resps per R reinf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNresp_per_reinf(box%, right%, slice%)) NEXT box% PRINT: PRINT "Avg resps per any reinf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNtotal_resp_per_reinf(box%, slice%)) NEXT box% PRINT: PRINT "Average left IRT:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_irt(box%, left%, slice%)) NEXT box% PRINT: PRINT "Average right IRT:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_irt(box%, right%, slice%)) NEXT box% PRINT: PRINT "Average overall IRT:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNtotal_avg_irt(box%, slice%)) NEXT box% PRINT: PRINT "Avg lat L resp aft L rf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_same_resp(box%, left%, slice%)) NEXT box% PRINT: PRINT "Avg lat R resp aft R rf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_same_resp(box%, right%, slice%)) NEXT box% PRINT: PRINT "Avg lat any resp aft L rf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_any_resp(box%, left%, slice%)) NEXT box% PRINT: PRINT "Avg lat any resp aft R rf:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_any_resp(box%, right%, slice%)) NEXT box% PRINT: PRINT "Left omissions:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_omissions%(box%, left%, slice%)) NEXT box% PRINT: PRINT "Right omissions:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, num_omissions%(box%, right%, slice%)) NEXT box% PRINT: PRINT "Avg L reinf coll time:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_coll_lat(box%, left%, slice%)) NEXT box% PRINT: PRINT "Avg R reinf coll time:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNavg_coll_lat(box%, right%, slice%)) NEXT box% PRINT: PRINT "Avg any reinf coll time:"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, FNtotal_avg_coll_lat(box%, slice%)) NEXT box% REM RNC, 28 Aug 99 PRINT: PRINT "L single-lever presses (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, sl_num_presses%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R single-lever presses (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, sl_num_presses%(box%, right%, slice%)) NEXT box% PRINT: PRINT "L single-lever reinfs (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, sl_num_reinfs%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R single-lever reinfs (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, sl_num_reinfs%(box%, right%, slice%)) NEXT box% PRINT: PRINT "L(unreinf)->R switches (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, switches_after_unreinf%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R(unreinf)->L switches (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, switches_after_unreinf%(box%, right%, slice%)) NEXT box% PRINT: PRINT "L(unreinf)->L chains (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, chains_after_unreinf%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R(unreinf)->R chains (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, chains_after_unreinf%(box%, right%, slice%)) NEXT box% PRINT: PRINT "L(reinf)->L chains (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, chains_after_reinf%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R(reinf)->R chains (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, chains_after_reinf%(box%, right%, slice%)) NEXT box% PRINT: PRINT "L(reinf)->R switches (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, switches_after_reinf%(box%, left%, slice%)) NEXT box% PRINT: PRINT "R(reinf)->L switches (RHQ):"; FOR box% = 1 TO num_boxes% PROCprint_stat(22 + box% * 8, switches_after_reinf%(box%, right%, slice%)) NEXT box% ENDPROC DEF PROCrnc_header_line PRINT "BOX,SUBJECT,SESSION,SESSION_LENGTH,CHANGEOVER_DELAY,RI_LEFT,RI_RIGHT,MAX_REINFS_L,MAX_REINFS_R,"; PRINT "REINF_L,REINF_R,REINF_DURATION_L,REINF_DURATION_R,COLLECT_DURATION_L,COLLECT_DURATION_R,"; PRINT "STIMULUS_L,STIMULUS_R,"; PRINT "SLICE,"; PRINT "NUM_PRESSES_L,NUM_PRESSES_R,NUM_PRESSES_TOT,NUM_REINFS_L,NUM_REINFS_R,NUM_REINF_TOT,"; PRINT "NUM_OM_L,NUM_OM_R,NUM_OM_TOT,BIAS,RESP_PER_REINF_L,RESP_PER_REINF_R,RESP_PER_REINF_TOT,"; PRINT "AVG_IRT_L,AVG_IRT_R,AVG_IRT_TOT,AVG_COLL_LAT_L,AVG_COLL_LAT_R,AVG_COLL_LAT_TOT,"; PRINT "AVG_SAME_RESP_L,AVG_SAME_RESP_R,AVG_ANY_RESP_L,AVG_ANY_RESP_R,"; PRINT "SL_NUM_PRESSES_L,SL_NUM_PRESSES_R,SL_NUM_REINFS_L,SL_NUM_REINFS_R,"; PRINT "SWITCH_AFTER_UNREINF_L,SWITCH_AFTER_UNREINF_R,SWITCH_AFTER_UNREINF_TOT,"; PRINT "CHAIN_AFTER_UNREINF_L,CHAIN_AFTER_UNREINF_R,CHAIN_AFTER_UNREINF_TOT,"; PRINT "SWITCH_AFTER_REINF_L,SWITCH_AFTER_REINF_R,SWITCH_AFTER_REINF_TOT,"; PRINT "CHAIN_AFTER_REINF_L,CHAIN_AFTER_REINF_R,CHAIN_AFTER_REINF_TOT" ENDPROC REM ************* record the data for a time slice ************** DEF PROCrecord_slice_data(box%, slice%) PRINT num_presses%(box%, left%, slice%); ","; num_presses%(box%, right%, slice%); ","; FNtotal_num_presses(box%, slice%); ","; PRINT num_reinfs%(box%, left%, slice%); ","; num_reinfs%(box%, right%, slice%); ","; FNtotal_num_reinfs(box%, slice%); ","; PRINT num_omissions%(box%, left%, slice%); ","; num_omissions%(box%, right%, slice%); ","; FNtotal_num_omits(box%, slice%); ","; PRINT FNbias(box%, slice%); ","; PRINT FNresp_per_reinf(box%, left%, slice%); ","; FNresp_per_reinf(box%, right%, slice%); ","; FNtotal_resp_per_reinf(box%, slice%); ","; PRINT FNavg_irt(box%, left%, slice%); ","; FNavg_irt(box%, right%, slice%); ","; FNtotal_avg_irt(box%, slice%); ","; PRINT FNavg_coll_lat(box%, left%, slice%); ","; FNavg_coll_lat(box%, right%, slice%); ","; FNtotal_avg_coll_lat(box%, slice%); ","; PRINT FNavg_same_resp(box%, left%, slice%); ","; FNavg_same_resp(box%, right%, slice%); ","; PRINT FNavg_any_resp(box%, left%, slice%); ","; FNavg_any_resp(box%, right%, slice%); ","; REM RNC 28 Aug 99 PRINT sl_num_presses%(box%, left%, slice%); ","; sl_num_presses%(box%, right%, slice%); ","; PRINT sl_num_reinfs%(box%, left%, slice%); ","; sl_num_reinfs%(box%, right%, slice%); ","; REM RNC 3 Nov 99 - L, R, total (for each measure) PRINT switches_after_unreinf%(box%, left%, slice%);","; switches_after_unreinf%(box%, right%, slice%);","; switches_after_unreinf%(box%, left%, slice%)+switches_after_unreinf%(box%, right%, slice%); ","; PRINT chains_after_unreinf%(box%, left%, slice%);","; chains_after_unreinf%(box%, right%, slice%);","; chains_after_unreinf%(box%, left%, slice%)+chains_after_unreinf%(box%, right%, slice%); ","; PRINT switches_after_reinf%(box%, left%, slice%);","; switches_after_reinf%(box%, right%, slice%);","; switches_after_reinf%(box%, left%, slice%)+switches_after_reinf%(box%, right%, slice%); ","; PRINT chains_after_reinf%(box%, left%, slice%);","; chains_after_reinf%(box%, right%, slice%);","; chains_after_reinf%(box%, left%, slice%)+chains_after_reinf%(box%, right%, slice%) ENDPROC REM *********** collect statistics about a leverpress (one_lever)*********** DEF PROCcollect_single_lever_press_stats(box%, side%, slice%, press_time%) REM RNC, 28 Aug 99, the total/this re-entrancy IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_single_lever_press_stats(box%, side%, timeslice%(box%), press_time%) ENDIF other_side% = FNother_side(side%) sl_num_presses%(box%, side%, slice%) += 1 PROCprint_resps(box%, side%) REM update the time of last press indicator last_press_time%(box%, side%, slice%) = press_time% ENDPROC REM*********collect stats about reinf (one lever)********************** DEF PROCcollect_single_lever_reinf_stats(box%, side%, slice%, reinf_time%) REM RNC, 28 Aug 99, the total/this re-entrancy IF (slice% = total% AND num_timeslices% <> 0) THEN PROCcollect_single_lever_reinf_stats(box%, side%, timeslice%(box%), reinf_time%) ENDIF other_side% = FNother_side(side%) REM do some bookkeeping last_reinf_time%(box%, side%, slice%) = reinf_time% sl_num_reinfs%(box%, side%, slice%) += 1 PROCprint_reinfs(box%, side%) ENDPROC REM ************* record the single lever data************** DEF PROCrecord_single_lever_data(box%) PRINT "n/a"; ","; "n/a";","; FNtotal_num_presses(box%, slice%); ","; PRINT "n/a"; ","; "n/a"; ","; FNtotal_num_reinfs(box%, slice%); "," ENDPROC