PennController for IBEX › Forums › Support › Randomization of Stimuli Across Blocks
- This topic has 6 replies, 2 voices, and was last updated 4 years, 5 months ago by AndreasK.
-
AuthorPosts
-
June 24, 2020 at 8:56 am #5705AndreasKParticipant
Hi Jeremy,
First of all, thank you very much for all the helpful answers on the support page. They’ve helped me a lot so far but I haven’t been able to figure out a solution for my current problem.
I’m planning a recall task with two blocks. During the first block, participants will hear the stimuli in a familiar accent and during the second block, they will hear it in an unfamiliar accent. In total, there are 24 stimuli, which I have saved in a table.
What I would like to achieve is that 12 stimuli are randomly selected for the first block. The second block should then include the remaining 12 stimuli. I would like this choice to be randomized for each participant, such that participants A and B will hear different stimuli in the first (and second) block.
I thought I could use two tables and Templates, one for each block. However, I can only randomize the order within each block in this way. Participants A and B would still hear the same stimuli in each block, just in a different order. Is there a way to randomize it differently to get the desired outcome?
I also thought that I could simply produce different lists for each participant individually but this seems like a lot of manual effort so I was wondering if there is a way of doing it more easily with pcIBEX.
Apologies if this query has already been answered elsewhere.
Andreas
June 24, 2020 at 10:44 am #5706JeremyKeymasterHi Andreas,
Here’s an example of what you can do. I use left-right vs right-left spelling to represent your design’s different accents, but in your case you probably want to point to different audio files. I’m also defining only 4 items, but set NITEMS to 24 if this is how many items you have (make sure you have 24 corresponding rows in your table—25 including the header)
AddTable("myTable", `leftRight,rightLeft hello,olleh world,dlrow bye,eyb mate,etam`) NITEMS = 4 order = [...new Array(NITEMS)].map((v,i)=>i<NITEMS/2).sort(v=>Math.random()>=0.5) Sequence( randomize("leftRight") , randomize("rightLeft") ) Template( "myTable" , row => newTrial( (order[0]?"leftRight":"rightLeft") , newText( (order.shift()?row.leftRight:row.rightLeft) ).print() , newButton("Next").print().wait() ) )
Let me know if you have any questions
Jeremy
June 25, 2020 at 11:11 am #5720AndreasKParticipantHi Jeremy,
Thanks a lot for your response.
This code is really helpful but, if I understand it correctly, it always chooses ‘hello’ and ‘world’ for the first two trials (i.e. first block) and then ‘eyb’ and ‘etam’ for the third and fourth trial (i.e. second block). The order of the trials within each block varies from participant to participant, which is what I want.
However, I would also like to vary the words in the first block across participants. For example, Participant A sees ‘hello’ and ‘world’ in the first block (and ‘eyb’ and ‘etam’ in the second block). Participant B sees ‘hello’ and ‘mate’ in the first block. Participant C sees ‘world’ and ‘bye’ in the first block, etc.
Could you help with that?
I was also wondering what the order array does exactly. I started my PhD just a year ago and I am not very familiar with coding but trying my best to learn it at the moment. I tried to look up the individual elements: From what I found, the first part creates an array with four undefined slots. These are then mapped with the .map function and sorted with the .sort function. What I can’t follow are the lambda (?) functions inside .map and .sort. From playing with the code, the .map and .sort functions seem to make sure that not only rightLeft words are displayed but I can’t work out why that is.
I appreciate if you can’t explain this in detail. Can you recommend any books or websites that I could have a look at to learn this type of coding?
June 25, 2020 at 11:41 am #5721JeremyKeymasterHi Andreas,
it always chooses ‘hello’ and ‘world’ for the first two trials (i.e. first block) and then ‘eyb’ and ‘etam’ for the third and fourth trial (i.e. second block)
You’re probably using Chrome (which is fine) just replace
order = [...new Array(NITEMS)].map((v,i)=>i<NITEMS/2).sort(v=>Math.random()>=0.5)
with
order = [...new Array(NITEMS)].map((v,i)=>i<NITEMS/2).sort(v=>1-2*(Math.random()>=0.5))
I was also wondering what the order array does exactly.
You got it right for the most part:
- [...new Array(NITEMS)] indeed creates one array of NITEMS slots with the value undefined
- map((v,i)=>i<NITEMS/2) loops through every slot, fills the v variable with its value (in this case, always undefined) and i with its index (from 0 to NITEMS-1) and replaces the value in the slot with i<NITEMS/2, which is true for the slots whose index is in the first half and false for the other half of the slots
- sort(v=>1-2*(Math.random()>=0.5)) loops through every slot of the array returned from map (half true, half false) and depending on the value returned by the lambda function, it moves it forward (value > 0) or backward (value < 0) in the array. In this case, the value is a random number between 1 and -1 for each slot, so you end up with an array with half its slots true and half of them false in a totally random order
The Template function will then look up the first value of the order array for each trial it generates, and remove it from the array at the same time (that’s the shift() method) so that the next generated trial will look up the next “first” value from order. Then, because of how we defined of order, half your trials will be generated from a true value (-> "leftRight") and the other half will be generated from a false value, in a random (ie. non linear) order.
Not sure where to start with javascript, I never really followed a single method and the language is now more of a family of languages with many different uses. Ideally PennController lets you abstract away from javascript, but there are some cases (like this one) where it lacks some functionality that can only be implemented using some javascript
Let me know whether changing the random bit fixed the issue
Jeremy
June 26, 2020 at 10:21 am #5723AndreasKParticipantHi Jeremy,
Yes, it works fine now. Will it work with this code in other browsers as well or do I need to change the code according to which browser my participants use?
Thanks a lot for explaining the code in detail. That was very helpful for me and I understand the syntax much better now.
I’d have one more question. Is it possible to add another variable here. For example, both the familiar and the unfamiliar accent will be presented in two voices. I’ve created a table below following your example with leftRight and RightLeft:
AddTable("myTable",leftRight_1,leftRight_2,rightLeft_1,rightLeft_2 hello_1,hello_2,olleh_1,olleh_2 world_1,world_2,dlrow_1,dlrow_2 bye_1,bye_2,eyb_1,eyb_2 mate_1,mate_2,etam_1,etam_2)
The numbers following the words indicate the voices (two for familiar/leftRight and two for unfamiliar/RightLeft). Ideally, the randomization would be such that participant A e.g. hears ‘bye_1’, ‘world_2’, ‘etam_1’, ‘olleh_2’. Participant B hears e.g. ‘mate_1’, ‘hello_2’, ‘dlrow_1’ and ‘eyb_2’. Basically, I would like the same randomization as above but now also including the factor ‘voice’. Is there a way of achieving this?
I’ve tried to edit the code myself but I only achieved partly what I wanted and I had to use two tables. However, this makes a random choice of sentences impossible as I would have to decide which words will be leftRight or rightLeft by allocating them to the corresponding table.
Andreas
June 26, 2020 at 2:09 pm #5726JeremyKeymasterHi Andreas,
Yes, the code should work across browsers (or at least, you won’t have to use a different code for Firefox vs Chrome)
The new design you are describing has 4 conditions instead of 2, so you will need to adapt the code I gave you accordingly. So I worked on a slightly more general version of the code:
AddTable("myTable", `leftRight_familiar,rightLeft_familiar,leftRight_unfamiliar,rightLeft_unfamiliar hello_familiar,olleh_familiar,hello_unfamiliar,olleh_unfamiliar world_familiar,dlrow_familiar,world_unfamiliar,dlrow_unfamiliar bye_familiar,eyb_familiar,bye_unfamiliar,eyb_unfamiliar mate_familiar,etam_familiar,mate_unfamiliar,etam_unfamiliar`) NITEMS = 4 CONDITIONS = ['leftRight_familiar','rightLeft_familiar','leftRight_unfamiliar','rightLeft_unfamiliar'] order = [...new Array(NITEMS)].map((v,i)=>i%CONDITIONS.length).sort(v=>Math.random()>=0.5) Sequence( randomize("leftRight_familiar"), randomize("rightLeft_familiar"), randomize("leftRight_unfamiliar"), randomize("rightLeft_unfamiliar"), ) Template( "myTable" , row => newTrial( CONDITIONS[order[0]] , newText( row[CONDITIONS[order.shift()]] ).print() , newButton("Next").print().wait() ) )
Now if you update your design to use more or less conditions, you only have to change the content of Sequence and the value of CONDITIONS (and NITEMS if you have a different number of items). Notice that I took the liberty to replace 1 and 2 with familiar and unfamiliar for more transparency.
Let me know if you have any questions
Jeremy
June 28, 2020 at 4:50 pm #5733AndreasKParticipantHi Jeremy,
The code works perfectly. Thank you very much. I’ve tried it with different numbers of conditions and it works without any problems. I’ve also inserted the
.sort(v=>1-2*(Math.random()>=0.5))
from above to make it work in Chrome.Thanks again for all your help. This is fantastic.
Andreas
-
AuthorPosts
- You must be logged in to reply to this topic.