Millisecond Forums

Stop flickering!

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

By Blackadder - 5/10/2010

Hi All,

if I understand things correctly, the following should hold:

(i) The /erase property of a stimulus has Inquisit clear the area of the screen inhabited by the respective stimulus upon the end of a trial.

(ii) When a trial ends in frame i, the next trial ought to start in frame i+1.

(iii) Be the last frame of a trial called i, the final stimulus in the stimulus sequence will be visible until and including this frame i, provided there is no posttrialpause.

(iv) Be the first frame of the next trial called i+1, the initial stimulus in the stimulus sequence will be visible already in this frame i+1, provided there is no pretrialpause.

If all of the above is true, I'm afraid this is not what happens. Consider the script below which is pretty self-explanatory. When the stimulus with erase set to "true" is active, Inquisit displays the cleared screen contents for supposedly one frame, thus causing the text to flicker. Why is that?

Bye, Malte


--

<text TEXT_blink>
/ erase = true(white)
/ items = ("Press 'b' to stop blinking. And just whisper 'q' to quit.")
</text>

<text TEXT_steady>
/ erase = false
/ items = ("Press 'b' to start blinking. And just whisper 'q' to quit.")
</text>

<text TEXT_hint>
/ erase = false
/ items = ("Inquisit's a bit slow on the uptake, though. You may have to try more than once.")
/ position = (50,75)
</text>


<trial TRIAL_blink>
/ branch = [if(trial.TRIAL_blink.response==48)trial.TRIAL_steady]
/ branch = [if(trial.TRIAL_blink.response!=48 && trial.TRIAL_blink.response!=16)trial.TRIAL_blink]
/ responsetime = 0
/ stimulustimes = [0=sequence(TEXT_blink,TEXT_hint)]
/ timeout = 40
/ validresponse = (anyresponse)
</trial>

<trial TRIAL_steady>
/ branch = [if(trial.TRIAL_steady.response==48)trial.TRIAL_blink]
/ branch = [if(trial.TRIAL_steady.response!=48 && trial.TRIAL_steady.response!=16)trial.TRIAL_steady]
/ responsetime = 0
/ stimulustimes = [0=sequence(TEXT_steady,TEXT_hint)]
/ timeout = 40
/ validresponse = (anyresponse)
</trial>


<block BLOCK_main>
/ trials = [1=TRIAL_steady]
</block>

<expt>
/ blocks = [1=BLOCK_main]
</expt>

By Dave - 5/10/2010

(i) The /erase property of a stimulus has Inquisit clear the area of the screen inhabited by the respective stimulus upon the end of a trial.


True.


(ii) When a trial ends in frame i, the next trial ought to start in frame i+1.


Not quite, if I understand your notation correctly. If 'erase=true' for any stimulus, the next trial ought to start in frame i+2, with one additional frame in between trials to perform the erase. If 'erase=false' for all stimuli, the next trial indeed ought to start in frame i+1.


(iii) Be the last frame of a trial called i, the final stimulus in the stimulus sequence will be visible until and including this frame i, provided there is no posttrialpause.


Correct.


(iv) Be the first frame of the next trial called i+1, the initial stimulus in the stimulus sequence will be visible already in this frame i+1, provided there is no pretrialpause.


See my note on (ii). This holds true only if / 'erase = false' for all stimuli.


When the stimulus with erase set to "true" is active, Inquisit displays the cleared screen contents for supposedly one frame, thus causing the text to flicker. Why is that?


Precisely because '/ erase = true'.


~Dave

By Blackadder - 5/10/2010

Not quite, if I understand your notation correctly. If 'erase=true' for
any stimulus, the next trial ought to start in frame i+2, with one
additional frame in between trials to perform the erase. If
'erase=false' for all stimuli, the next trial indeed ought to start in
frame i+1.



Is that stated somewhre in the help or is it mere conjecture based on what Inquisit actually does?


To me, erasing a stimulus from video memory and displaying the erased contents of the screen are two entirely different things. There is no reason why Inquisit should not commit the deletion of a certain part of the screen within one vertical retrace and on the next frame show the contents of the previously cleared video memory.


In my conception, the "erase" property exists to dispense with the need of creating blank stimuli and superimpose them onto areas that are to be erased at the end of a trial. Hence, "erase=true(white)" in a stimulus called "TEXT_oldtext" should accomplish the same thing as "0=sequence(SHAPE_blank,TEXT_newtext) in the next trial. The replacement of TEXT_oldtext by TEXT_newtext should in both cases happen without a blink inbetween.


The wording in the help kind of supports my notion. It says "at the end of a trial", not "after the end of a trial". I'd thus file the flickering as a bug, if you ask me.



Bye, Malte

By Dave - 5/10/2010

Is that stated somewhre in the help or is it mere conjecture based on what Inquisit actually does?


From the "How to Erase Stimuli" topic (emphasis is mine): "By default, Inquisit erases all stimuli presented on a given trial after the
subject has responded
."


However, as ever so often, only Sean will be able to provide you with a definitive answer.


~Dave

By seandr - 5/11/2010

Malte,


David's reply is correct - the process of erasing (which is no different than the process of presenting a stimulus) takes one frame. Specifically, if the last stimulus on a given trial was presented on frame N (and the subject responds in 0 milliseconds or the trial is set with /response=noresponse), the stimulus is erased at frame N+1. Response time, obviously, can push this back further.


Note that Inquisit trials were designed to be autonomous, meaning that they can run without making any assumptions about what trials were run before or what trials will follow. Given branching and other ways of dynamically adjusting task flow, the fewer implicit assumptions or connections made between trials, the better. For example, what if a given trial decides to erase its stimuli on the first frame of a subsequent trial but the subsequent trial is not run because a stop condition is met? Or what if the following trial includes a 500 ms pretrialpause? I can imagine the system attempting to handle these various situations, but the result would be more complicated than it needs to be.


I'm not sure what scenario led you to this discovery, but if you wish to present a stimulus and have it erased the next frame, it sounds like you should be doing this within one trial rather than two linked trials. Typically, tachistoscopic presentations are handled in a single trial, and that was certainly my expectation when I designed this. If that's not possible, I'd be curious to know why. Perhaps there some other limitation in the design of the trial that needs to be reconsidered.


If for some reason a single trials isn't possible, than you can set /erase=false as mentioned already and then present the erasing stimulus at the beginning of the next trial.


-Sean

By Blackadder - 5/11/2010

Dear Sean,


thanks for clearing this up. If I understand your explanation correctly it practically implies that an experiment with k trials will always be k frames longer than what would be expected by simply adding up the stimulusframes definitions.


It's not to say that I do not understand your explanation but I struggle to follow its logic entirely. Let's again assume that trial A is supposed to end in frame i due to the stimulusframes specification. It is thus probably valid to say that trial A owns frame i. Things proceed frome there as follows:


(1) Upon presentation of frame i, trial A iterates through all its cleaning up stuff, i.e. executing the erase-statements of the formerly displayed stimuli.


(2) Frame i+1 comes up which technically belongs to no-one. Trial A has gone to rest after the exhaustive housecleaning and trial B got just waken up and is now told to prepare its stimulus presentation.


(3) In frame i+2, the first frame owned by trial B, the stimulus presentation of trial B finally starts.


So in the end, between every two trials, there lies on rogue frame owned by nobody which just contains everything that has been left over by previous trials.


My question is: why no within-frame handshake between two subsequent trials? Or, to be more precise, no handshake at all but just a speedier switch than currently. Things would proceed somewhat as follows:


(1a) Frame i is shown, trial A commits its cleaning up and goes to sleep after a millisecond or so. Trial B is woken up and told "Hurry, prepare your stuff, your first frame (i+1) is coming up."


(1b) Trial B lives up to the expectations and has stimulus presentation ready before the advent of frame i+1.


(2) Frame i+1 is shown - no flicker, no additional frames between trials



I do not see where this would introduce interdependencies between trials, it just saves one frame by handing over display control between trials somewhere within a retrace interval instead of at the exact beginning of one.


Bye, Malte.

By Dave - 5/11/2010

Sorry to stray away from the techy stuff in this reply, but actually I don't understand what the fuss is about. You can get Inquisit  to behave exactly as you whish by simply keeping '/ erase = false' on your stims and either using "blank" stims to clear protions of your screen at any time you want or by setting up trial B's stims to properly overwrite (and implicitly erase) trial A's stims -- no orphaned frames between trials this way. Personally, I almost never use '/ erase = true' on any of my stims. What am I missing?


~Dave

By seandr - 5/11/2010

My question is: why no within-frame handshake between two subsequent trials?


Well, as I said before, there's no guarantee there will be a subsequent trial, or that that subsequent trial won't pause 500ms before it gets on to the business of presenting its stimuli and erasing those of the previous trial.


There are dozens of tasks where as soon as a response is given, the target stimulus is erased and a correct or error message is immediately displayed. If cleanup is the responsibility of the subsequent trial, how do I program this very common response paradigm? With two trials?


If a trial were nothing but an array of stimulus frames, perhaps it would make sense for subsequent trials to clean up any stimuli left on the screen by previous trials. However, most trials involve other things, such as measuring a response (that won't likely occur conveniently at a frame boundary), presenting (and erasing) stimuli to indicate whether a response was correct, and pausing for inter-trial intervals.In these cases, there is no benefit to deferring clean up to the next trial.


Given all of the different functions performed by trials, and given the unpredictability of how and whether a subsequent trial will be run, this kind of handshake would have to be quite complicated to generalize properly to all of the various cases, and I wouldn't be surprised to find that there were cases where it had undesirable side effects.


At the same time, the benefits seem to be limited to a very specific scenario. In cases such as this where the programmer has something very specific in mind, it seems preferable to allow the programmer to determine exactly how and whether two trials cooperate.


What kind of task are you programming by the way? There are cases where I've considered allowing certain kinds of relationships between trials to handle tasks that are not currently possible with Inquisit, such as dual-task paradigms and tasks involving multiple responses that may involve different input devices. Possibly it would be useful to be able to explicitly connect the stimulus frames of two different trials if a task required this, although in fact, that's already possible by simply presenting a blank on the subsequent trial.


-Sean

By seandr - 5/11/2010

If I understand your explanation correctly it practically implies that an experiment with k trials will always be k frames longer than what would be expected by simply adding up the stimulusframes definitions.


Sorry, I had meant to reply to this as well. If your trial simply presents and erases stimuli, then yes, the effective length of a trial will be the number of frames + 1. If you set erase=false, then the length should equal the number of frames.


Of course, the length of a given trial may be influenced by many other things, including the response latency, setting the /timeout or /trialduration parameters, and setting /erase=false. If you set /trialduration=2000, for example, the length of the trial is exactly 2000ms regardless of whether or not the stimuli are erased during that trial.


-Sean



By Blackadder - 5/11/2010

Or, to be more precise, no handshake at all but just a speedier switch than currently.


... is what I was suggesting before. My idea to dispense with the 1-frame delay does not introduce the need for any form of cooperation between trials. I can't help but to only find just one single difference between the Inquisit implementation and my suggestion:


In what Inquisit currently does, there is a 1-frame delay (the "rogue" frame) between two trials, provided any stimulus in the trial sported "erase=true". In my suggestion, there is no 1-frame delay because as soon as trial A is done cleaning up, trial B or whatever comes next takes over.


If there is no trial B, or trial B has a pretrialpause, or any other circumstances occur, that's completely fine. The program flow is exactly the same, only that with the Inquisit way, we have a vertical retrace at the end of a trial, whereas with my conception there is none. Maybe I'm just not getting it but I don't understand why any of the objections you made would apply if Inquist would do exactly one thing differently: not wait for a retrace. Can you plot any situation that would turn out differently in case Inquisit wasn't waiting one retrace before anything else happens (i.e., new trial, next block, pause, end of experiment, you name it) but hand control over to whatever happens next as soon as the current trial signals "I'm done."



To me, it was a rather unexpected finding that a property pertaining to a stimulus could alter the length of a trial, and consequently the whole experiment. A stimulus should simply not be capable of messing with the time structure. That said, of course it's possible to mimic the "erase=true" setting by other means like blank occluder shapes and the like, which is what Dave suggested and I was doing all along. But being able to leave all that housecleaning to Inquisit without screen flickering would be quite convenient.



To end this, just a quick answer to Sean's last question. We set up an experiment where most of the screen contents remain constant across the whole experiment, while only a few stimuli are rotated, sized, moved or replaced during trials. Needless to say, regarding the topic of this thread, we cannot have flicker between stimulus alterations. Subjects have to respond to certain changes and are also entitled to trigger specific events. Due to the dynamic nature of the changes we need to enforce a "one trial, one transformation" strategy to allow for realtime subject responses and immediate reactions to these responses. The transformations themselves require a lot of erasing, depending on size and shape of the stimuli. It would have been very helpful if the erase-feature was available but blank occluders will do the trick, too.


Bye, Malte

By Dave - 5/11/2010

We set up an experiment where most of the screen contents remain constant across the whole experiment, while only a few stimuli are rotated, sized, moved or replaced during trials. Needless to say, regarding the topic of this thread, we cannot have flicker between stimulus alterations. Subjects have to respond to certain changes and are also entitled to trigger specific events. Due to the dynamic nature of the changes we need to enforce a "one trial, one transformation" strategy to allow for realtime subject responses and immediate reactions to these responses. The transformations themselves require a lot of erasing, depending on size and shape of the stimuli. It would have been very helpful if the erase-feature was available but blank occluders will do the trick, too.


In such cases, it usually helps to use the '/ erase' settings and your "occluders" smartly / efficiently. As an example, consider the two attached scripts.


~Dave

By Blackadder - 5/11/2010

NIfty scripting!



The "erase" setting is entirely out of the picture in our case since a stimulus will be replaced with another stimulus in any instance, rather than with a blank area. Setting "erase" to true will yield flicker in such cases, hence we must rely on blank shapes.


Bye, Malte.

By Dave - 5/11/2010

Well, then the only practical help I can offer is to assist you in optimizing your script's setup, i.e. finding ways to keep the number of required occluders / blank shapes as low as possible. Let me know and I'll be here to help.


Cheers,


~Dave

By Blackadder - 5/11/2010

Thanks Dave,


the script is already done. I've decided to go with a set of small blank shapes and calculate their positions to occlude an arbitrarily sized area. Works well.


Bye, Malte.