-
Notifications
You must be signed in to change notification settings - Fork 19
ClosedEconomy_PR1
The first use of the progressive ratio task was published in 1961, as a means to measure the relative strength or โattractivenessโ of rewards (Hodos, W. (1961). Progressive Ratio as a Measure of Reward Strength. Science, 134(3483), 943โ944). Since this pioneering study, thousands of publications have adapted versions of the progressive ratio task to assess motivation for food, brain stimulation and pharmacological agents. Briefly, the task requires an animal to make increasing numbers of operant responses (typically a nosepoke or a lever press) to obtain each reward; the ratio of these required responses increases progressively throughout the task. In a classical progressive ratio assay, this task would be conducted in an operant box, and the task would end if an animal failed to make any active responses within a pre-determined time (i.e. 15 or 30 minutes), at which point the task would end and the number of responses within the last successfully completed ratio is referred to as the โbreak pointโ, a proxy for an animalโs motivation to obtain the reward.
The โclosed economyโ version of the task was popularized by Collier and colleagues, and used more recently by the Rowland and Beeler labs. This versioin of the task requires that the animal live in the test environment and earn 100% of their food through operant responses. Rather than the terminating the task after the pre-determined time, the ratio resets and the ratio re-initializes from the beginning if the animal withholds responding for a preset time (often 30 minutes). This eliminates the need for food restriction, which itself profoundly increases motivation for food rewards (Hodos, W. 1961). The closed economy version of the task gives high-dimensional data with multiple breakpoints per subject; the distribution of these breakpoints can then be compared before and after experimental manipulations to get a comprehensive picture of how reward attractiveness is affected.
Progressive ratio schedules can be either arithmetic or logarithmic/exponential (Fig X), and the ratio may increment following each reward, or after a set interval of rewards. The exponential schedule allows for more rapid progression through a range of reinforcer values to establish the break-point, while arithmetic or base-schedules give more measurements at each ratio requirement for more fine-grained analysis of response patterns. Readers are referred to excellent reviews on how these different schedules shape behavior on the progressive ratio task (Killeen et al., J Exp Psychol, 2009; Richardson and Roberts 1996).
โTime outโ delay. The โTime outโ delay refers to the length of time an animal must go without making a response before the reinforcement schedule resets. In the closed economy design, this is critically important, as an animal must be able to earn sufficient rewards to maintain body weight from the task. The reinforcement schedule should also be considered. For example, we have found that mice will regularly make over a hundred nose-pokes for a single pellet. However, the length of time required to complete these nose-pokes ensures that pellets are earned several minutes apart, despite intensive efforts from the mouse. In some schedules, requiring a 30 minute delay before ratio reset can make it impossible for mice to earn sufficient pellets from the task to maintain body weight, which can be problematic both for animal welfare, or for interpreting results from the task.
/*
Feeding experimentation device 3 (FED3)
This is a resetting progressive ratio task meant to be used in a closed economy setting as in Mourra et al., 2020: https://pubmed.ncbi.nlm.nih.gov/31809732/
The task starts with left pokes active on an FR1, and incrememnts the FR +2 for each earned pellet. ie: FR1, FR3, FR5, etc.
If 30 minutes pass without a left or right poke the FR ratio resets to FR1
Code by: Kia Barclay and Lex Kravitz
alexxai@wustl.edu, kbarclay@wustl.edu
January, 2021
This project is released under the terms of the Creative Commons - Attribution - ShareAlike 3.0 license:
human readable: https://creativecommons.org/licenses/by-sa/3.0/
legal wording: https://creativecommons.org/licenses/by-sa/3.0/legalcode
*/
#include <FED3.h> //Include the FED3 library
int poke_num = 0; //number of pokes since last pellet
int pellets_in_current_block = 0; //pellet number in current block
int pokes_required = 1; //current FR
unsigned long poketime = 0; //time of poke
int resetInterval = 1800; //number of seconds without a poke to reset
String sketch = "ClosedEcon_PR1"; //Unique identifier text for each sketch - only the first 8 characters will show on the screen
FED3 fed3 (sketch); //Start the FED3 object
void setup() {
fed3.begin(); //Setup the FED3 hardware
fed3.FEDmode = 1; //Customize the display options to FEDmode 1 for an operant session
fed3.EnableSleep = true; //Set to false to inhibit sleeping to use the Serial port; Set to true to reduce battery power
fed3.FR = pokes_required;
}
void loop() {
fed3.run(); //Call fed.run at least once per loop
checkReset(); //Check if it's time to reset to FR1
if (fed3.Left) { //If left poke is triggered
fed3.logLeftPoke(); //log Left poke
poke_num++; //increment poke number.
poketime = fed3.unixtime; //update the current time of poke
serialoutput(); //print data to the Serial monitor - EnableSleep must be false to use Serial monitor
if (poke_num == pokes_required) { //check if current FR has been achieved
fed3.ConditionedStimulus(); //Deliver conditioned stimulus (tone and lights)
pellets_in_current_block++; //increment the pellet number by 1
fed3.BlockPelletCount = pellets_in_current_block;
fed3.Feed(); //Deliver pellet
fed3.BNC(500, 1); //Send 500ms pulse to the BNC output when pellet is detected (move this line to deliver this pulse elsewhere)
pokes_required += 1; //Edit this line to change the PR incremementing formula. Default is for each pellet add 1 to the pokes required.
fed3.FR = pokes_required; //Update the FR requirement in the functions in the FED3 library
poke_num = 0; //reset poke_num to 0
}
}
if (fed3.Right) { //If right poke is triggered
fed3.logRightPoke(); //log right poke
}
}
//////////////////////////////////////////////////////////////////////////////////////
//if more than 30 mins has passed since last poke -- reset the block and parameters
//////////////////////////////////////////////////////////////////////////////////////
void checkReset() {
if (fed3.unixtime - poketime >= resetInterval) { //if the reset interval has elapsed since last poke
pellets_in_current_block = 0;
fed3.BlockPelletCount = pellets_in_current_block;
poke_num = 0;
pokes_required = 1;
fed3.FR = pokes_required;
Serial.println(" ");
Serial.println("****"); //print **** on the serial monitor
fed3.pixelsOn(5, 5, 5, 5);
delay(200);
fed3.pixelsOff();
poketime = fed3.unixtime; //store the current time of poke
}
}
//////////////////////////////////////////////////////////////////////////////////////
// Use Serial.print statements for debugging
//////////////////////////////////////////////////////////////////////////////////////
void serialoutput() {
Serial.print("Unixtime: ");
Serial.println(fed3.unixtime);
Serial.println("Pellets RightPokes LeftPokes Poke_Num Pel Pokes_Required PokeTime Reset FR");
Serial.print(" ");
Serial.print(fed3.PelletCount);
Serial.print(" ");
Serial.print(fed3.RightCount);
Serial.print(" ");
Serial.print(fed3.LeftCount);
Serial.print(" ");
Serial.print(poke_num);
Serial.print(" ");
Serial.print(pellets_in_current_block);
Serial.print(" ");
Serial.print(pokes_required);
Serial.print(" ");
Serial.print(poketime);
Serial.print(" ");
Serial.print(fed3.FR);
Serial.println(" ");
Serial.println(" ");
}