Stages¶
The stages of the experiment.
-
class
forced_choice.stages.
RootStage
(**kwargs)¶ Bases:
cplcom.moa.stages.ConfigStageBase
The stage that creates and initializes all the Barst devices (or simulation devices if
ExperimentApp.simulate
).-
configs
¶ A dict whose keys are names of experiment types and whose values are
ExperimentConfig
instances configuring the corresponding experiment.
-
create_daqin_devs
(sim, settings)¶ Creates the daq input device,
daq_in_dev
.
-
create_daqout_devs
(sim, settings)¶ Creates the daq output device,
daq_out_dev
.
-
daq_in_dev
¶ The Switch and Sense device,
DAQInDevice
when using actual hardware, or aDAQInDeviceSim
whensimulate
the hardware.
-
daq_out_dev
¶ The Switch and Sense device,
DAQOutDevice
when using actual hardware, or aDAQOutDeviceSim
whensimulate
the hardware.
-
filter_len
¶ The number of previous trials to average when displaying the trial result in the graphs.
-
ftdi_chan
¶ The FTDI controller device,
FTDIDevChannel
when using actual hardware, or None whensimulate
.
-
log_filename
¶ The pattern that will be used to generate the log filenames for each trial. It is generated as follows:
strftime(log_name_pat.format(**{'animal': animal_id, 'trial': trial, 'block': block}))
Which basically means that all instances of
{animal}
,{trial}
, and{block}
in the filename will be replaced by the animal name given in the GUI, the current trial, and block numbers. Then, it’s is passed to strftime that formats any time parameters to get the log name used for that animal.If the filename matches an existing file, the new data will be appended to that file.
-
mfc_a
¶ The MFC controlling one odor stream,
MFC
when using actual hardware, or aNumericPropertyChannel
whensimulate
the hardware.
-
mfc_air
¶ The MFC controlling the air,
MFC
when using actual hardware, or aNumericPropertyChannel
whensimulate
the hardware.
-
mfc_b
¶ The MFC controlling the other odor stream,
MFC
when using actual hardware, or aNumericPropertyChannel
whensimulate
the hardware.
-
n_valve_boards
¶ The number of valve boards connected. Each board typically controls 8 valves.
-
odor_dev
¶ The FTDI valve board,
FTDIOdors
when using actual hardware, or aFTDIOdorsSim
whensimulate
the hardware.
-
simulate
¶ Whether the user has chosen to simulate the experiment. When
True
, no actual hardware is required and all the hardware will be emulated by software and virtual devices.
-
sound_file_l
¶ The sound file used in training as a cue when the left side is rewarded.
-
sound_file_r
¶ The sound file used in training as a cue when the right side is rewarded.
-
sound_l
¶ The
cplcom.moa.device.ffplayer.FFPyPlayerAudioDevice
that plays the file provided insound_file_l
.
-
sound_r
¶ The
cplcom.moa.device.ffplayer.FFPyPlayerAudioDevice
that plays the file provided insound_file_r
.
-
tracker
= None¶ The
ObjectStateTracker
instance used to process the device activation and deactivation during startup and shutdown.
-
use_mfc
¶ Whether a MFC is used for mixing the odor streams (i.e. two odors are presented in a mixed form for each trial).
-
-
class
forced_choice.stages.
ExperimentConfig
(load=True, **kwargs)¶ Bases:
moa.base.MoaBase
Stores the configuration parameters for a experiment.
-
NO_valve
¶ A list of, for each block in
num_blocks
, the normally open (mineral oil) odor valve. I.e. the valve which is normally open and closes during the trial when the odor is released.
-
air_rate
¶ A list of, for each block in
num_blocks
, the flow rate for the air stream using the air MFC whenRootStage.use_mfc
orRootStage.use_mfc_air
.
-
apply_config_ui
()¶ Updates the odor and experiment values of the UI using the provided configuration parameters.
-
bad_iti
¶ The ITI duration of a failed trial.
-
beta_trials_max
¶ For each odor, it is the last
beta_trials_max
trials (of that odor) to take into account when computing the accuracy rate for that odor.Trials for this odor further back in history than
beta_trials_max
specific to this odor are dropped.
-
beta_trials_min
¶ The minimum number of trials for each odor that must have occured before
odor_beta
bias compensation is activated. If the number of trial that occurred for any odor is less thanbeta_trials_min
, bias compensation is disabled.
-
do_equal_random
(n, m, cond, last_val=None)¶ Implements
odor_equalizer
when selected.
-
do_odor_list
(block, block_odors, odor_opts)¶ Reads the odor selection for each trial from a list when
odor_method
‘`list’`.
-
do_odor_random
(block, block_odors, odor_opts, method, n)¶ When
odor_method
is not'list'
, but is random or constant, this generates the odors list for each trial.
-
good_iti
¶ The ITI duration of a passed trial.
-
incomplete_iti
¶ The ITI duration of a trial where the animal did not hold its nose long enough in the nose port and
min_nose_poke
was not satisfied.
-
max_decision_duration
¶ A list of, for each block in
num_blocks
, the maximum duration of the decision stage. After this duration, the stage will terminate and proceed to the ITI stage even if the animal didn’t visit the reward port.The decision determines whether a reward is dispensed and the duration of the ITI.
If zero, there is no maximum.
-
max_nose_poke
¶ A list of, for each block in
num_blocks
, the maximum duration of the nose port stage. After this duration, the stage will terminate and proceed to the decision stage even if the animal is still in the nose port.If zero, there is no maximum.
-
mfc_a_rate
¶ A list of, for each block in
num_blocks
, the flow rate for the odor stream a using the odor a MFC whenRootStage.use_mfc
.
-
mfc_b_rate
¶ A list of, for each block in
num_blocks
, the flow rate for the odor stream b using the odor b MFC whenRootStage.use_mfc
.
-
min_nose_poke
¶ A list of, for each block in
num_blocks
, the minimum duration in the nose port AFTER the odor is released (i.e.odor_delay
). A nose port exit less than this duration will result in an incomplete trial. The ITI will then beincomplete_iti
.If zero, there is no minimum.
-
mix_dur
¶ A list of, for each block in
num_blocks
, how long to pass the air stream through the odor vials before the trial starts (during the last ITI).This ensures that when the animal enters the nose port, the odor is stream is already saturated. During this time the odor is directed to teh vaccum.
-
mix_valve
¶ A list of, for each block in
num_blocks
, the valve that directs the odor to go to vacuum or to the animal. Before the odor goes to the animal, the odor is mixed and evacuated to vacuum in order to saturate the air stream into a steady state condition.
-
num_blocks
¶ The number of blocks to run. Each block runs
num_trials
trials.All the configuration parameters that are lists, e.g.
num_trials
can specify a different value for each block.If the number of elements in these lists are less than the number of blocks, the last value of the list is used for the remaining blocks. E.g. for 10 blocks, if
num_trials
is[5, 6, 2]
, then blocks 2 - 9 will have 2 trials.
-
num_pellets
¶ The number of sugar pellets to deliver upon a successful trial.
-
num_trials
¶ A list of the number of trials to run for each block of
num_blocks
.
-
odor_beta
¶ A list of, for each block in
num_blocks
, the beta value to use when compensating for unequal side performance. This compensation is applied dynamically during the trials on top of any previous odor computations.We keep track of the accuracy rate of every odor (i.e. how often the animal chooses the incorrectly for that odor). Then, odors where the animal performed poorly will get presented with a higher probability.
A
odor_beta
value of zero disables this bias compensation. A value of e.g. 10, will bias very strongly towards changing the next trial odor to be a odor in which the animal performed poorly. The closer to zero, the lower such bias compensation. A value of 2-3 is reasonable.The trials are accumulated across blocks so a new block does not clear the odor bias history.
-
odor_delay
¶ A list of, for each block in
num_blocks
, how long to delay the odor delivery onset from when the animal enters the nose port.If zero, there’s no delay.
-
odor_equalizer
¶ A list of, for each block in
num_blocks
, the number of trials during which all the odors for that block will be presented an equal number of times.That is, during these exclusively grouped
odor_equalizer
trials, no odor will be presented more times than any other odor.The number of odors for each block listed in
odor_selection
must divide without remainder theodor_equalizer
value for that block.
-
odor_method
¶ A list of, for each block in
num_blocks
, the method used to determine which odor to use in the trials for the odors listed inodor_selection
.Possible methods are constant, randomx, or list.
odor_selection
is used to select the odor to be used with this method.- constant:
odor_selection
is a 2d list of odors of lengthnum_blocks
. Each element in the outer list is a single element list containing the odor that is used for all the trials of that block.- randomx: x is a number or empty
odor_selection
is a 2d list of odors of lengthnum_blocks
. Each inner list is a list of odors from which the trial odor would be randomly selected for each trial in the block.If the method is
random
, the odor is randomly selected from that list. If random is followed by an integer, e.g.random2
, then it’s random with the condition that no odor can be repeated more then x (2 in this) times successively.- list:
odor_selection
is a 2d list of filenames. The files are read for each block and the odors listed in the file is used for the trials.The structure of the text file is a line for each block. Each line is a comma separated list, with the first column being the block number and the other column the odors to use for that block.
Each inner list in the 2d list (line) can only have a single filename for that block.
-
odor_names
¶ A
RootStage.n_valve_boards
* 8 long list for each valve, indicating the name of the odor for that valve.
-
odor_opts
= None¶ A list containing, for each block, a list of all the possible odors for this block from which we select a odor for every trial.
Each element is a tuple of 1 or two odors with the same structure as the elements returned by
extract_odor()
.
-
odor_path
¶ The filename of a file containing the names of odors and which side to reward that odor.
The structure of the file is as follows: each line describes an odor and is a 3 or 4 column comma separated list of
(idx, name, side, mfc)
, where idx is the zero-based valve index. Name is the odor name. And side is the side of the odor to reward (r, l, rl, lr, or -). If using an mfc, the 4th column is eithera
, orb
indicating the mfc to use of that valve.An example file is:
1, mineral oil, r 4, citric acid, rl 5, limonene, l ...
-
odor_selection
¶ A list of, for each block in
num_blocks
, a inner list of odors used to select from trial odors for each block. Seeodor_method
.
-
odor_side
¶ A
RootStage.n_valve_boards
* 8 long list for each valve, indicating which side is rewarded for that valve.
-
sound_cue_delay
¶ A list of, for each block in
num_blocks
, the random amount of time to delay the sound cue AFTERmin_nose_poke
elapsed. It’s a value between zero andsound_cue_delay
.If zero or if
sound_dur
is zero, there is no delay.
-
sound_dur
¶ A list of, for each block in
num_blocks
, the duration to play the sound cue aftersound_cue_delay
. It plays eitherRootStage.sound_file_r
orRootStage.sound_file_l
depending on the trial odor.If zero, no sound is played.
-
trial_odors
= None¶ A 2d list of the odors for each trial in each block.
Each element is a tuple of 1 or two odors with the same structure as the elements returned by
extract_odor()
.
-
valve_mfc
= None¶ A
RootStage.n_valve_boards
* 8 long list for each valve, indicating whether MFC a or b is used for that valve.
-
wait_for_nose_poke
¶ A list of, for each block in
num_blocks
, whether to wait for a nose poke or to immediately go to the reward stage.When False, entering the reward port will dispense reward and end the trial. The ITI will then be
good_iti
for that block.
-
-
class
forced_choice.stages.
AnimalStage
(**kwargs)¶ Bases:
moa.stage.MoaStage
In this stage, each loop iteration runs another animal.
-
animal_id
¶ The animal id of the current animal.
-
block
¶ The current block number.
-
config
¶ The
ExperimentConfig
instance used to configure the current animal.
-
do_decision
(r, l, timed_out)¶ Executed after the reward port entry or after waiting for the reward port entry timed out. It decides whether the animal is rewarded.
-
do_nose_poke
()¶ Executed after the first nose port entry of the trial.
-
do_nose_poke_exit
(timed_out)¶ Executed after the first nose port exit of the trial.
-
do_odor_release
()¶ After
start_mixing()
, it redirects the already mixing odor to the animal.
-
init_trial
(block, trial)¶ Starts the trial.
-
initialize_animal
()¶ Executed before the start of a new animal.
-
initialize_box
()¶ Turns on fans, lights etc at the beginning of the experiment.
-
iti
¶ The ITI used for this trial.
-
nose_poke_exit_timed_out
= False¶ Whether the animal was in the nose port longer than
ExperimentConfig.max_nose_poke
and it timed out.
-
nose_poke_exit_ts
= None¶ The time of the nose port exit.
-
nose_poke_ts
= None¶ The time of the nose port entry.
-
odor
= None¶ The odor to reward for this trial.
-
odor_outcome
= {}¶ keys are the odor indices, values are a list with 0 or 1 indicating the trial reward outcome for that odor. This combines all the blocks for the animal.
-
odor_start_ts
= None¶ The time when the odor was released to the animal.
-
odor_widgets
= []¶ List of
forced_choice.graphics.TrialPrediction
instances for all the blocks, containing all the trials.
-
outcome
= None¶ Whether this trial was an incomplete.
-
outcome_wid
= None¶ The
forced_choice.graphics.TrialOutcome
widget describing the current trial.
-
outcomes
= []¶ 1 or 0 for each trial indicating the trial reward outcome. Reset at each block.
-
post_trial
()¶ Executed after each trial.
-
pre_block
()¶ Executed before each block.
-
pre_trial
()¶ Executed before each trial.
-
predict_widget
= None¶ forced_choice.graphics.TrialPrediction
instance for the current trial.
-
reward_entry_timed_out
= False¶ Whether the animal waited longer than
ExperimentConfig.max_decision_duration
before making a decision by going to either feeder side and it timed out.
-
reward_entry_ts
= None¶ The time of the reward port entry.
-
reward_side
¶ The feeder device name of the side on which to reward this trial.
-
side_went
= None¶ The feeder side the animal visited.
-
sound
¶ The sound file, from
RootStage.sound_r
andRootStage.sound_l
, to use for this trial.
-
start_mixing
()¶ Opens the odor valves to start mixing with the air stream, but directs it to the vacuum.
-
total_fail
¶ Total number of failed trials for this block.
-
total_incomplete
¶ Total number of incomplete trials for this block.
-
total_pass
¶ Total number of passed trials for this block.
-
trial
¶ The current trial number.
-
trial_start_time
= None¶ The start time of the trial in human readable clock format.
-
trial_start_ts
= None¶ The start time of the trial in seconds.
-
update_trial_odor
()¶ Updates the trial odor using
ExperimentConfig.beta
when non-zero.
-
-
forced_choice.stages.
extract_odor
(odors, block, N)¶ Takes the list of odors for a block, provided in
ExperimentConfig.odor_selection
, and parses it and returns the possible odors to choose from for that block.Parameters: - odors: list
The odors list for a specific block, provided in
ExperimentConfig.odor_selection
.- block: int
The block associated with the odors.
- N: int
The total of number of odor valves available (typically 8 or 16).
Returns: A list of the parsed odors.
Each element of the list is a 1 or 2-tuple. The elements in this tuple is each a 3-tuple with the valve number controlling this odor, the probability p of this odor being rewarded, even if correctly chosen by the subject when provided, and the MFC rate at which this odor airflow will bubble through (in order to mix them), if
RootStage.use_mfc
.
-
forced_choice.stages.
select_odor
(odors)¶ Given a element of the list returned by
extract_odor()
, if the element is a 1-tuple it returns the first item, otherwise, it returns the odor with the higher flow rate of the two.It is the odor (with the higher flow rate) that is rewarded when the animal picks that side when a odor mixture is presented.