___________________________________________________________________________________________________________________ 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 *******************************************************************************************************************