By Blackadder - 10/8/2013
Hi All, consider the following (functional) script:
<text TEXT_A> / erase = false / items = ("A") / txbgcolor = white </text>
<text TEXT_B> / erase = false / items = ("B") / txbgcolor = white </text>
<shape SHAPE_dummy> / color = white / erase = false / position = (0%, 0%) / size = (1px, 1px) / shape = rectangle </shape>
<trial TRIAL_main> / branch = [if (trial.TRIAL_main.response==57) trial.TRIAL_main] / responseframe = 1 / responseinterrupt = trial / stimulusframes = [1=TEXT_A; 3=TEXT_B; 4=SHAPE_dummy] / timeout = 0 / validresponse = ("a", 57) </trial>
<block BLOCK_main> / trials = [1 = TRIAL_main] </block>
<expt> / blocks = [1 = BLOCK_main] </expt>
The code above presents an "A" for 2 frames, then presents a "B" for 1 frame, followed by a stimulus dummy for another frame. The dummy is there to have "A" and "B" stay on the screen for 2 frames each.
Then, the trial branches onto itself and starts anew, the result being a rapid flicker between "A" and "B".
The script is supposed to stop if the "a" key is pressed (scancode 30) and meanwhile just record every press of the space bar (scancode 57).
My question: why does this script not record any keypresses?
If I understand the help correctly, response recording should start at frame 1. Hence, if I pressed the space bar somewhere between frame 1 and 4, the trial should return a 57 as its response. Well, it doesn't, and neither does "a" terminate the script. Why is that?
Bye, Malte
|
By Dave - 10/8/2013
My question: why does this script not record any keypresses?
Because
<trial TRIAL_main> / branch = [if (trial.TRIAL_main.response==57) trial.TRIAL_main] / responseframe = 1 / responseinterrupt = trial / stimulusframes = [1=TEXT_A; 3=TEXT_B; 4=SHAPE_dummy] / timeout = 0 / validresponse = ("a", 57) </trial>
you leave no time for any responses whatsoever.
|
By Blackadder - 10/9/2013
Aha! Thanks a lot for clarifying.
So with a refresh rate of 60 Hz and a trial that covers 4 frames, I'd set the timeout to 4 * 1/60 * 1000 = 66 milliseconds.
The trial would then look like
<trial TRIAL_main> / branch = [if (trial.TRIAL_main.response==57) trial.TRIAL_main] / responseframe = 1 / responseinterrupt = trial / stimulusframes = [1=TEXT_A; 3=TEXT_B; 4=SHAPE_dummy] / timeout = 66 / validresponse = ("a", 57) </trial>
This appears to work, Inquisit records responses now. Allow me two questions:
(1) Inquisit constantly records "46" as the trial latency on trials where i pressed the space bar. Where does this value of 46 milliseconds come from?
(2) Should I incorporate some kind of tolerance value to guarantee that Inquisit will not wait too long (i.e., more than 1 frame) before ending the trial. I'm thinking 60 instead of 66 milliseconds.
Best wishes, Malte
|
By Dave - 10/9/2013
(1) Inquisit constantly records "46" as the trial latency on trials where i pressed the space bar. Where does this value of 46 milliseconds come from?
I don't know. Might be a systematic delay induced by your keyboard, for example. Note that with a trial this short you are approaching typical measurement error sizes for some keyboards (they vary greatly).
(2) Should I incorporate some kind of tolerance value to guarantee that Inquisit will not wait too long (i.e., more than 1 frame) before ending the trial. I'm thinking 60 instead of 66 milliseconds.
You might want to try, but that may exacerbate #1 above.
|
By Blackadder - 10/9/2013
Hi Dave, your hunch was spot on. I just tested latency recording with a Cedrus keypad which gave reasonable and, more importantly, variable latencies. Seems to be a Windows messaging issue indeed. The peculiar thing is that with /timeout = 66, the trial latency on noresponse trials is recorded as 46. A mystery.
My problem now is that with the Cedrus keypad I'm missing 30% - 40% of all button presses, on a normal keyboard between 70% and 80%. Most probably, those responses fall into the trial preparation/allocation or cleanup intervals and are not registered.
Do you have any suggestions on how to this could be avoided in what I try to do. My only idea so far would be prolonging the trial as in
/ stimulusframes = [1=A;3=B;5=A;7=B;9=A;...]
The obstacle being that in my actual experiment, "A" consists of five BMPs which makes me worry if this will cause too much precaluation and thus disrupt the 2-frame update intervals.
My second question would be: is there any way of terminating a trial which does not involve a user response besides the /timeout property?
Best wishes, Malte
|
By Dave - 10/9/2013
The peculiar thing is that with /timeout = 66, the trial latency on noresponse trials is recorded as 46. A mystery.
This would be consistent with a loss / lag of one frame on a system running at 50Hz refresh rate (i.e., a 20ms refresh cycle). Could be either
- an off-by-one bug in /responseframe. What happens when with /responseframe=0 and /responsetime=0 respectively? What happens when you extend the timeout -- is the latency for non-responses still off by the same amount?
- a one-frame-lag induced by some other system component (driver, display hardware).
- something else entirely which I haven't thought off.
My only idea so far would be prolonging the trial as in / stimulusframes = [1=A;3=B;5=A;7=B;9=A;...]
That would be my intuition as well. I have a gut-level feeling, though, that Inquisit may not be a particularly good fit for the particular type of study you're aiming to implement. Can't be sure about that, though, without further details (i.e., which are the variables of interest, relative to what are responses to be measured, etc.?).
My second question would be: is there any way of terminating a trial which does not involve a user response besides the /timeout property?
/trialduration, but I don't immediately see how that would help. /trialduration fixes the trial's duration to the specified value (duh, I know), while /timeout specifies maximum duration. The way your trials are set up (/responseinterrupt), though, it shouldn't make any difference which one you use.
|
By Blackadder - 10/10/2013
This would be consistent with a loss / lag of one frame on a system running at 50Hz refresh rate (i.e., a 20ms refresh cycle).
The data comes from my notebook (60Hz) on which I've done some more testing in the meantime. First observation I made was that the recorded latency scales linearly with the timeout. It is always "timeout-16" (yes, "minus"), at least for the dozen or so timeouts I've checked. 16 fits nicely with the refresh cycle of 16.6665 ms with a 60Hz refresh rate.
Conclusion is: you were right again, the /responseframe=1 attribute is causing the problems. One might say that it's not a bug but rather unexpected behavior. While the frame count in the /stimulusframes property starts at 1, /responseframe starts at 0. Setting /responseframe=0 or /responsetime=0 has latency and timeout become identical.
I have a gut-level feeling, though, that Inquisit may not be a particularly good fit for the particular type of study you're aiming to implement.
May very well be true. I had initially thought about using Matlab+PschophysicsToolbox for this special use case, but I reckoned it such a simple setup that I chose to try Inquisit first. I only need two stimuli to alternate at about 33Hz for several minutes and to record keypresses and their timings during the whole thing. Response timing accuracy is not the top priority since responses should usually be seperated by seconds, not milliseconds. The only crucial thing is that there must not be much disruption in the 33Hz flicker frequency.
It's ironic that I have everything working in Inquisit (realtime priority and the like) except for response recording. BUT with /responsetime=0 the lost keypress problem has improved greatly. Inquisit only misses about 20% of keypresses via a normal keyboard. I'll try with the Cedrus now. 10% missed responses might be acceptable.
|
By Blackadder - 10/11/2013
One more question for those with insight into the Inquisit code. If in a trial I have
/ stimulusframes = [1=A; 3=B]
The trial will then span 3 frames. In frame 4, given nothing takes too long after the onset of frame 3, the next frame (i.e., frame 4) should display the first frame of the following trial.
If the trial further contains
/ timeout = 40
and with a refresh rate of 60 Hz, response recording will stop at some point during the third frame, thus bearing the risk of missing keypresses.
What happens when I use
/ trialduration = 40
instead? Will response recording stop after 40 msec just as with the /timeout property?
|
By Dave - 10/11/2013
/timeout vs. /trialduration should not make any difference here. As detailed previously, /timeout determines *maximum* trialduration (i.e., the trial may terminate earlier if applicable), /trialduration *fixes* duration to the specified value (i.e., the trial *will not terminate* earlier).
Giving the diagram in the "How to control trial duration and inter-trial intervals" topic in the docs another look might help to clarify.
|
By Blackadder - 10/11/2013
I am aware of the flow diagram in the docs. The key issue to me is that both /timeout and /trialduration work with a millisecond metric while the actual metric for the experimentator is always discrete, i.e. frames.
Consequently, /trialduration=55 will never be accurate on a 60Hz system. The actual trial length will always be at least 66.665 msec. Hence, physical trial length and defined trial length are not identical, thereby making it impossible to precisely sync response recording to trial duration.
Inquisit handles this very nicely in parts by introducing the frames metric for various trial properties. Unfortunately not for the only two properties that allow to end a trial. I'd love to see /timeoutframe and /trialdurationframes in the next release.
Anyway, thanks for your help, Dave.
|
By Dave - 10/12/2013
the actual metric for the experimentator is always discrete, i.e. frames.
Yes and no.
Consequently, /trialduration=55 will never be accurate on a 60Hz system. The actual trial length will always be at least 66.665 msec
Also yes and no. Of course, Inquisit can terminate response polling and the like after 55ms, thus terminating the trial. What it cannot do (and neither can any other software), is make your display do anything when it isn't ready to (i.e., when it is in the midst of a refresh cycle).
I'd love to see /timeoutframe and /trialdurationframes in the next release.
Not sure I personally like this idea, but you can do this now. Nothing prevents you from computing frame-perfect durations in ms based on the display.refreshinterval or display.refreshrate property. /timeout, /trialduration and the like do accept values and expressions. And for the stimulus presentation sequence there is also /numframes.
However, I don't see how any of that helps to solve the actual problem at hand.
|
By Blackadder - 10/12/2013
Yes and no.
Let's just stay with the "yes" part when it comes to the observer's perspective - which should be the focus of interest for the experimentator. Disregarding afterimages of any sort, the visual stimulation from a trial will always end after a discrete amount of frames. Of course you can arbitrarily terminate some processes within the software on a very fine-grained discrete scale - such as response polling. At the observer end, however, a trial and all internal observer responses it evokes terminate along a rather coarse discrete timline determined by the monitor framerate.
Nothing prevents you from computing frame-perfect durations in ms based on the display.refreshinterval or display.refreshrate property. /timeout, /trialduration and the like do accept values and expressions.
That's reassuring. What happens when my trial is 4 frames long, i.e., 1/60*1000 msec and I set the timeout to exactly these 1/60*1000. Will the frame refresh and the timeout compete with each other? The scenario I'm thinking about is the graphics driver preparing the next refresh while Inquisit waits for the timeout to complete. At some point the next refresh is about to happen. At this exact moment Inquisit realizes that the timeout has come and it tries to update the frame buffer... too late because the next refresh just happened.
Or is Inquisit smart enough to realize that the timeout coincides with a refresh onset and adjust things accordingly? Meaning that it prepares the next trial right after it has put up the last frame of the previous trial while keeping to poll responses until the actual next refresh?
|
By Dave - 10/12/2013
Will the frame refresh and the timeout compete with each other?
Unless there are other sources of error or drift, yes. But if you want to make absolutely sure to never miss a frame, you need to use pre- and posttrialpause (which are part of trialduration) to give Inquisit time for stim prep and cleanup. Again, the diagram mentioned previously should come in handy to clarify.
|
By Blackadder - 10/12/2013
you need to use pre- and posttrialpause (which are part of trialduration) to give Inquisit time for stim prep and cleanup. Again, the diagram mentioned previously should come in handy to clarify.
Yes, but Inquisit won't record responses during pre-/posttrialpause, if I understand the docs correctly.
Seems my problem boils down to not being able to
a) do a finite, yet lenghty loop of stimulus presentations within a trial while
b) polling multiple responses per trial
Guess it's Matlab then. Thanks for responding so thoroughly.
|
By Dave - 10/12/2013
Inquisit won't record responses during pre-/posttrialpause, if I understand the docs correctly.
Yes, that is absolutely correct.
Seems my problem boils down to not being able to a) do a finite, yet lenghty loop of stimulus presentations within a trial while b) polling multiple responses per trial
I agree. Inquisit's model doesn't seem to be a good fit here because
- a trial is designed to collect a single response and
- stimulus presentation and response collection are intricately linked (a <trial> is a self-contained unit which tries to ensure maximum precision within it; what happens between trials is another matter).
What you would need is some method to completely de-couple stimulus presentation and response polling, or at least something that keeps stimulus presentation intact *across* trials. I, frankly, don't see a fail-safe way to achieve this with Inquisit.
|
|