Skip to content

ClosedEconomy_PR1

Kravitz Lab edited this page Jan 31, 2026 · 3 revisions

ClosedEconomy_PR1

Overview

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.

Schedule of reinforcement.

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.

Code

/*
  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(" ");
}

Navigation

๐Ÿ”ง Get started with FED3

๐ŸŽฎ Program FED3

๐Ÿ Behavioral Code

๐Ÿ“ Example menus (switch between programs without reflashing FED3)

๐Ÿ” FED3 pellets

๐Ÿ“ข FED3 Publications

๐ŸŽจ FED3 Artwork

๐Ÿ˜ตโ€๐Ÿ’ซ FED3 troubleshooting

Clone this wiki locally