___________________________________________________________________________________________________________________ WUNDT CLOCK PARADIGM: Time Estimation of Voluntary and Involuntary Events ___________________________________________________________________________________________________________________ Script Author: Katja Borchert, Ph.D. (katjab@millisecond.com) for Millisecond Software, LLC Date: 11-16-2016 last updated: 10-01-2024 by K. Borchert (katjab@millisecond.com) for Millisecond Software, LLC Script Copyright © 10-01-2024 Millisecond Software Millisecond Software thanks Dr. Patrick Haggard for assistance with procedural details! ___________________________________________________________________________________________________________________ BACKGROUND INFO ___________________________________________________________________________________________________________________ This script implements a Wundt Clock Paradigm to measure time estimations of voluntary and involuntary events based on: Haggard, P., Clark, S., & Kalogeras, J. (2002). Voluntary action and conscious awareness. Nature Neuroscience, 5(4), 382–385. Demanet J.,Muhle-Karbe P.S., Lynn M.T., Blotenberg I., Brass M. (2013) . Power to the will: How exerting physical effort boosts the senseof agency. Cognition, 129, 574–578. ___________________________________________________________________________________________________________________ TASK DESCRIPTION ___________________________________________________________________________________________________________________ Participants watch a red dot rotating around a clock display with 60 different dot positions. They have to pinpoint the location of the red dot at a) at the time of a spacebar press (voluntary event = action) b) at the time a beep is played (involuntary event) The red dot keeps rotating for a random period of time after the target event has taken place and then disappears. Participants are then asked to select the relevant clock position. 4 different conditions: 1. agency_action: the spacebar press is followed by a beep. (target event = spacebar press) 2. agency_tone: the spacebar press is followed by a beep. (target event = beep onset) 3. baseline_action: the spacebar press is NOT followed by a beep (target event = spacebar press) 4. baseline_tone: the tone is played at a random time without a spacebar press (target event = beep onset) The script estimates the judgment errors in ms: the distance between position of the red dot at time of target event (calculated based on event timings, rotation speed, and start of rotation) and the selected clock position in ms required to cross that distance. (=> with the default settings, the dot requires 50ms to travel from dot to dot) Note: in this script the red dot rotates in a continuous fashion around the clock and participant can select any position (not only the dots) on the clock face. ___________________________________________________________________________________________________________________ DURATION ___________________________________________________________________________________________________________________ the default set-up of the script takes appr. 12 minutes to complete ___________________________________________________________________________________________________________________ DATA OUTPUT DICTIONARY ___________________________________________________________________________________________________________________ The fields in the data files are: (1) Raw data file: 'wundtclockparadigm_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 session: 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 such as feedback trials. Thus, trialNum may not reflect the number of main trials run per block. condition: 1 = baseline_action; 2 = baseline_tone; 3 = agency_action; 4 = agency_tone targetEvent: 1 = action; 2 = tone iti: stores the random posttrialpause duration (in ms) => the time the dot moves after the target event has occurred baselineToneDelay: stores the tone delay (in ms) in the baseline tone condition startDot: stores the starting dot (randomly determined) (1-60 => dot 60 is in the 12 o'clock position) response: the participant's response latency: the response latency (in ms) measured from onset of trial targetClockHandPosition: calculates the last absolute clock face position of the clockHand when event occurred in terms of dot positions 1-60. (1-60 => dot 60 is in the 12 o'clock position) selectedPosition: stores the participant selected clock face position of the clockHand when event occurred see calculateSelectedPosition for details of how this value is calculated in this script based on the coordinates of the selected location distance: stores the shortest, absolute distance between the targetClockHandPosition and the selectedPosition (measured in 'dot distance': e.g. distance = 1.08 => the two positions are 1.08 'dots' apart) Note: each dot is separated by 6degrees and 50ms judgmentError: stores the calculated judgment error in ms (=> time in ms required to cross distance given the speed of the rotation) (a distance of 1 dot between actual and selected dots => judgment error = 50ms; distance = 1.08 => 50ms * 1.08 = 54ms) (positive values: participant selected a position that was further along than the clock actually was, negative value: participant selected a position that was not quite as far along as the clock actually was) Note: see below for algorithm used to calculate the judgment error or check calculateJudgmentError (2) Summary data file: 'wundtclockparadigm_summary*.iqdat' (a separate file for each participant)* inquisit.version: Inquisit version run computer.platform: the platform the script was run on (win/mac/ios/android) startDate: date script was run startTime: time script was started subjectId: assigned subject id number groupId: assigned group id number sessionId: assigned session id number elapsedTime: time it took to run script (in ms); measured from onset to offset of script completed: 0 = script was not completed (prematurely aborted); 1 = script was completed (all conditions run) meanJudgmentErrorAgencyAction: mean judgment error (in ms) in the agency_action condition meanJudgmentErrorBaselineAction: mean judgment error (in ms) in the baseline_action condition meanJudgmentErrorAgencyTone: mean judgment error (in ms) in the agency_tone condition meanJudgmentErrorBaselineTone: mean judgment error (in ms) in the baseline_tone condition bindingScoreaction: difference btw. mean judgment errors in baseline_action and agency_action conditions bindingScoreTone: difference btw. mean judgment errors in baseline_tone and agency_tone conditions * separate data files: to change to one data file for all participants (on Inquisit Lab only), go to section "DATA" and follow further instructions ___________________________________________________________________________________________________________________ EXPERIMENTAL SET-UP ___________________________________________________________________________________________________________________ * 1 Demo Block with 2 demonstration trials (baseline_tone, baseline_action) * 4 Experimental Blocks: random order of baseline_tone, baseline_action, agency_tone, agency_action (tested in blocked design) - each block runs 15 trials => 60 trials total Trial Sequence: baseline_action: - clock face presented for 2s (default, editable parameter) - clock hand starts rotating from a randomly selected clock position - participant can press Spacebar at time of their choosing (clock hand rotates 100 times if no response occurs, editable parameters) - clock hand keeps moving for a randomly selected time btw. 1000-2000ms, in increments of 250ms - participants are asked to select the dot the clock hand was on when event (spacebar press) occurred. baseline_tone: - clock face presented for 2s (default, editable parameter) - clock hand starts rotating from a randomly selected clock position - beep is played at a randomly selected delay (btw. 1000-4500ms, in increments of 250ms) - clock hand keeps moving for a randomly selected time btw. 1000-2000ms, in increments of 250ms - participants are asked to select the dot the clock hand was on when event (beep onset) occurred. agency_action: - clock face presented for 2s (default, editable parameter) - clock hand starts rotating from a randomly selected clock position - participant can press Spacebar at time of their choosing (clock hand rotates 100 times if no response occurs, editable parameters) - a beep is played 250ms after Spacebar press - clock hand keeps moving for a randomly selected time btw. 1000-2000ms after spacebar press, in increments of 250ms - participants are asked to select the dot the clock hand was on when event (spacebar press) occurred. agency_tone: - clock face presented for 2s (default, editable parameter) - clock hand starts rotating from a randomly selected clock position - participant can press Spacebar at time of their choosing (clock hand rotates 100 times if no response occurs, editable parameters) - a beep is played 250ms after Spacebar press - clock hand keeps moving for a randomly selected time btw. 1000-2000ms after spacebar press, in increments of 250ms - participants are asked to select the CLOCK FACE POSITION clock hand was on when event (beep onset) occurred. Inquisit Algorithm to calculate the Target Clock Hand Position: STEP 1: calculate how many rotations the clock hand has completed at time of event -> expressions.nrRotations Example: spacebar press occurred at 3154ms into the trial => 1 full rotation of 3000ms had already been completed STEP 2: adjust event values.eventTiming (measured from onset of trial) to get values.correctedEventTiming (= event timing from start of last rotation) Example: 3154ms - 1*3000ms = 154ms => event occurred at 154ms into the current rotation STEP 3: calculate the clock hand position on the clock relative to the start of the rotation (= how many clock positions has clock hand passed over) Example: if event occurred at 154ms => 154/50 = 3.08 => it has just passed the third dot in the rotation and is on the way to the 4th dot STEP 4: convert the relative clock hand position to the absolute (target) clock hand position (measured from dot0 = dot60) at time of event Example: clockHand started at values.startDot = 58 and moved 3.08 dots along => in the last rotation, the clock hand would have been at dot position: 58+3.08 = 61.08 => corrected to 1.08 (=> between dot1 and dot2) Inquisit Algorithm to calculate the Selected Clock Hand Position Note: in this script, the response area extends 1.25% to the right and left of the actual clock face, therefore the selected coordinate may not actually be on the clock face. The selected clock position is taken as the intersection from the line between clock center and selected coordinate and the clock face by calculating the placement angle between the vertical axis (represents 0 degrees) and the selected coordinate (clockwise rotation) STEP 1: Determine which quadrant the response coordinates falls into by comparing x/y coordinates of selected position with clock center coordinates: quadrant1: top right quadrant (0 < placement angle <= 90) => max. selected Position = 15 quadrant2: bottom right quadrant (90 < placement angle <= 180) => max. selected Position = 30 quadrant3: bottom left quadrant (180 < placement angle <= 270) => max. selected Position = 45 quadrant4: top left quadrant (270 < placement angle <= 360) => max. selected Position = 60 Example: clock center = (912px,912px) selected Position = (1217px,1248px) => horizontal position falls to the right of clock center AND vertical position falls below clock center => quadrant 2 (15 < selected position <=30) STEP 2: Determine the additional degrees ('quadrant angle') that have to be added to the boundary angles of each quadrant using Sin (quadrant angle) = opposite/hypotenuse. a) Determine which axis (vertical or horizontal) is going to be the 'adjacent' side in the right triangle btw. center line to the selected coordinate, and from selected coordinate to the axis. b) then determine opposite side quadrant1: adjacent = vertical y-axis => opposite side is the horizontal distance from y-axis to selected coordinates quadrant2: adjacent = horizontal x-axis => opposite side is the vertical distance from x-axis to selected coordinates quadrant3: adjacent = vertical y-axis => opposite side is the horizontal distance from y-axis to selected coordinates quadrant4: adjacent = horizontal x-axis => opposite side is the vertical distance from x-axis to selected coordinates Example: quadrant angle between x-axis (adjacent side in quadrant 2) and the line from circle center to selected coordinate calculations use sin(quadrant angle) = opposite/hypotenuse => quadrant angle = asin(opposite/hypotenuse), 'quadrant angle' measured in circle radians => angle in degrees = deg(asin(opposite/hypotenuse) with: side opposite to angle = difference in pixel height from selected y coordinate and center y coordinate hypotenuse = pixel distance from clock center to selected coordinate quadrant angle (in radians) = asin(336/454) = 0.83 => quadrant angle (in deg) = 47.44deg STEP 3: calculate the placement angle by adding the quadrant angle to the boundary angle of the quadrant quadrant1: placement angle = quadrant angle + 0degrees quadrant2: placement angle = quadrant angle + 90degrees quadrant3: placement angle = quadrant angle + 180degrees quadrant4: placement angle = quadrant angle + 270degrees Example: in quadrant 2: placement angle = quadrant angle + 90degrees = 47.44degrees + 90degrees = 137.44degrees STEP 4: convert the placement angle into a clock face position (in 'dot unit') by dividing it by 6degrees (dots are 6degrees apart from each other) Example: Selected Clock Hand Position = 137.44degrees/6degrees = 22.9 (almost on Dot23) Inquisit Algorithm to calculate the judgment error in ms: STEP1: calculate the absolute shortest distance btw. the targetClockHandPosition and the selectedPosition Example: targetClockHandPosition = 58.08 and selectedPosition = 1.34 values.distance = Math.max(58.08, 1.34) - Math.min(58.08, 1) = 58.08 - 1.34 = 56.74 if (56.74 > 30) {values.distance = 60-56.74 = 3.26 => shortest distance} (Note: 30 is the max absolute possible distance between dots) STEP2: determine the absolute judgment error in ms (calculating how long it takes the clock hand to travel the distance, with 50ms needed to travel from one dot to another) Example: values.judgmentError = 3.26 * 50ms = 163ms STEP3: determine the sign of the judgment error (does the selectedPosition precede (+) or trail (-) the targetClockHandPosition?) Example: if I add the absolute distance to the targetClockHandPosition and I get to the selectedPosition, the selectedPosition 'precedes' the targetClockHandPosition values.helper = 58.08 + 3.26 = 61.34 => corrected to 1.34 values.helper = 1.34 = 1.34 = values.selectedPosition => errorJudgment is positive ___________________________________________________________________________________________________________________ INSTRUCTIONS ___________________________________________________________________________________________________________________ provided by Millisecond Software - all instructions can be edited, either in the script (page elements and text stimuli) or in provided htm-files. To edit htm/html-files: open the respective documents in simple Text Editors such as TextEdit (Mac) or Notepad (Windows). ___________________________________________________________________________________________________________________ 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: /circleProportion: proportion of canvas height used for the circle radius of 60 dots (default: 0.4) /clockdotSize: proportional size of of the black clock dot faces (default: 2%) /handDotSize: proportional size of of the red clock hand dot (default: 3%) /rotationSpeed: the time it takes to rotate through the entire clock once (measured from starting point) (default: 3000ms) /maxNrRotations: number of time the clock hand maximally rotates before it stops (default: 100) /prepDuration: duration in ms in which only the 60 clock faces are presented before the clockHand dot appears (default: 2000ms) extra caution in changing these parameters is required: /toneDelay: the delay of the tone in ms (default: 250ms) !!!this change only affects any computations that take into account this delay. To change the actual delay, a new sound file with a new built-in delay period has to be created. /toneDuration: the duration (in ms) of the tone (default: 7ms)5 !!!this change only affects any computations that take into account this duration. To change the actual tone duration, a new sound file has to be created.