Link Search Menu Expand Document

This notebook parses the eprime files into BIDS valid events TSVs.

if (!require("pacman")) install.packages("pacman")

## Loading required package: pacman

pacman::p_load(rprime, dplyr, tidyverse, rjson)

Let’s start with an example:

rp <- read_eprime("~/dropbox/rawbx/RTG1_1ITCscanner1LLA-05200-1.txt")

experiment_data <- FrameList(rp)
message("Structure of eprime:")

## Structure of eprime:

print(preview_frames(experiment_data))

## 
##  Eprime.Level Running Procedure
##             1  Header    Header
## List of 17
##  $ Eprime.Level       : num 1
##  $ Eprime.LevelName   : chr "Header_"
##  $ Eprime.Basename    : chr "RTG1_1ITCscanner1LLA-05200-1"
##  $ Eprime.FrameNumber : chr "1"
##  $ Procedure          : chr "Header"
##  $ Running            : chr "Header"
##  $ VersionPersist     : chr "1"
##  $ LevelName          : chr "LogLevel10"
##  $ Experiment         : chr "RTG1_1ITCscanner1LLA"
##  $ SessionDate        : chr "06-10-2011"
##  $ SessionTime        : chr "13:30:30"
##  $ SessionTimeUtc     : chr "5:30:30 PM"
##  $ Subject            : chr "05200"
##  $ Session            : chr "1"
##  $ RandomSeed         : chr "1055496015"
##  $ Group              : chr "1"
##  $ Display.RefreshRate: chr "60.052"
##  - attr(*, "class")= chr [1:2] "EprimeFrame" "list"
## 
##  Eprime.Level   Running Procedure
##             3 TrialList TrialProc
## List of 66
##  $ Eprime.Level                     : num 3
##  $ Eprime.LevelName                 : chr "TrialList_1"
##  $ Eprime.Basename                  : chr "RTG1_1ITCscanner1LLA-05200-1"
##  $ Eprime.FrameNumber               : chr "2"
##  $ Procedure                        : chr "TrialProc"
##  $ Running                          : chr "TrialList"
##  $ Offer                            : chr "23"
##  $ delay                            : chr "21"
##  $ NullDuration                     : chr "5000"
##  $ LeftRight                        : chr "0"
##  $ FeedbackDur                      : chr "1672"
##  $ Cycle                            : chr "1"
##  $ Sample                           : chr "1"
##  $ nullscreen.OnsetDelay            : chr "303"
##  $ nullscreen.OnsetTime             : chr "54348"
##  $ nullscreen.DurationError         : chr "-303"
##  $ nullscreen.StartTime             : chr "54047"
##  $ nullscreen.OffsetTime            : chr "58845"
##  $ nullscreen.FinishTime            : chr "58845"
##  $ nullscreen.ActionDelay           : chr "0"
##  $ nullscreen.ActionTime            : chr "54348"
##  $ nullscreen.OffsetDelay           : chr "0"
##  $ Choice1.OnsetDelay               : chr "0"
##  $ Choice1.OnsetTime                : chr "59045"
##  $ Choice1.DurationError            : chr "-999999"
##  $ Choice1.Duration                 : chr "4000"
##  $ Choice1.StartTime                : chr "58846"
##  $ Choice1.OffsetTime               : chr "61373"
##  $ Choice1.FinishTime               : chr "61373"
##  $ Choice1.OffsetDelay              : chr "-999999"
##  $ Choice1.RTTime                   : chr "61373"
##  $ Choice1.RT                       : chr "2328"
##  $ Choice1.RESP                     : chr "y"
##  $ Choice1.CRESP                    : chr "r"
##  $ FeedbackDisplay6.OnsetDelay      : chr "939"
##  $ FeedbackDisplay6.OnsetTime       : chr "62312"
##  $ FeedbackDisplay6.DurationError   : chr "-939"
##  $ FeedbackDisplay6.Duration        : chr "1672"
##  $ FeedbackDisplay6.StartTime       : chr "62310"
##  $ FeedbackDisplay6.OffsetTime      : chr "62845"
##  $ FeedbackDisplay6.FinishTime      : chr "62845"
##  $ FeedbackDisplay6.OffsetDelay     : chr "0"
##  $ Choice.OnsetDelay                : chr "0"
##  $ Choice.OnsetTime                 : chr "0"
##  $ Choice.DurationError             : chr "0"
##  $ Choice.Duration                  : chr "4000"
##  $ Choice.StartTime                 : chr "0"
##  $ Choice.OffsetTime                : chr "0"
##  $ Choice.FinishTime                : chr "0"
##  $ Choice.TargetOffsetTime          : chr "0"
##  $ Choice.TargetOnsetTime           : chr "0"
##  $ Choice.OffsetDelay               : chr "0"
##  $ Choice.RTTime                    : chr "0"
##  $ Choice.RT                        : chr "0"
##  $ Choice.RESP                      : chr ""
##  $ Choice.CRESP                     : chr ""
##  $ FeedbackDisplay3.OnsetDelay      : chr "0"
##  $ FeedbackDisplay3.OnsetTime       : chr "0"
##  $ FeedbackDisplay3.DurationError   : chr "0"
##  $ FeedbackDisplay3.Duration        : chr "0"
##  $ FeedbackDisplay3.StartTime       : chr "0"
##  $ FeedbackDisplay3.OffsetTime      : chr "0"
##  $ FeedbackDisplay3.FinishTime      : chr "0"
##  $ FeedbackDisplay3.TargetOffsetTime: chr "0"
##  $ FeedbackDisplay3.TargetOnsetTime : chr "0"
##  $ FeedbackDisplay3.OffsetDelay     : chr "0"
##  - attr(*, "class")= chr [1:2] "EprimeFrame" "list"
## 
##  Eprime.Level   Running Procedure
##             2 BlockList BlockProc
## List of 9
##  $ Eprime.Level      : num 2
##  $ Eprime.LevelName  : chr "BlockList_1"
##  $ Eprime.Basename   : chr "RTG1_1ITCscanner1LLA-05200-1"
##  $ Eprime.FrameNumber: chr "52"
##  $ Procedure         : chr "BlockProc"
##  $ Running           : chr "BlockList"
##  $ PracticeMode      : chr "?"
##  $ Cycle             : chr "1"
##  $ Sample            : chr "1"
##  - attr(*, "class")= chr [1:2] "EprimeFrame" "list"
## 
##  Eprime.Level Running Procedure
##             1    <NA>      <NA>
## List of 65
##  $ Eprime.Level            : num 1
##  $ Eprime.LevelName        : logi NA
##  $ Eprime.Basename         : chr "RTG1_1ITCscanner1LLA-05200-1"
##  $ Eprime.FrameNumber      : chr "53"
##  $ Procedure               : logi NA
##  $ Running                 : logi NA
##  $ Experiment              : chr "RTG1_1ITCscanner1LLA"
##  $ SessionDate             : chr "06-10-2011"
##  $ SessionTime             : chr "13:30:30"
##  $ SessionTimeUtc          : chr "5:30:30 PM"
##  $ Subject                 : chr "05200"
##  $ Session                 : chr "1"
##  $ RandomSeed              : chr "1055496015"
##  $ Group                   : chr "1"
##  $ Display.RefreshRate     : chr "60.052"
##  $ Slide2.OnsetDelay       : chr "19"
##  $ Slide2.OnsetTime        : chr "8774"
##  $ Slide2.DurationError    : chr "-999999"
##  $ Slide2.PreRelease       : chr "0"
##  $ Slide2.Duration         : chr "-1"
##  $ Slide2.StartTime        : chr "8755"
##  $ Slide2.OffsetTime       : chr "19995"
##  $ Slide2.FinishTime       : chr "19995"
##  $ Slide2.TimingMode       : chr "0"
##  $ Slide2.CustomOnsetTime  : chr "0"
##  $ Slide2.CustomOffsetTime : chr "0"
##  $ Slide2.ActionDelay      : chr "0"
##  $ Slide2.ActionTime       : chr "8774"
##  $ Slide2.TargetOffsetTime : chr "-1"
##  $ Slide2.TargetOnsetTime  : chr "8755"
##  $ Slide2.OffsetDelay      : chr "-999999"
##  $ Slide2.RTTime           : chr "19995"
##  $ Slide2.ACC              : chr "0"
##  $ Slide2.RT               : chr "11221"
##  $ Slide2.RESP             : chr "n"
##  $ Slide2.CRESP            : chr ""
##  $ Slide1.OnsetTime        : chr "20000"
##  $ Slide1.DurationError    : chr "-999999"
##  $ Slide1.Duration         : chr "-1"
##  $ Slide1.StartTime        : chr "19998"
##  $ Slide1.OffsetTime       : chr "54045"
##  $ Slide1.FinishTime       : chr "54045"
##  $ Slide1.RT               : chr "34045"
##  $ Goodbye.OnsetDelay      : chr "2"
##  $ Goodbye.OnsetTime       : chr "558047"
##  $ Goodbye.DurationError   : chr "0"
##  $ Goodbye.PreRelease      : chr "0"
##  $ Goodbye.Duration        : chr "6000"
##  $ Goodbye.StartTime       : chr "557853"
##  $ Goodbye.OffsetTime      : chr "564047"
##  $ Goodbye.FinishTime      : chr "564047"
##  $ Goodbye.TimingMode      : chr "0"
##  $ Goodbye.CustomOnsetTime : chr "0"
##  $ Goodbye.CustomOffsetTime: chr "0"
##  $ Goodbye.ActionDelay     : chr "1"
##  $ Goodbye.ActionTime      : chr "558048"
##  $ Goodbye.TargetOffsetTime: chr "564047"
##  $ Goodbye.TargetOnsetTime : chr "558045"
##  $ Goodbye.OffsetDelay     : chr "0"
##  $ Goodbye.RTTime          : chr "0"
##  $ Goodbye.ACC             : chr "0"
##  $ Goodbye.RT              : chr "0"
##  $ Goodbye.RESP            : chr ""
##  $ Goodbye.CRESP           : chr ""
##  $ Clock.StartTimeOfDay    : chr "6/10/2011 1:30:30 PM"
##  - attr(*, "class")= chr [1:2] "EprimeFrame" "list"
## NULL

trial <- filter_in(experiment_data, "Running", "TrialList")
block <- filter_in(experiment_data, "Running", "BlockList")
slides <- filter_in(experiment_data, "Eprime.Level", 1)

slides_df <- to_data_frame(slides) %>%
  readr::type_convert()

## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   .default = col_double(),
##   Eprime.LevelName = col_character(),
##   Eprime.Basename = col_character(),
##   Procedure = col_character(),
##   Running = col_character(),
##   LevelName = col_character(),
##   Experiment = col_character(),
##   SessionDate = col_character(),
##   SessionTime = col_time(format = ""),
##   SessionTimeUtc = col_time(format = ""),
##   Subject = col_character(),
##   Slide2.RESP = col_character(),
##   Slide2.CRESP = col_logical(),
##   Goodbye.RESP = col_logical(),
##   Goodbye.CRESP = col_logical(),
##   Clock.StartTimeOfDay = col_character()
## )
## ℹ Use `spec()` for the full column specifications.

trial_df <- to_data_frame(trial) %>%
  readr::type_convert()

## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   .default = col_double(),
##   Eprime.LevelName = col_character(),
##   Eprime.Basename = col_character(),
##   Procedure = col_character(),
##   Running = col_character(),
##   Choice1.RESP = col_character(),
##   Choice1.CRESP = col_character(),
##   Choice.RESP = col_character(),
##   Choice.CRESP = col_character()
## )
## ℹ Use `spec()` for the full column specifications.

head(trial_df)

##   Eprime.Level Eprime.LevelName              Eprime.Basename Eprime.FrameNumber
## 1            3      TrialList_1 RTG1_1ITCscanner1LLA-05200-1                  2
## 2            3      TrialList_2 RTG1_1ITCscanner1LLA-05200-1                  3
## 3            3      TrialList_3 RTG1_1ITCscanner1LLA-05200-1                  4
## 4            3      TrialList_4 RTG1_1ITCscanner1LLA-05200-1                  5
## 5            3      TrialList_5 RTG1_1ITCscanner1LLA-05200-1                  6
## 6            3      TrialList_6 RTG1_1ITCscanner1LLA-05200-1                  7
##   Procedure   Running Offer delay NullDuration LeftRight FeedbackDur Cycle
## 1 TrialProc TrialList  23.0    21         5000         0        1672     1
## 2 TrialProc TrialList  28.0     5         5000         1        2328     1
## 3 TrialProc TrialList  30.5    55         5000         1        1984     1
## 4 TrialProc TrialList  39.0    34        17000         1        2440     1
## 5 TrialProc TrialList  25.0     7         8000         0        1736     1
## 6 TrialProc TrialList  22.5    45         2000         1        2584     1
##   Sample nullscreen.OnsetDelay nullscreen.OnsetTime nullscreen.DurationError
## 1      1                   303                54348                     -303
## 2      2                     0                63045                        0
## 3      3                     0                72045                        0
## 4      4                     0                81045                        0
## 5      5                     0               102045                        0
## 6      6                     0               114045                        0
##   nullscreen.StartTime nullscreen.OffsetTime nullscreen.FinishTime
## 1                54047                 58845                 58845
## 2                62853                 67845                 67845
## 3                71854                 76845                 76845
## 4                80853                 97845                 97845
## 5               101854                109845                109845
## 6               113853                115845                115845
##   nullscreen.ActionDelay nullscreen.ActionTime nullscreen.OffsetDelay
## 1                      0                 54348                      0
## 2                      0                 63045                      0
## 3                      0                 72045                      0
## 4                      0                 81045                      0
## 5                      0                102045                      0
## 6                      0                114045                      0
##   Choice1.OnsetDelay Choice1.OnsetTime Choice1.DurationError Choice1.Duration
## 1                  0             59045               -999999             4000
## 2                  0             59045               -999999             4000
## 3                  0             59045               -999999             4000
## 4                  0             59045               -999999             4000
## 5                  0            110045               -999999             4000
## 6                  0            110045               -999999             4000
##   Choice1.StartTime Choice1.OffsetTime Choice1.FinishTime Choice1.OffsetDelay
## 1             58846              61373              61373             -999999
## 2             58846              61373              61373             -999999
## 3             58846              61373              61373             -999999
## 4             58846              61373              61373             -999999
## 5            109846             112309             112309             -999999
## 6            109846             112309             112309             -999999
##   Choice1.RTTime Choice1.RT Choice1.RESP Choice1.CRESP
## 1          61373       2328            y             r
## 2          61373       2328            y             r
## 3          61373       2328            y             r
## 4          61373       2328            y             r
## 5         112309       2264            y             r
## 6         112309       2264            y             r
##   FeedbackDisplay6.OnsetDelay FeedbackDisplay6.OnsetTime
## 1                         939                      62312
## 2                         939                      62312
## 3                         939                      62312
## 4                         939                      62312
## 5                           3                     112312
## 6                           3                     112312
##   FeedbackDisplay6.DurationError FeedbackDisplay6.Duration
## 1                           -939                      1672
## 2                           -939                      1672
## 3                           -939                      1672
## 4                           -939                      1672
## 5                             -3                      1736
## 6                             -3                      1736
##   FeedbackDisplay6.StartTime FeedbackDisplay6.OffsetTime
## 1                      62310                       62845
## 2                      62310                       62845
## 3                      62310                       62845
## 4                      62310                       62845
## 5                     112311                      113845
## 6                     112311                      113845
##   FeedbackDisplay6.FinishTime FeedbackDisplay6.OffsetDelay Choice.OnsetDelay
## 1                       62845                            0                 0
## 2                       62845                            0                 0
## 3                       62845                            0                 0
## 4                       62845                            0                 0
## 5                      113845                            0                 0
## 6                      113845                            0                 0
##   Choice.OnsetTime Choice.DurationError Choice.Duration Choice.StartTime
## 1                0                    0            4000                0
## 2            68045              -999999            4000            67846
## 3            77045              -999999            4000            76846
## 4            98045              -999999            4000            97847
## 5            98045              -999999            4000            97847
## 6           116045              -999999            4000           115846
##   Choice.OffsetTime Choice.FinishTime Choice.TargetOffsetTime
## 1                 0                 0                       0
## 2             69717             69717                   71845
## 3             79061             79061                   80845
## 4             99605             99605                  101845
## 5             99605             99605                  101845
## 6            117461            117461                  119845
##   Choice.TargetOnsetTime Choice.OffsetDelay Choice.RTTime Choice.RT Choice.RESP
## 1                      0                  0             0         0        <NA>
## 2                  68045            -999999         69717      1672           y
## 3                  77045            -999999         79061      2016           r
## 4                  98045            -999999         99605      1560           r
## 5                  98045            -999999         99605      1560           r
## 6                 116045            -999999        117461      1416           r
##   Choice.CRESP FeedbackDisplay3.OnsetDelay FeedbackDisplay3.OnsetTime
## 1         <NA>                           0                          0
## 2            r                           3                      69720
## 3            r                           3                      79064
## 4            r                           3                      99608
## 5            r                           3                      99608
## 6            r                           3                     117464
##   FeedbackDisplay3.DurationError FeedbackDisplay3.Duration
## 1                              0                         0
## 2                             -3                      2328
## 3                             -3                      1984
## 4                             -3                      2440
## 5                             -3                      2440
## 6                             -3                      2584
##   FeedbackDisplay3.StartTime FeedbackDisplay3.OffsetTime
## 1                          0                           0
## 2                      69719                       71845
## 3                      79063                       80845
## 4                      99607                      101845
## 5                      99607                      101845
## 6                     117463                      119845
##   FeedbackDisplay3.FinishTime FeedbackDisplay3.TargetOffsetTime
## 1                           0                                 0
## 2                       71845                             71845
## 3                       80845                             80845
## 4                      101845                            101845
## 5                      101845                            101845
## 6                      119845                            119845
##   FeedbackDisplay3.TargetOnsetTime FeedbackDisplay3.OffsetDelay
## 1                                0                            0
## 2                            69717                            0
## 3                            79061                            0
## 4                            99605                            0
## 5                            99605                            0
## 6                           117461                            0

Each line of this table indicates an event (trial) happening in the experiment. In an ITC task, participants are shown a value of money and a delay. They’re asked, “would you rather receive $20 now, or wait X number of days to receive $Y later?” Hence, each line is an offer in this paradigm.

Processing

We want to get this into BIDS standard. Here’s the proposed columns:

Mandatory in BIDS:

onset: time that the trial happened from the start of the scan

duration: how long that event happened for

Required for ITC

choice: did they choose the delayed offer or not

button_press: did they go left or right

amount: how much they were offered

delay: what was the delay on the offer

reaction time: how long did they take to make their decision

Data Wrangling

The first thing we need to define is what choice they made. The column LeftRight indicates whether the instant $20 option is on the left or right of the screen. If LeftRight == 1, the delayed option was presented on the left.

We’ll code this as a factor delay_position with two levels, 1 to indicate it was on the right, and 0 to indicate it was on the left:

trial_df_proc <- trial_df %>%
  select(-contains("null"), -contains("Eprime"), -contains("Feedback")) %>%
  mutate(delay_position = ifelse(LeftRight == 0, 1, 0))

Next, we define which button they pressed, left (0) or right (1):

We’ll also define the motor response they made, button_press, as either 1 (right) or 0 (left). We use CHOICE.RESP and CHOICE1.RESP as the indicator of which side they picked. If the delayed option was on the left, use CHOICE.RESP; r is right, y is left.

Then, we encode the choice as either 1=delayed (the delayed position and the chosen button press where the same) or 0=now (the delayed position and the chosen button press where different):

trial_df_proc <- trial_df_proc %>%
  mutate(
    button_press = case_when(
      
      LeftRight == 1 & Choice.RESP == "y" ~ 0,
      LeftRight == 1 & Choice.RESP == "r" ~ 1,
      LeftRight == 0 & Choice1.RESP == "y" ~ 0,
      LeftRight == 0 & Choice1.RESP == "r" ~ 1
      
    ),
    choice = case_when(
      
      LeftRight == 1 & Choice.RESP == "y" ~ 1,
      LeftRight == 1 & Choice.RESP == "r" ~ 0,
      LeftRight == 0 & Choice1.RESP == "y" ~ 0,
      LeftRight == 0 & Choice1.RESP == "r" ~ 1
      
      )
    )

We also include the amount and delay:

trial_df_proc <- trial_df_proc %>%
  rename(offer = Offer) %>%
  select(offer, delay, choice, button_press, delay_position, everything())

The duration of the trial is uniform at 4000ms. There are two columns for event timings: Choice1.OnsetTime and Choice.OnsetTime. If LeftRight==1 the task proceeds to Choice.*. If they clicked right, the time for this gets recorded in Choice.OnsetTime, and the value in Choice1.OnsetTime is duplicated from the previous row:

10            216687           222699      ## left
11            228727           222699      ## left
12            246744           222699      ## right
13            246744           264762      ## right
14            246744           270774      ## right

Here we use the duplicated function to tell us if a value in a vector is a duplicate of itself. If there’s a duplicate, take the value from the opposite column:

trial_df_proc <- trial_df_proc %>%
  mutate(
    onset = case_when(
       
      # the first row should both not be duplicates
      !duplicated(Choice.OnsetTime) & !duplicated(Choice1.OnsetTime) ~ 0,
      
      # if any value in Choice is a duplicate, choose the value from Choice1
      duplicated(Choice.OnsetTime) ~ Choice1.OnsetTime,
      
      # vice versa
      duplicated(Choice1.OnsetTime) ~ Choice.OnsetTime
    ),
    
    duration = 4000,
    
  ) %>%
  select(onset, duration, everything())

We can do the same for response time:

trial_df_proc <- trial_df_proc %>%
  mutate(
    row_num = row_number(),
    response_time = case_when(
       
      # the first row should be the one that's not zero
      row_num == 1 & Choice.RT == 0 ~ Choice1.RT,
      row_num == 1 & Choice1.RT == 0 ~ Choice.RT,
      
      # if any value in Choice is a duplicate, choose the value from Choice1
      duplicated(Choice.RT) ~ Choice1.RT,
      
      # vice versa
      duplicated(Choice1.RT) ~ Choice.RT
    )
  ) %>%
  select(onset, duration, response_time, everything(), -row_num)

Lastly, we have to account for the timepoint that the task began (as opposed to when the participant is reading instructions). This is given in the slides_df:

trial_df_proc <- trial_df_proc %>%
  mutate(onset = ifelse(onset == 0, onset, onset - slides_df$Slide1.OffsetTime[2]))

Here’s the data head so far:

trial_df_sv <- trial_df_proc %>%
  select(onset:delay_position) %>%
  mutate(IA = 20)
trial_df_sv %>%
  head()

##   onset duration response_time offer delay choice button_press delay_position
## 1     0     4000          2328  23.0    21      0            0              1
## 2 14000     4000          1672  28.0     5      1            0              0
## 3 23000     4000          2016  30.5    55      0            1              0
## 4 44000     4000          1560  39.0    34      0            1              0
## 5 56000     4000          2264  25.0     7      0            0              1
## 6 62000     4000          1416  22.5    45      0            1              0
##   IA
## 1 20
## 2 20
## 3 20
## 4 20
## 5 20
## 6 20

From here, we write this data frame to a file.

trial_df_sv %>% 
  write_delim("/cbica/projects/wolf_satterthwaite_reward/Curation/code/itc_eprime/matlab_code/data/demo_trial.txt", delim = "\t")

Subjective Value

We calculate the k parameter for ITC using a pre-compiled matlab script:

function []=kable_itc_wrapper(inputfile, outputfile)

m = readtable(inputfile);
type='h';

choice = m.('choice');
IA = m.('IA');
DA = m.('offer');
D = m.('delay');

out = KableLab_ITC(type,choice,IA,DA,D);
k_param=out.k;
Tout = table(k_param);
writetable(Tout,outputfile);
disp(k_param);

end

% ------------------------------------- %
% kable lab ITC code starts here
% ------------------------------------- %
function out = KableLab_ITC(type,choice,IA,DA,D)
% data quality control by checking missed trials.
if sum(choice ~= 0 & choice ~= 1) ~= 0
    error('choice input has non binary elements')
end
if sum(choice) == length(choice) || sum(choice) == 0
    error('choices are all one-sided')
end

% type specifies the type of discounting function
if strcmp(type,'e') || strcmp(type,'h')
    out = fitoneparam(type,choice,IA,DA,D);
%elseif strcmp(type,'g')
%    out = fitgen(choice,IA,DA,D);
%elseif strcmp(type,'q')
%    out = fitquasi(choice,IA,DA,D);
else
    error('unknown discounting function type')
end
out.type = type;
[~,dev] = mnrfit([],2-choice); % an intercept-only model
out.LL0 = -dev/2; % LL of a null model
out.r2 = 1 - out.LL/out.LL0; % McFadden's R-squared
out.DV = out.SVlater-IA; % Decision Variable
predictedChoice = out.DV>=0;
out.percentPredicted = sum(predictedChoice == choice) / length(choice) * 100;
out.choicep = 1 ./ (1 + exp(-(out.noise.*out.DV)));
out.choiceresid = out.choicep-choice;
out.rawresid = out.DV-round(max(abs(out.DV))).*(2.*choice-1);
end

function out = fitoneparam(type,choice,IA,DA,D)
if strcmp(type,'e') % exponential case
    indiffk = -log(IA./DA)./D;
else % hyperbolic case
    indiffk = (DA-IA)./(IA.*D);
end
mink = min(indiffk)*(0.99);
maxk = max(indiffk)*(1.01);
[noise,ks] = meshgrid([-1,0,1], linspace(log(mink),log(maxk),5)); % search grid. We search in logspace
b = [noise(:) ks(:)];
info.negLL = inf;
for i = 1:length(b)
    [new.b,new.negLL] = fmincon(@negLL,b(i,:),[],[],[],[],[log(eps),log(mink)],[2,log(maxk)],[],...
        optimset('Algorithm','interior-point','Display','off'),choice,IA,DA,D,type);
    if new.negLL < info.negLL
        info = new;
    end
end
out.k = exp(info.b(2));
out.noise = exp(info.b(1));
out.LL = -info.negLL;
if strcmp(type,'e')
    out.SVlater = DA.*exp(-out.k.*D);
else
    out.SVlater = DA./(1+out.k.*D);
end
end

function negLL = negLL(beta,choice,IA,DA,D,type) % function for negative Log-Likelihood
switch type
    case 'e'
        SVdelayed = DA.*exp(-exp(beta(2)).*D);
    case 'h'
        SVdelayed = DA./(1+exp(beta(2)).*D);
    case 'q'
        SVdelayed = exp(log(DA)+log(beta(2))+D.*log(beta(3)));
        beta(1) = log(beta(1));
    case 'g'
        SVdelayed = DA./((1+exp(beta(2)).*D).^beta(3));
        beta(1) = log(beta(1));
end
reg = exp(beta(1)).*(SVdelayed-IA);
p = 1 ./ (1 + exp(-reg));
p(p == 1) = 1-eps;
p(p == 0) = eps;
negLL = -sum((choice==1).*log(p) + (choice==0).*log(1-p));
end

Here’s how it’s called:

./run_kable_itc_wrapper.sh $MATLAB_DIR data/demo_trial.txt data/output_trial.txt

And read it in:

k_param <- read_table("/cbica/projects/wolf_satterthwaite_reward/Curation/code/itc_eprime/matlab_code/data/output_trial.txt") %>%
  pull(k_param)

## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   k_param = col_double()
## )

k_param

## [1] 0.07106205

Finally, subjective value is calculated by \(\frac{\text{offer}} {1 + k \times \text{delay}}\)

final_df <- trial_df_sv %>%
  mutate(subjective_value = offer / (1 + k_param * delay)) %>%
  mutate_if(~ is.numeric(.) && all(unique(.) %in% c(0, 1, NA)), factor) %>%
  select(-IA) 

Final Outputs

Here’s the final dataframe:

final_df

##     onset duration response_time offer delay choice button_press delay_position
## 1       0     4000          2328  23.0    21      0            0              1
## 2   14000     4000          1672  28.0     5      1            0              0
## 3   23000     4000          2016  30.5    55      0            1              0
## 4   44000     4000          1560  39.0    34      0            1              0
## 5   56000     4000          2264  25.0     7      0            0              1
## 6   62000     4000          1416  22.5    45      0            1              0
## 7   68000     4000          1344  37.5   149      0            1              0
## 8   83000     4000          1200  40.5    97      0            1              0
## 9   95000     4000          1656  31.5    68      0            0              1
## 10 101000     4000          1168  46.5    48      0            1              0
## 11 107000     4000          1544  31.5    48      0            0              1
## 12 125000     4000          1536  27.5    53      0            0              1
## 13 143000     4000          1224  43.0   161      0            1              0
## 14 149000     4000          1536  48.0   107      0            1              0
## 15 161000     4000          3464  41.5    15      1            1              1
## 16 170000     4000          1248  39.0    48      0            0              1
## 17 185000     4000          1048  25.5   149      0            1              0
## 18 191000     4000          1344  20.5    84      0            0              1
## 19 197000     4000          1352  38.0   178      0            0              1
## 20 203000     4000          3168  31.5     7      0            0              1
## 21 209000     4000          1072  25.5    84      0            1              0
## 22 215000     4000          1312  34.0     7      1            1              1
## 23 221000     4000          1272  20.5   161      0            0              1
## 24 233000     4000          1696  41.5     7      1            0              0
## 25 254000     4000           928  28.0    48      0            1              0
## 26 263000     4000          1216  29.0     4      1            1              1
## 27 269000     4000          1128  33.0    55      0            1              0
## 28 278000     4000          1048  47.5    43      0            0              1
## 29 290000     4000          1112  33.0   107      0            0              1
## 30 296000     4000           824  22.5   178      0            1              0
## 31 302000     4000          1016  50.0   124      0            1              0
## 32 308000     4000          1192  30.0    34      0            0              1
## 33 317000     4000          1424  26.5     7      0            1              0
## 34 341000     4000          1032  25.5   124      0            1              0
## 35 347000     4000           880  39.0   124      0            1              0
## 36 356000     4000          1136  25.5   107      0            0              1
## 37 365000     4000          1456  36.5    32      0            1              0
## 38 371000     4000          1128  41.5   178      0            0              1
## 39 380000     4000           760  45.0   149      0            1              0
## 40 386000     4000          1096  44.0   124      0            0              1
## 41 395000     4000          1336  29.0    68      0            0              1
## 42 410000     4000          1488  29.0    17      0            0              1
## 43 419000     4000          2328  26.5    29      0            0              1
## 44 431000     4000          1256  48.0    23      0            0              1
## 45 449000     4000          1368  30.5    97      0            0              1
## 46 455000     4000          1272  44.0    34      0            1              0
## 47 470000     4000           912  47.5    84      0            1              0
## 48 482000     4000          1328  48.0    34      0            1              0
## 49 491000     4000          1136  22.5   124      0            0              1
## 50 500000     4000          1136  28.0   124      0            1              0
##    subjective_value
## 1          9.228413
## 2         20.659477
## 3          6.213822
## 4         11.416496
## 5         16.695223
## 6          5.359961
## 7          3.236038
## 8          5.131117
## 9          5.401032
## 10        10.541879
## 11         7.141273
## 12         5.769689
## 13         3.456317
## 14         5.579035
## 15        20.087799
## 16         8.841576
## 17         2.200506
## 18         2.941509
## 19         2.784078
## 20        21.035981
## 21         3.658950
## 22        22.705503
## 23         1.647779
## 24        27.714070
## 25         6.347798
## 26        22.581305
## 27         6.723151
## 28        11.712004
## 29         3.835586
## 30         1.648467
## 31         5.095960
## 32         8.781920
## 33        17.696936
## 34         2.598940
## 35         3.974849
## 36         2.963862
## 37        11.148492
## 38         3.040506
## 39         3.883246
## 40         4.484445
## 41         4.972378
## 42        13.133732
## 43         8.657869
## 44        18.220280
## 45         3.864174
## 46        12.880149
## 47         6.815692
## 48        14.051072
## 49         2.293182
## 50         2.853738

We pair this with a dictionary in BIDS describing how to interpret these columns, like:

{
    "column": {
        "LongName": "some name",
        "Description": "long description",
        "Levels": {
            "go": "level one of a factor",
            "stop": "leve two of a factor",
        }
    }
}

dictionary <- final_df %>%
  select(-onset, -duration) %>%
  map(~ list(
    LongName = "",
    Description = ""
  ))
  
dictionary$response_time$LongName <- "Response Time to Offer"
dictionary$response_time$Description <- "How long it takes for the participant to choose and respond with a button press"

dictionary$offer$LongName <- "Offer Amount"
dictionary$offer$Description <- "Amount of money in dollars that the trial is offering"

dictionary$delay$LongName <- "Delay on Offer"
dictionary$delay$Description <- "Number of days to wait until they can receive the offer"

dictionary$choice$LongName <- "Choice made by the participant"
dictionary$choice$Description <- "Factor indicating whether the participant selected an offer of 20 dollars immediately, or an offer of more value at the delayed time"
dictionary$choice$Levels <- list(`1` = "Selected the delayed offer",
                                 `0` = "Selected the immediate offer")

dictionary$button_press$LongName <- "Which button was pressed"
dictionary$button_press$Description <- "Factor indicating whether the participant pressed the button on the right or the left"
dictionary$button_press$Levels <- list(`1` = "Pressed the right hand button",
                                 `0` = "Pressed the left hand button")

dictionary$delay_position$LongName <- "Position of the delayed option"
dictionary$delay_position$Description <- "Factor indicating which side of the screen the delayed option is on for the trial"
dictionary$delay_position$Levels <- list(`1` = "Delay on the right",
                                 `0` = "Delay on the left")

dictionary$subjective_value$LongName <- "Subjective value of potential offer"
dictionary$subjective_value$Description <- "Participant's subjective value of the delayed offer calculated using a discount curve (as is common in the literature)" # should add paper link in here

jsonlite::toJSON(dictionary) %>%
  jsonlite::prettify()

## {
##     "response_time": {
##         "LongName": [
##             "Response Time to Offer"
##         ],
##         "Description": [
##             "How long it takes for the participant to choose and respond with a button press"
##         ]
##     },
##     "offer": {
##         "LongName": [
##             "Offer Amount"
##         ],
##         "Description": [
##             "Amount of money in dollars that the trial is offering"
##         ]
##     },
##     "delay": {
##         "LongName": [
##             "Delay on Offer"
##         ],
##         "Description": [
##             "Number of days to wait until they can receive the offer"
##         ]
##     },
##     "choice": {
##         "LongName": [
##             "Choice made by the participant"
##         ],
##         "Description": [
##             "Factor indicating whether the participant selected an offer of 20 dollars immediately, or an offer of more value at the delayed time"
##         ],
##         "Levels": {
##             "1": [
##                 "Selected the delayed offer"
##             ],
##             "0": [
##                 "Selected the immediate offer"
##             ]
##         }
##     },
##     "button_press": {
##         "LongName": [
##             "Which button was pressed"
##         ],
##         "Description": [
##             "Factor indicating whether the participant pressed the button on the right or the left"
##         ],
##         "Levels": {
##             "1": [
##                 "Pressed the right hand button"
##             ],
##             "0": [
##                 "Pressed the left hand button"
##             ]
##         }
##     },
##     "delay_position": {
##         "LongName": [
##             "Position of the delayed option"
##         ],
##         "Description": [
##             "Factor indicating which side of the screen the delayed option is on for the trial"
##         ],
##         "Levels": {
##             "1": [
##                 "Delay on the right"
##             ],
##             "0": [
##                 "Delay on the left"
##             ]
##         }
##     },
##     "subjective_value": {
##         "LongName": [
##             "Subjective value of potential offer"
##         ],
##         "Description": [
##             "Participant's subjective value of the delayed offer calculated using a discount curve (as is common in the literature)"
##         ]
##     }
## }
##