Return to the Wundt Clock Paradigm page
___________________________________________________________________________________________________________________	

				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:  03-13-2020 by K. Borchert (katjab@millisecond.com) for Millisecond Software, LLC

Script Copyright © 03-13-2020 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 FILE INFORMATION 
___________________________________________________________________________________________________________________
The default data stored 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
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 such as feedback trials. Thus, trialnum 
										may not reflect the number of main trials run per block. 
									
values.condition:					1 = baseline_action; 2 = baseline_tone; 3 = agency_action; 4 = agency_tone
values.targetEvent:					1 = action; 2 = tone
values.iti:							stores the random posttrialpause duration (in ms) => the time the dot moves after the target event has occurred
values.baseline_toneDelay:			stores the tone delay (in ms) in the baseline tone condition	
values.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

expressions.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)	
								
values.selectedPosition:			stores the participant selected clock face position of the clockHand when event occurred  
									see expressions.calculateSelectedPosition for details of how this value is calculated in this script
									based on the coordinates of the selected location
									
values.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
									
values.judgmentError:				stores the calculated judgment error in ms (=> time in ms required to cross values.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 expressions.calculateJudgmentError
							

(2) Summary data file: 'wundtclockparadigm_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)

meanJudgmentError_agency_action:	mean judgment error (in ms) in the agency_action condition
meanJudgmentError_baseline_action: 	mean judgment error (in ms) in the baseline_action condition
meanJudgmentError_agency_tone:		mean judgment error (in ms) in the agency_tone condition
meanJudgmentError_baseline_tone:	mean judgment error (in ms) in the baseline_tone condition
BindingScore_action:				difference btw. mean judgment errors in baseline_action and agency_action conditions
BindingScore_tone:					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 = max(58.08, 1.34) - 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.