How to repeat trial conditionally?

1,169 views
Skip to first unread message

Paweł Strojny

unread,
Aug 9, 2013, 5:56:18 AM8/9/13
to psychop...@googlegroups.com
Hi,

I'm using PsychoPy for few hours but I have to say it seems very good!

I saw some video and written tutorials but don't know how to solve my problem, maybe it is so obvious that nobody needs help (until mine appearance :P).

I,m trying to convert Digit Identification task from Inquisit to PsychoPy. I wrote it in inquisit by my colleagues prefer to have it in PP.

In this task random digit (1-6) is displayed for short period of time and then subject is asked if he/she identified what digit was presented. If yes - subject presses adequate key ('1' for 1 and so on). If subject isn't sure - he/she presses '7' and THE SAME digit is presented again for the same period of time. The digit is repeated until subject type key form 1 to 6. If the key 1-6 is pressed (even if it was wrong), program displays another random digit and procedure starts again.

Thanks to tutorials I know how to display digits, how to record if answer was correct but I can't build in the repeat-on-7 option. Could you help me?

Michael MacAskill

unread,
Aug 9, 2013, 6:19:53 PM8/9/13
to psychop...@googlegroups.com
Hello & welcome. It really helps if you tell us if you are using PsychoPy's Builder or Coder view, as the answers are quite different.

In Coder, this would be straight forward. In Builder, you need to be a bit crafty. I haven't tried this, but one solution might be to wrap your trial in two loops rather than one.

The outer loop is the one you probably already have implemented, designed to repeat for however many trials you will run, and probably pointing to an external .xlsx or .csv file containing your conditions. But you should also have an inner loop, which doesn't point to an external file, but is just set to run practically infinitely (say, for 1000 repetitions).

In the trial, you have a code component that checks the keyboard response at the end of the routine. If it is 1-6, then you terminate the inner loop (i.e. it only runs once). Otherwise, 7 must have been pushed, so the loop runs again, and again, until a 1-6 response is given. I think this double-loop structure would ensure that the same stimulus digit keeps being presented as required, because the outer loop won't advance until the inner loop has terminated.

See the first example on this webpage:
<http://www.psychopy.org/recipes/builderTerminateLoops.html>

Regards,

Michael
> --
> You received this message because you are subscribed to the Google Groups "psychopy-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to psychopy-user...@googlegroups.com.
> To post to this group, send email to psychop...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/psychopy-users/be84c41e-f549-43f2-9cdd-834de9032e06%40googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Paweł Strojny

unread,
Aug 11, 2013, 4:13:38 AM8/11/13
to psychop...@googlegroups.com
Hi Michael,

Thanks for responding, it is very helpful. I'm working in builder so your advice let me to take one step forward.

Actually I've seen the page about terminating loops but didn't figure out that this double-loop structure can help. It seems it is, I applied the code which is terminating the loop after pressing a key (if len(Response.keys)>0:^  trials_repeat.finished=1) but it isn't exactly what I need. My code should refer to particular key (in my case "7"). So what should I change in code if I want to repeat inner loop after pressing "7" and terminate it after first pressing of key "1-6'?

I suppose that it should be something like that: if VALUE(?)(Response.keys)=7:^  trials_repeat.finished=1. Am I correct? ["Response" is the name of keyboard routine, "trials_repeat" is the name of the inner loop.]

Michael MacAskill

unread,
Aug 11, 2013, 4:39:17 AM8/11/13
to psychop...@googlegroups.com
On 11 Aug, 2013, at 10:13, Paweł Strojny <stroj...@gmail.com> wrote:

> I suppose that it should be something like that: if VALUE(?)(Response.keys)=7:^ trials_repeat.finished=1. Am I correct? ["Response" is the name of keyboard routine, "trials_repeat" is the name of the inner loop.]
No, if you look at the logic as described, it is the other way around: the loop terminates if the value is NOT 7.

so the code would be something like:

if Response.keys != ['7']:
trials_repeat.finished = 1

Python syntax:
!= # means "not equal to"
'7' # the keyboard doesn't return the number 7, but the character string '7', as indicated by quotes.
['7'] # the keyboard returns a "list" of values, as indicated by the square brackets, even when only one key was pressed (because it could be set to return many key presses). So we can't just test to see if it is '7', we have to check if it is a list containing just the key '7'.


Regards,

Michael

Paweł Strojny

unread,
Aug 11, 2013, 5:51:24 AM8/11/13
to psychop...@googlegroups.com
The second way works (with '7'), first and third don't. Could you help me undestand why? Anyway - thank you very much Michael!

My script is almost ready now. I need only to figure out how can I terminate outer loop alternatively: when 120 trials occurred (this is easy - nReps in loop menu) OR after 210 seconds (in my case).

Should I add another lines into the same "End Routine"?

Michael MacAskill

unread,
Aug 11, 2013, 8:15:59 AM8/11/13
to psychop...@googlegroups.com

On 11 Aug, 2013, at 11:51, Paweł Strojny <stroj...@gmail.com> wrote:

> My script is almost ready now. I need only to figure out how can I terminate outer loop alternatively: when 120 trials occurred (this is easy - nReps in loop menu) OR after 210 seconds (in my case).

Something like this would tidily close the whole experiment:

if globalClock.getTime() > 120:
core.quit()

Or if you have more to go, you would probably need to explicitly close both loops so that the experiment will progress:

if globalClock.getTime() > 120:
trials_repeat.finished = 1
outer_loop_name.finished = 1

Regards,

Mike

Paweł Strojny

unread,
Aug 13, 2013, 10:19:02 AM8/13/13
to psychop...@googlegroups.com
Great,

I have small issue abut time.

If I use command you've suggested ('if globalClock.getTime() > 120:  trials_repeat.finished = 1') script is metering one global time of experiment - that's why if global clock reached 120 s once all subsequent trials are ended immediately they're started. I'm looking for some command which I can put into End Routine which may reset globalClock - is that a good idea? Or maybe I should use another command refering to some "nonglobal"Clock?

Pawel

Michael MacAskill

unread,
Aug 13, 2013, 10:36:21 AM8/13/13
to psychop...@googlegroups.com
Sorry, I assumed you wanted a global time, but I guess 120 s is actually quite short for that.

There is a value simply called 't', which is the time elapsed within a trial, but it gets reset to zero each time. So we need to manually keep track of that cumulative time across trials.

So in the "begin experiment" box of the code component, put:
cumulativeTime = 0 # initialise a variable to use later.

And amend the "end routine" check to be something like (NB not tested):

if Response.keys != ['7']: # the person pushed 1-6, so go on to the next trial:
trials_repeat.finished = 1
else: # the person pushed '7' so we will continue repeating, but check the time first:
cumulativeTime = cumulativeTime + t
if cumulativeTime >= 120: # the person pushed '7' but we should exit anyway:
trials_repeat.finished = 1

Regards,

Michael

On 13 Aug, 2013, at 16:19, Paweł Strojny <stroj...@gmail.com> wrote:

> Great,
>
> I have small issue abut time.
>
> If I use command you've suggested ('if globalClock.getTime() > 120: trials_repeat.finished = 1') script is metering one global time of experiment - that's why if global clock reached 120 s once all subsequent trials are ended immediately they're started. I'm looking for some command which I can put into End Routine which may reset globalClock - is that a good idea? Or maybe I should use another command refering to some "nonglobal"Clock?
>
> Pawel

--
Michael R. MacAskill, PhD 66 Stewart St
Research Director, Christchurch 8011
New Zealand Brain Research Institute NEW ZEALAND

Research Fellow, michael....@nzbri.org
Te Whare Wānanga o Otāgo, Otautahi Ph: +64 3 3786 072
University of Otago, Christchurch http://www.nzbri.org/macaskill



Paweł Strojny

unread,
Aug 13, 2013, 11:28:02 AM8/13/13
to psychop...@googlegroups.com
Thanks,

Because of my experiment's structure it seems that I need sth analogous to "t" but reseting after each loop. Maybe I'm wrong but:

I have double loop structure. On the first level routine "random" which is ramdomising digit + routine "trial" which is displaying random digit, collecting response and so on. On the secon level I have loop "trials" which is repeating both routines. On the secon level routine "EndOfBlock" is added which is displaying information that block is eneded and new (with shorter disptimes) is going to start + loop "blocks" which is repeating whole (but with different display times). I'm not sure if I wrote it clearly, I attach file just in case.

So if I need to count time for every block and end block if time is reached I need to count time on "second" level. Am I correct?

best,

Pawel
DIT.rar
Reply all
Reply to author
Forward
0 new messages