___________________________________________________________________________________________________________________
DIFFERENCE THRESHOLD: METHOD OF LIMITS (Example: determine difference threshold for a red)
___________________________________________________________________________________________________________________
Script Author: Katja Borchert, Ph.D. (katjab@millisecond.com) for Millisecond Software, LLC
Date: 01-20-2014
last updated: 03-06-2020 by K. Borchert (katjab@millisecond.com) for Millisecond Software, LLC
Script Copyright © 03-06-2020 Millisecond Software
___________________________________________________________________________________________________________________
BACKGROUND INFO
___________________________________________________________________________________________________________________
This script implements the METHOD OF LIMITS to estimate the difference threshold for a particular color red
Reference:
Ehrenstein, W.H. & and Addie Ehrenstein, A. (1999). Psychophysical Methods. In U. Windhorst & H. Johansson, Hakan (Eds.),
Modern Techniques in Neuroscience Research (pp.1211-1241). Heidelberg: Springer.
(->http://uni-leipzig.de/~isp/isp/history/texts/PSYPHY-M.PDF)
___________________________________________________________________________________________________________________
TASK DESCRIPTION
___________________________________________________________________________________________________________________
Participants are asked repeatedly whether a red Target color is lighter or darker than a red base color.
For example: the red component of the target color is lighter. As long as participants say the target
red is lighter than the base red, the target red gets adjusted by a preestablished step size (editable
value). Once participants reverse their answer (and say it's darker), the trial is over and the threshold is
calculated as the mean between the last two red color components for the target (aka the last "lighter" and
the first "darker" red component).
By default this scripts estimates the Difference Thresholds for 1 red colors (-> editable parameters),
with 2 trials each, one for a lighter and one for a darker start target. The order is determined randomly
for each participant (-> list.baseline_values)
1 cycle = 1 "up" sequence + 1 "down" sequence
___________________________________________________________________________________________________________________
DURATION
___________________________________________________________________________________________________________________
the default set-up of the script takes appr. 2 minutes to complete
___________________________________________________________________________________________________________________
DATA FILE INFORMATION
___________________________________________________________________________________________________________________
The default data stored in the data files are:
(1) Raw data file: 'limitsmethod_raw*.iqdat' (a separate file for each participant)
build: The specific Inquisit version used (the 'build') that was run
computer.platform: the platform the script was run on (win/mac/ios/android)
date, time, date and time script was run
subject, group, with the current subject/groupnumber
script.sessionid: with the current session id
blockcode, blocknum: the name and number of the current block (built-in Inquisit variable)
trialcode, trialnum: the name and number of the currently recorded trial (built-in Inquisit variable)
Note: trialnum is a built-in Inquisit variable; it counts all trials run; even those
that do not store data to the data file.
cycles: stores the number of "limits" cycles run (one cycle runs an up and a down sequence)
baseline_value: stores the color of the current base
target_value: stores the color of the current
direction: 1 = Down (sequence starts with targetvalue > baseline value)
2 = Up (sequence starts with targetvalue < baseline value)
sequencecount: counts how many limits sequences have been run in a cycle
response: the participant's response
latency: the response latency in ms
diffthreshold_up: the estimated Difference threshold for the current UP sequence (= starting with
target value < baseline value)
diffthreshold_down: the estimated Difference threshold for the current DOWN sequence (= starting with
target value > baseline value)
totaldiffthreshold: mean difference threshold for one adjustment cycle (up and down)
(2) Summary data file: 'limitsmethod_summary*.iqdat' (a separate file for each participant)
computer.platform: the platform the script was run on (win/mac/ios/android)
script.startdate: date script was run
script.starttime: time script was started
script.subjectid: assigned subject id number
script.groupid: assigned group id number
script.sessionid: assigned session id number
script.elapsedtime: time it took to run script (in ms); measured from onset to offset of script
script.completed: 0 = script was not completed (prematurely aborted);
1 = script was completed (all conditions run)
cycles: stores the number of "limit" cycles run
step: the stepsize with which the target color increases/decreases (default: 2)
parameters.initialdifference: initial difference in the red component of target and base (default: 50+1 = 51)
Note: in this script the initial difference is selected in such a way that the
adjusted targetvalues are always either above or below baseline.
parameters.baselinevalue1: the baseline_value of the first "limits" cycle
diffthreshold1: stores the Difference Threshold of the first cycle
Note: by design, this script only runs one cycle
___________________________________________________________________________________________________________________
INSTRUCTIONS
___________________________________________________________________________________________________________________
see section Editable Instructions
___________________________________________________________________________________________________________________
EDITABLE CODE
___________________________________________________________________________________________________________________
check below for (relatively) easily editable parameters, stimuli, instructions etc.
Keep in mind that you can use this script as a template and therefore always "mess" with the entire code
to further customize your experiment.
The parameters you can change are:
/responsekey_lighter -
/responsekey_darker: the response key assignments (scancodes and labels)
/baselinevalue1: the baseline value (0 -> black, 255 -> brightest red) for cycle 1
Note: to add further cycles with different basevalues
add a value for each new baseline value you want to test and go to
BLOCKS for further instructions.
/step: the stepsize with which the target color increases/decreases (default: 2)
/initialdifference: initial difference in the red component of target and base (default: 50+1 = 51)
Note: in this script the initial difference is selected in such a way that the
adjusted targetvalues are always either above or below baseline.
/interadjustmentpause: pause after an adjustment sequence in ms (default: 500ms)
**************************************************************************************************************
**************************************************************************************************************
EDITABLE PARAMETERS: change editable parameters here
**************************************************************************************************************
**************************************************************************************************************
/responsekey_lighter = "L"
/responsekey_darker = "D"
/baselinevalue1 = 80
/step = 2
/initialdifference = 50 + 0.5*parameters.step
/interadjustmentpause = 500
**************************************************************************************************************
**************************************************************************************************************
EDITABLE STIMULI: change editable stimuli here
**************************************************************************************************************
**************************************************************************************************************
-
/1 = "BASE COLOR"
/2 = "TARGET COLOR"
**************************************************************************************************************
**************************************************************************************************************
EDITABLE INSTRUCTIONS: change instructions here
**************************************************************************************************************
**************************************************************************************************************
-
/1 = "Is the Target Color (right) LIGHTER or DARKER than the Base Color (left)?"
/2 = "LIGHTER -> Press the '<%parameters.responsekey_lighter%>' <%expressions.buttoninstruct1%>
DARKER -> Press the '<%parameters.responsekey_darker%>' <%expressions.buttoninstruct1%>"
/ fontstyle = ("Arial", 2.80%, false, false, false, false, 5, 1)
^For the following task you will be presented two circles of different shades of red.
^^The left circle is called the BASE.
^The right circle is called the TARGET.
^^The BASE color stays constant but the TARGET color will progessively get lighter (or darker).
^^Your task is to decide whether the current red color of the TARGET is lighter or darker than the red
color of the base.
^^If it's lighter -> Press the <%parameters.responsekey_lighter%> <%expressions.buttoninstruct1%>
^If it's darker -> Press the <%parameters.responsekey_darker%> <%expressions.buttoninstruct1%>
^^^The closer the TARGET color gets to the BASE color the more difficult the task.
You have reached the end of the task.
^^Thank you!
****************************************************************************************************
general instruction expressions: adjust the instruction text depending on device used to run script
****************************************************************************************************
/buttoninstruct1 = if (computer.touch && !computer.haskeyboard) {"button";} else {"key on your keyboard";}
**************************************************************************************************************
!!!REMAINING CODE: Customize after careful consideration only!!!
**************************************************************************************************************
**************************************************************************************************************
**************************************************************************************************************
DEFAULTS
**************************************************************************************************************
**************************************************************************************************************
script requires Inquisit 6.1.0.0 or higher
/canvasaspectratio = (4,3)
/minimumversion = "6.1.0.0"
/ fontstyle = ("Arial", 3%, false, false, false, false, 5, 1)
/txbgcolor = white
/ txcolor = black
*******************************************************************************************************************
*******************************************************************************************************************
DATA: this section contains data file information
*******************************************************************************************************************
*******************************************************************************************************************
********************
raw data
********************
/ columns = (build, computer.platform, date, time, subject, group, script.sessionid, blockcode, blocknum,
trialcode, trialnum,
values.cycles, values.baseline_value, values.target_value, values.direction, values.sequencecount, response, latency,
values.diffthreshold_up, values.diffthreshold_down, expressions.totaldiffthreshold)
********************
summary data
********************
/ columns = (computer.platform, script.startdate, script.starttime, script.subjectid, script.groupid, script.sessionid, script.elapsedtime,
script.completed,
values.cycles, parameters.step, parameters.initialdifference,
parameters.baselinevalue1, values.diffthreshold1)
*******************************************************************************************************************
*******************************************************************************************************************
VALUES: automatically updated
*******************************************************************************************************************
*******************************************************************************************************************
/cycles: stores the number of "limits" cycles run
/baseline_value: stores the red color targetonent of the current base
/target_value: stores the red color targetonent of the current target Color
/targetvalue_down: stores the beginning targetvalue for the current down sequence
/targetvalue_up: stores the beginning targetvalue for the current up sequence
/sequencecount: counts how many adjustment sequences have been run in a cycle
/change: stores the adjustment change (based on parameters.step)
/count_baseline: add the number of times an adjustment sequence was run for the given baseline
/direction: 1 = target lighter; 2 = target darker
/DiffThreshold_down: Difference threshold for sequence in which target starts out lighter
/DiffThreshold_up: Difference threshold for sequence in which target starts out darker
/sum_DiffThreshold: add the difference thresholds for up and down sequence in a cycle
/DiffThreshold1: stores the Difference Threshold of the first cycle
/cycles = 0
/baseline_value = 0
/target_value = 0
/targetvalue_down = 0
/targetvalue_up = 0
/sequencecount = 0
/change = 0
/count_baseline = 0
/direction = 0
/DiffThreshold_down = 0
/DiffThreshold_up = 0
/sum_DiffThreshold= 0
/DiffThreshold1 = 0
*******************************************************************************************************************
*******************************************************************************************************************
EXPRESSIONS
*******************************************************************************************************************
*******************************************************************************************************************
/TotalDiffThreshold: Mean difference threshold (averaging threshold of decreasing and increasing targetvalues)
/TotalDiffThreshold = values.sum_DiffThreshold/2
*******************************************************************************************************************
*******************************************************************************************************************
INSTRUCTIONS
*******************************************************************************************************************
*******************************************************************************************************************
/items = instructions
/select = 1
/position = (50%, 10%)
/ fontstyle = ("Arial", 3%, true, false, false, false, 5, 1)
/ txcolor = black
/erase = false
/items = instructions
/select = 2
/position = (50%, 20%)
/ fontstyle = ("Arial", 2%, false, false, false, false, 5, 1)
/ txcolor = black
/erase = false
*******************************************************************************************************************
*******************************************************************************************************************
STIMULI
*******************************************************************************************************************
*******************************************************************************************************************
/shape = circle
/color = (155, 0, 0)
/size = (30%*3/4, 30%)
/position = (30%, 50%)
/shape = circle
/color = (155, 0, 0)
/size = (30%*3/4, 30%)
/position = (70%, 50%)
/items = labels
/select = 1
/ fontstyle = ("Arial", 3%, false, false, false, false, 5, 1)
/ txcolor = black
/hposition = shape.base.hposition
/vposition = shape.base.vposition + shape.base.height + 10%
/erase = false
/items = labels
/select = 2
/ fontstyle = ("Arial", 3%, false, false, false, false, 5, 1)
/ txcolor = black
/hposition = shape.target.hposition
/vposition = shape.target.vposition + shape.target.height + 10%
/erase = false
/shape = rectangle
/color = white
/size = (100%, 100%)
/position = (50%, 50%)
*******************************************************************************************************************
*******************************************************************************************************************
LISTS
*******************************************************************************************************************
*******************************************************************************************************************
Note: list randomly selects the down (1) or the up (2) sequence for one adjustment cycle
/items = (1, 2)
/replace = false
/ resetinterval = 1
*******************************************************************************************************************
*******************************************************************************************************************
TRIALS
*******************************************************************************************************************
*******************************************************************************************************************
Note: trial is run before each new adjustement trial
- base color and initial target color are determined
and the corresponding shape colors are updated accordingly
- counts are updated
/ontrialbegin = [
values.sequencecount += 1;
values.direction = list.nextdirection.nextvalue;
if (values.direction == 1) {
values.target_value = values.targetvalue_down;
} else {
values.target_value = values.targetvalue_up;
};
shape.base.colorred = parameters.baselinevalue1;
shape.target.colorred = values.target_value;
values.change = 0;
]
/timeout = 0
/branch = [
if (values.direction == 1) {
trial.adjust_down;
} else {
trial.adjust_up;
};
]
Note:
- decreases the red color targetonent of the target Color
/ontrialbegin = [
values.direction = 1;
values.target_value -= values.change;
shape.target.colorred = values.target_value;
]
/ stimulusframes = [1 = taskinstruct1, taskinstruct2, baselabel, targetlabel, base, target]
/validresponse = (parameters.responsekey_darker, parameters.responsekey_lighter)
/monkeyresponse = (parameters.responsekey_darker, parameters.responsekey_lighter)
/ontrialend = [
values.change = parameters.step;
if (values.target_value == 255 && trial.adjust_down.responsetext == parameters.responsekey_lighter) {
values.target_value -=1;
} else if (values.target_value == 0 && trial.adjust_down.responsetext == parameters.responsekey_darker) {
values.target_value +=1;
};
]
/branch = [
if (trial.adjust_down.responsetext == parameters.responsekey_darker) {
return trial.end;
} else {
return trial.adjust_down;
};
]
Note:
- increases the red color targetonent of the target Color
/ontrialbegin = [
values.direction = 2;
values.target_value += values.change;
shape.target.colorred = values.target_value;
]
/ stimulusframes = [1 = taskinstruct1, taskinstruct2, baselabel, targetlabel, base, target]
/validresponse = (parameters.responsekey_darker, parameters.responsekey_lighter)
/monkeyresponse = (parameters.responsekey_darker, parameters.responsekey_lighter)
/ontrialend = [
values.change = parameters.step;
if (values.target_value == 255 && trial.adjust_up.responsetext == parameters.responsekey_lighter) {
values.target_value -=1;
} else if (values.target_value == 0 && trial.adjust_up.responsetext == parameters.responsekey_darker) {
values.target_value +=1;
};
]
/branch = [
if (trial.adjust_up.responsetext == parameters.responsekey_lighter) {
return trial.end;
} else {
return trial.adjust_up;
};
]
Note:
- keeps track of the threshold
/stimulusframes = [1 = eraser]
/timeout = 0
/recorddata = true
/ontrialend = [
if (values.direction == 1) {
values.DiffThreshold_down = (values.target_value + 0.5*parameters.step);
values.sum_DiffThreshold += (values.target_value + 0.5*parameters.step);
} else {
values.DiffThreshold_up = (values.target_value - 0.5*parameters.step);
values.sum_DiffThreshold += (values.target_value - 0.5*parameters.step);
};
]
/branch = [
if (values.sequencecount < 2) {
return trial.start;
};
]
/posttrialpause = parameters.interadjustmentpause
*******************************************************************************************************************
*******************************************************************************************************************
BLOCKS
*******************************************************************************************************************
*******************************************************************************************************************
Note: block.limits1 runs one cycle (once starting above and once starting below basevalue)
with parameters.baselinevalue1
To run further cycles, create separate blocks for each of the baselines.
change -> /onblockbegin = [values.baseline_value = values.baselinevalue2]
Go to EXPERIMENT and add the new cycles
/onblockbegin = [
values.diffthreshold_down = 0;
values.diffthreshold_up = 0;
values.sum_diffthreshold = 0;
values.sequencecount = 0;
values.cycles += 1;
values.baseline_value = parameters.baselinevalue1;
values.targetvalue_down = values.baseline_value + (parameters.initialdifference);
values.targetvalue_up = values.baseline_value - (parameters.initialdifference);
]
/trials = [1=start]
/onblockend = [
values.diffthreshold1 = expressions.totaldiffthreshold;
]
*******************************************************************************************************************
*******************************************************************************************************************
EXPERIMENT
*******************************************************************************************************************
*******************************************************************************************************************
Note: to run more cycles add the newly created limits blocks
/blocks = [1 = limits1] => /blocks = [1 = limits1; 2 = limits2....]
/postinstructions = (end)
/blocks = [1 = limits1]
*******************************************************************************************************************
End of File
*******************************************************************************************************************