Hello, I’m new to PsychoPy and python!
I have a reaction time task where participants respond to a target as quickly as possible. I need to set the target duration in the second block of trials to the mean RT from the first block, and also vary this duration for each trial within the std RT from the first block of trials.
I’ve calculated the running mean and std RT (from upper mean RT) from block 1 and have set the target duration to this mean RT by entering $meanRT in stop duration in the builder:
I’m stuck on how to make this duration vary trial by trial within the std RT, but am thinking I need to insert a code component before the target? Any help on the code needed for this would be much appreciated.
Thank you very much!
Rachel
Hi @rachel.rodrigues, you could always create a range of values between the lower and upper standard deviations of the mean, shuffle them, and select a value from the shuffled list of durations. E.g.,
rtList = list(range(90, 110, 1)) # Upper and lower values are 90 and 110, in steps of 1 millisecond
shuffle(rtList)
newRT = rtList[0] # Get first value from shuffled list
You could put this in a code component “Begin Routine” tab placed before the target.
Hi @dvbridges, thank you very much for your reply! I have a couple more questions following on from this-
If I calculate the minimum and maximum RT and store these as variables is it possible to input these into rtList = list(range(90, 110, 1)), e.g. rtList = list(range(minRT, maxRT, 1))
I tried this but I get the following error:
rtList = (list(range(minRT, maxRT, 1))
NameError: name ‘minRT1’ is not defined
I also read the range function uses integers, would it still be ok with reaction times?
Thank you
Rachel
Yes, you can. That looks good, except that you have the code that creates the range of RTs in the Begin Experiment
tab. You will need it in the Begin Routine
tab.
Thanks David, I’ve changed it to begin routine and it runs through the first block fine. Then when it gets to the first target in the second block I get this error:
Please could you advise on what this means and what I need to change in the code?
Many thanks
Rachel
Hi @dvbridges, just wanted to update you on progress. Thank you so much for the help!
I’ve been looking more into the error above and think I needed to change minRT1 and maxRT2 from floats to integers, so changed the code to this (which I’m not sure is right):
rtList = list(range(int(minRT1), int(maxRT1), 1))
shuffle(rtList)
newRT1 = rtList[0]
However, now I’m getting this error, which I think means the list is empty?
I’ve looked into this too, but can’t figure out what’s wrong - any help you could give would be very much appreciated.
Thank you
Rachel
This means that rtList
is empty when you try and access the first element of that list. So, we need to know why rtList
is not being filled with RTs between the ranges specified. I think this may happen if your RTs are all < 1 second. Your, int conversion will essentially round down.
Perhaps then we should use something slightly different. Try:
rtList = np.arange(minRT1, maxRT1, .05) # np.arange(start, stop, steps - .05 seconds (50ms) in this case)
shuffle(rtList)
newRT1 = rtList[0]
Hi @dvbridges, this seems to be working fine now! Thank you so much for the help! Rachel
If you are wanting to sample values from a truly gaussian and continuous distribution, rather than a set of discrete values sampled in a rectangular fashion across an interval, numpy
provides a function to allow you to do exactly that:
https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.random.normal.html
e.g.
this_trial_duration = np.random.normal(loc = meanRT, scale = stdRT)
i.e. your durations will cluster about the mean in a gaussian manner, with values further away being rarer. Calculating a range of values as above gives you a discrete rectangular distribution, where the mean is as likely as values at either tail.
But being sampled from a continuous distribution, you should probably then round them to correspond to values consistent with the refresh rate of your system.
Hi @Michael, thank you very much for your feedback! I’ve tried entering $this_trial_duration into the builder but seems I need to extract one value.
Would you please be able to advise how I would then extract one random value from this_trial_duration to use every trial?
Thank you
Rachel
That function will return a single value, unless the parameters you pass it are not themselves single values (e.g. if the meanRT
or stdRT
values are provided as lists or arrays rather than scalars).
So I guess you could just do:
this_trial_duration = np.random.normal(loc = meanRT, scale = stdRT)[0]
to extract a single value but you should probably figure out why it is returning a list or array in the first place.
Hi @Michael, thank you for clarifying! I think I misinterpreted this and it does give one value. I’m getting another issue though, if you or @dvbridges don’t mind giving some advice on it?
I’m getting the following error message for this code:
‘’'import numpy as np
meanRT2 = np.mean(trials_prac_2.data[‘target_prac_2_resp.rt’])
medianRT2 = np.median(trials_prac_2.data[‘target_prac_2_resp.rt’])
RT2 = trials_prac_2.data[‘target_prac_2_resp.rt’]
uppermeanRT2 = RT2 > medianRT2
upperstdRT2 = np.std(uppermeanRT2)’’’
The code is in the correct tab (end routine) and I’ve checked all the names are spelt correctly. Also the exact same code just with different variable names works ok in the previous block, so I’m not sure what’s going wrong in this block?
Thank you so much!
Rachel
Dear @Michael and @dvbridges,
I’ve managed to resolve the above issue by including an if statement (I realised that the mean RT couldn’t be calculated if no key was pressed, which resulted in a crash, so it will only calculate this if a key press is made).
this_trial_duration = np.random.normal(loc = meanRT, scale = upperstdRT)
the above is now working ok for setting the target durations, but sometimes the target doesn’t appear. Could this be because the duration is too quick?
Thank you very much for your help.