Millisecond Forums

How to clean up this time estimation script - a beginning needs help for short script

https://forums.millisecond.com/Topic17697.aspx

By Psych_Josh - 11/10/2015

Hi everybody,

This is my first post, and I'm relatively inexperienced with Inquisit. I'm currently writing a script for a time estimation task, whereby a participant sees a '+' sign, presses the space button to produce an image (happy, sad, or neutral face), of which appears after a certain interval (either 100ms, 400ms, or 700ms), and the participant then judges the time it took for the image to appear via a scrolling bar that appears when the image disappears after staying on the screen for 400ms.

I've managed to write this script, which includes a few practice trials beforehand (where an image of a green circle appears after 100-1000ms, with 100ms intervals), however, it is extremely messy and inelegant, and I can't understand how some of the functions one would write to clean it up only produce errors (e.g., the 'clear stimulus' function).

It's by no means a long or complex script, judging by the standards of some I have used as comparators, but I genuinely can't make it cleaner than this. Firstly, I would like the practice trials to truly be a whole range (i.e., 100-1000ms, with 1ms intervals), but from what I gather, that would mean scripting every single number between 100-1000 in the list.targetduration attribute. Secondly, I would like the main task, where the image is produced after 100, 400, or 700ms to randomly, but equally, present the three different types of images. When I say 'randomly but equally', I mean I need the images to appear randomly, but in total, have appeared the same amount of times throughout the block (e.g., ten times each for 100, 400, and 700ms). At the moment, for 30 trials per image, I have listed the stimulus times (100, 400, 700ms) ten times each to ensure this, with /replace = false, but that looks completely inelegant. Finally, I attempted to use the 'clear' function to remove the stimuli for each trial, but it simply did not work for some reason, so instead I have to continually place white rectangles on top of the stimuli in order to remove it. 

I am more than happy to answer any questions if I have not been clear enough. I'm a beginner with Inquisit, and it's frustrating that some commands don't work when they theoretically should (at least from my novice perspective). I also apologise in advance if some of these topics have appeared in previous posts.

Many thanks!

Script:

*******************************************************************************************************************
*******************************************************************************************************************
INSTRUCTIONS
*******************************************************************************************************************
*******************************************************************************************************************
<instruct>
/windowsize = (90%, 90%)
/ fontstyle = ("Arial", 3.00%, false, false, false, false, 5, 1)
/ txcolor = (black)
/ screencolor = (255, 255, 255)
/ finishlabel = "Press <Spacebar>"
/nextkey = (57)
/nextlabel = "Press <Spacebar> to continue"
</instruct>

<page welcome>^^Welcome!
^^In this task you will be asked to estimate the duration of time intervals.
^^This task consists of 100 time estimation trials – the first 10 will be practice trials.
^^In the practice trials you will see a fixation cross (‘+’). When you are ready, press the spacebar to produce an image. Afterwards, you will be asked to estimate the time it took for the image to appear.
^^Once you have completed the practice trials and are familiarised with the task, you will proceed onto the main experiment.
^^In the practice trials, you will received feedback on your time estimation; however, you will not receive feedback in the main experiment.
</page>

<page main>^^Now you will begin the main experiment.^^Again, you will see a fixation cross, and, when you are ready, press the spacebar to produce an image.^^You will not receive any feedback regarding your time, so make sure you estimate the time as accurately as possible.
</page>

<page end>^^^Thank you for taking part in the experiment.
</page>

*******************************************************************************************************************
*******************************************************************************************************************
DEFAULTS
*******************************************************************************************************************
*******************************************************************************************************************
requires Inquisit 4.0.3.0

<defaults>
/minimumversion = "4.0.3.0"
/canvasaspectratio = (4,3)
</defaults>

*******************************************************************************************************************
*******************************************************************************************************************
VALUES
*******************************************************************************************************************
*******************************************************************************************************************
/completed:0 = script was not completed (prematurely aborted); 1 = script was completed (all conditions run)

/intervalestimation:stores the participant's estimation

********************
automatically updated
********************
<values>
/completed = 0
/intervalestimation = 0
</values>

*******************************************************************************************************************
*******************************************************************************************************************
DATA
*******************************************************************************************************************
*******************************************************************************************************************

********************
raw data
********************
build:Inquisit build
date, time, subject, group:date and time script was run with the current subject/groupnumber
blockcode, blocknum:the name and number of the current block
trialcode, trialnum: the name and number of the currently recorded trial
(Note: not all trials that are run might record data)
/intervalestimation:stores the participant's estimation
latency: the response latency (in ms)

<data>
/file = "ProspectiveTimeEstimation_rawdata.iqdat"
/separatefiles = true
/columns = [build, date, time, subject, group, blockcode, blocknum, trialcode, stimulusnumber, values.intervalestimation]
</data>

********************
summary data
********************

script.startdate:date script was run
script.starttime:time script was started
script.subjectid:subject id number
script.groupid:group id number
script.elapsedtime:time it took to run script (in ms)
/completed:0 = script was not completed (prematurely aborted); 1 = script was completed (all conditions run)

<summarydata >
/file = "ProspectiveTimeEstimation_summary.iqdat"
/columns = [script.startdate, script.starttime, script.subjectid, script.groupid, script.elapsedtime, values.completed]
</summarydata>


*******************************************************************************************************************
*******************************************************************************************************************
LISTS
*******************************************************************************************************************
*******************************************************************************************************************

<list targetduration>
/items = (100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
items = (100, 1000)
/replace = false
</list>

<list targetdurationh>
/items = (100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700)
/replace = false
</list>

<list targetdurationn>
/items = (100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700)
/replace = false
</list>

<list targetdurations>
/items = (100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700)
/replace = false
</list>

*******************************************************************************************************************
*******************************************************************************************************************
STIMULI
*******************************************************************************************************************
*******************************************************************************************************************

Stimuli presentation (Emoticons):
<item emoticonsh>
/1 = "HappyFace.png"
</item>

<picture emoticonsh>
/items = emoticonsh
/position = (50, 50)
</picture>

<item emoticonss>
/1 = "SadFace.png"
</item>

<picture emoticonss>
/items = emoticonss
/position = (50, 50)
</picture>

<item emoticonsn>
/1 = "NeutralFace.png"
</item>

<picture emoticonsn>
/items = emoticonsn
/position = (50, 50)
</picture>


Extra stimuli:

<shape circle>
/shape = circle
/size = (1% * 3/4 * 10, 10%)
/color = green
/position = (50%, 50%)
/erase = false
</shape>

<text cross>
/items = ("+")
/color = (0,0,0)
</text>

<text blank>
/items = (" ")
/color = (0,0,0)
</text>

<shape whiterectangle>
/shape = rectangle
/size = (70%, 70%)
/color = white
/position = (50%, 50%)
/erase = false
</shape>


Time estimation slide scale:

<slider TE_response>
/ caption="How much time before the image appeared (in ms)?"
/ labels=("0s", "100ms", "200ms", "300ms", "400ms", "500ms", "600ms", "700ms", "800ms", "900ms", "1000ms")
/responsefontstyle = ("Arial", 1.5%, false, false, false, false, 5, 1)
/ txcolor = (0, 0, 0)
/ range = (0, 1000)
/ increment = 100
/showticks = true
/slidersize = (70%, 30%)
/position = (10%, 50%)
/defaultresponse = 0
</slider>

*******************************************************************************************************************
*******************************************************************************************************************
TRIALS
*******************************************************************************************************************
*******************************************************************************************************************

*********
Practice trials
*********

<trial practice>
/stimulustimes = [500 = cross]
/correctresponse = (" ")
/pretrialpause = 500
/branch = [trial.practicedot]
/recorddata = false
</trial>

Note: presents a face after correct response
Spacebar advances to time estimation
<trial practicedot>
/stimulustimes = [1 = whiterectangle]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, list.targetduration.nextvalue)]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, list.targetduration.currentvalue+100)]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, list.targetduration.currentvalue+200)]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, list.targetduration.currentvalue+300)]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.whiterectangle, list.targetduration.currentvalue+400)]
/timeout = (list.targetduration.currentvalue+1000)
/branch = [surveypage.tep]
/recorddata = false
/ontrialend = [trial.practicedot.setstimulustime(shape.whiterectangle, list.targetduration.currentvalue)]
/ontrialend = [trial.practicedot.setstimulustime(shape.whiterectangle, list.targetduration.currentvalue+100)]
/ontrialend = [trial.practicedot.setstimulustime(shape.whiterectangle, list.targetduration.currentvalue+200)]
/ontrialend = [trial.practicedot.setstimulustime(shape.whiterectangle, list.targetduration.currentvalue+300)]
</trial>

Note: presents time estimation slide scale

<surveypage TEp>
/questions = [1 = TE_response]
/showpagenumbers = false
/ontrialend = [values.intervalestimation = slider.te_response.response]
/recorddata = false
/branch = [trial.feedback]
</surveypage>

<trial feedback>
/stimulustimes = [100 = endtrial]
/pretrialpause = 200
/correctresponse = (57)
/recorddata = false
</trial>

<text endtrial>
/items = ("The time interval to be estimated was: <%list.targetduration.currentvalue%>ms

Your estimation: <%slider.te_response.response%>ms

Press <Spacebar> to continue")
</text>

*********
Emoticon presentation - Positive
*********

<trial trialhappystart>
/stimulustimes = [500 = cross]
/correctresponse = (" ")
/pretrialpause = 500
/branch = [trial.trialhappyface]
/recorddata = false
</trial>

Note: presents a face after correct response
Spacebar advances to time estimation
<trial trialhappyface>
/stimulustimes = [1 = whiterectangle]
/ontrialbegin = [trial.trialhappyface.insertstimulustime(picture.emoticonsh, list.targetdurationh.nextvalue)]
/ontrialbegin = [trial.trialhappyface.insertstimulustime(picture.emoticonsh, list.targetdurationh.currentvalue+100)]
/ontrialbegin = [trial.trialhappyface.insertstimulustime(picture.emoticonsh, list.targetdurationh.currentvalue+200)]
/ontrialbegin = [trial.trialhappyface.insertstimulustime(picture.emoticonsh, list.targetdurationh.currentvalue+300)]
/ontrialbegin = [trial.trialhappyface.insertstimulustime(shape.whiterectangle, list.targetdurationh.currentvalue+400)]
/timeout = (list.targetdurationh.currentvalue+1000)
/branch = [surveypage.te]
/recorddata = true
/ontrialend = [trial.trialhappyface.setstimulustime(shape.whiterectangle, list.targetdurationh.currentvalue)]
/ontrialend = [trial.trialhappyface.setstimulustime(shape.whiterectangle, list.targetdurationh.currentvalue+100)]
/ontrialend = [trial.trialhappyface.setstimulustime(shape.whiterectangle, list.targetdurationh.currentvalue+200)]
/ontrialend = [trial.trialhappyface.setstimulustime(shape.whiterectangle, list.targetdurationh.currentvalue+300)]
</trial>



*********
Emoticon presentation - Neutral
*********

<trial trialneutralstart>
/stimulustimes = [500 = cross]
/correctresponse = (" ")
/pretrialpause = 500
/branch = [trial.trialneutralface]
/recorddata = false
</trial>

Note: presents a face after correct response
Spacebar advances to time estimation
<trial trialneutralface>
/stimulustimes = [1 = whiterectangle]
/ontrialbegin = [trial.trialneutralface.insertstimulustime(picture.emoticonsh, list.targetdurationn.nextvalue)]
/ontrialbegin = [trial.trialneutralface.insertstimulustime(picture.emoticonsh, list.targetdurationn.currentvalue+100)]
/ontrialbegin = [trial.trialneutralface.insertstimulustime(picture.emoticonsh, list.targetdurationn.currentvalue+200)]
/ontrialbegin = [trial.trialneutralface.insertstimulustime(picture.emoticonsh, list.targetdurationn.currentvalue+300)]
/ontrialbegin = [trial.trialneutralface.insertstimulustime(shape.whiterectangle, list.targetdurationn.currentvalue+400)]
/timeout = (list.targetdurationn.currentvalue+1000)
/branch = [surveypage.te]
/recorddata = true
/ontrialend = [trial.trialneutralface.setstimulustime(shape.whiterectangle, list.targetdurationn.currentvalue)]
/ontrialend = [trial.trialneutralface.setstimulustime(shape.whiterectangle, list.targetdurationn.currentvalue+100)]
/ontrialend = [trial.trialneutralface.setstimulustime(shape.whiterectangle, list.targetdurationn.currentvalue+200)]
/ontrialend = [trial.trialneutralface.setstimulustime(shape.whiterectangle, list.targetdurationn.currentvalue+300)]
</trial>



*********
Emoticon presentation - Positive
*********

<trial trialsadstart>
/stimulustimes = [500 = cross]
/correctresponse = (" ")
/pretrialpause = 500
/branch = [trial.trialsadface]
/recorddata = false
</trial>

Note: presents a face after correct response
Spacebar advances to time estimation
<trial trialsadface>
/stimulustimes = [1 = whiterectangle]
/ontrialbegin = [trial.trialsadface.insertstimulustime(picture.emoticonsh, list.targetdurations.nextvalue)]
/ontrialbegin = [trial.trialsadface.insertstimulustime(picture.emoticonsh, list.targetdurations.currentvalue+100)]
/ontrialbegin = [trial.trialsadface.insertstimulustime(picture.emoticonsh, list.targetdurations.currentvalue+200)]
/ontrialbegin = [trial.trialsadface.insertstimulustime(picture.emoticonsh, list.targetdurations.currentvalue+300)]
/ontrialbegin = [trial.trialsadface.insertstimulustime(shape.whiterectangle, list.targetdurations.currentvalue+400)]
/timeout = (list.targetdurations.currentvalue+1000)
/branch = [surveypage.te]
/recorddata = true
/ontrialend = [trial.trialsadface.setstimulustime(shape.whiterectangle, list.targetdurations.currentvalue)]
/ontrialend = [trial.trialsadface.setstimulustime(shape.whiterectangle, list.targetdurations.currentvalue+100)]
/ontrialend = [trial.trialsadface.setstimulustime(shape.whiterectangle, list.targetdurations.currentvalue+200)]
/ontrialend = [trial.trialsadface.setstimulustime(shape.whiterectangle, list.targetdurations.currentvalue+300)]
</trial>

<surveypage TE>
/questions = [1 = TE_response]
/showpagenumbers = false
/ontrialend = [values.intervalestimation = slider.te_response.response]
/recorddata = true
</surveypage>


*******************************************************************************************************************
*******************************************************************************************************************
BLOCKS
*******************************************************************************************************************
*******************************************************************************************************************
<block PracticeBlock>
/preinstructions = (welcome)
/trials = [1-10 = noreplace(practice)]
</block>


<block TimeEstimation>
/preinstructions = (main)
/postinstructions = (end)
/trials = [1-90 = noreplace(trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart, trialhappystart, trialsadstart, trialneutralstart)]
</block>

*******************************************************************************************************************
*******************************************************************************************************************
EXPERIMENT
*******************************************************************************************************************
*******************************************************************************************************************
<expt >
/blocks = [1 = PracticeBlock; 2 = TimeEstimation]
/onexptend = [values.completed = 1]
</expt>

*******************************************************************************************************************
End of File
*******************************************************************************************************************





By Dave - 11/10/2015

> Firstly, I would like the practice trials to truly be a whole range (i.e., 100-1000ms, with 1ms intervals), but from what I gather, that would
> mean scripting every single number between 100-1000 in the list.targetduration attribute

No, it doesn't necessarily mean you have to write out all numbers. You could use simple math:

<list targetduration>
/ poolsize = 901
</list>

will give you 901 consecutive index numbers -- from 1 to 901. You can then do

<values>
...
/ targetduration = 0
...
</values>

<trial practicedot>
/stimulustimes = [1 = whiterectangle]
/ ontrialbegin = [values.targetduration = 99 + list.targetduration.nextindex; ]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, values.targetduration)]
/ontrialbegin = [trial.practicedot.insertstimulustime(shape.circle, values.targetduration+100)]
...
</trial>

However, selecting 1 ms intervals does not actually make sense in practice: That's not how displays work. A display running at 100Hz will re-draw the screen at 10ms intervals only, a display running at 60Hz will only re-draw every ~16.7 ms. No display that I know of refreshes at 1000Hz, which is what you'd need to achieve 1ms granularity.

> Secondly, I would like the main task, where the image is produced after 100, 400, or 700ms to randomly, but equally, present the three
> different types of images. When I say 'randomly but equally', I mean I need the images to appear randomly, but in total, have appeared
> the same amount of times throughout the block (e.g., ten times each for 100, 400, and 700ms). At the moment, for 30 trials per image, I
> have listed the stimulus times (100, 400, 700ms) ten times each to ensure this, with /replace = false, but that looks completely
> inelegant.

<list targetdurationh>
/items = (100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700, 100, 400, 700)
/replace = false
</list>

can equivalently be stated as

<list targetdurationh>
/ items = (100, 400, 700)
/ poolsize = 30
/ replace = false
</list>

> Finally, I attempted to use the 'clear' function to remove the stimuli for each trial, but it simply did not work for some reason, so instead I
> have to continually place white rectangles on top of the stimuli in order to remove it.

The function's purpose is *not* to remove stimuli from the screen during a trial. Overwriting the stimulus with a blank is exactly the way "erasing" is supposed to work (cf. the "How to erase stimuli" topic in the documentation).

To be specific, the clear() function removes *items from a stimulus element*. The clearstimulusframes() function -- when called -- *removes all stimulus objects* from the given <trial> element, i.e., if you were to call that function /ontrialend, said <trial>'s *next* instance would not present any stimulus objects.
By Psych_Josh - 11/11/2015

Thank you so much for your response! It was very helpful, though some bugs ensued as a result:

Firstly:
<text endtrial>
/items = ("The time interval to be estimated was: <%list.targetduration.currentvalue%>ms

Your estimation: <%slider.te_response.response%>ms

Press <Spacebar> to continue")
</text>

This stopped producing a number, and replacing it with values.targetduration (with and without .currentvalue) produced an error. How would I remedy this so that it displayed the target's onset time?

Secondly, I experience a 'blinking' effect during the practice trials (I have not tried with the main experiment). I think this is something to do with having to replace rectangles on top of the stimuli to 'erase' them, but then another circle appearing afterwards. Effectively, it is not erasing the original stimuli (the circle) when it moves onto the next trial. So, in the second trial, it reappears, a white rectangle erases it, and then another circle appears. This builds up over the course of many trials to produce multiple 'blinks'. At least, this is my novice estimation of the problem.

Thank you again for taking the time to help me resolve the issue.
By Dave - 11/11/2015

#1 ought to read

<text endtrial>
/items = ("The time interval to be estimated was: <%values.targetduration%>ms

Your estimation: <%slider.te_response.response%>ms

Press <Spacebar> to continue")
</text>

#2 "Effectively, it is not erasing the original stimuli (the circle) when it moves onto the next trial"

is how it's supposed to work when you use the insertstimulustime() or -frame() functions. The changes are cumulative, i.e., the stimuli you *add* in instance n of the trial will carry over to instance n+1 and so forth. If you don't want that, you need to reset the trial's stimulus presentation queue to its initial state at the end of each trial. You do so by calling the resetstimulusframes() function /ontrialend, e.g.

<trial practicedot>
...
/ ontrialend = [trial.practicedot.resetstimulusframes(); ]
...
</trial>

Beyond that you should to pay attention to the individual stimulus elements' /erase settings. If /erase is not explicitly set to false, the stimulus will be blanked at the end of the trial by default -- that includes any objects you use to erase / overwrite stimuli *during the trial* (this is also covered in the "How to erase stimuli" topic mentioned previously).
By Psych_Josh - 11/11/2015

Thank you so much for your assistance - that all worked. 

One final thing to clear-up, is the 'BLOCKS' section, where I've had to set the trials to 90, no replace, and 30 of each trialhappystart, trialsadstart and trialneutralstart, to ensure there are 30 presentations of each. Is there a more elegant way of scripting this? I looked, but the poolsize function is absent for 'block' elements.

Thanks again!
By Dave - 11/11/2015

The *proportion* of elements you enter in a selection pool is what's relevant here. Here are some pertinent examples from the language reference for the /trials attribute.

The following block randomly selects either lefttrial or righttrial for each of its ten trials. Both trial types are run exactly five times.
<block myblock>
/ trials=[1-10=noreplace(lefttrial, righttrial)]
</block>...
The following block randomly selects either testtrial or distractortrial for each of its 12 trials. The testtrial is run exactly 8 time and distractortrial is run 4 times.
<block myblock>
/ trials=[1-12=noreplace(testtrial, testtrial, distractortrial)]
</block>
Thus, you can simply state
/trials = [1-90 = noreplace(trialhappystart, trialsadstart, trialneutralstart)]

and that will run 90 trials in random order with trialhappystart, trialsadstart and trialneutralstart in equal proportions, i.e., 30 each.
By Psych_Josh - 11/12/2015

Wonderful, thank you very much, you have been a great help!