 Welcome to another tutorial on Open Sesame. In this tutorial, we're going to take a look at how we can implement counterbalancing inside of our experiments. We're going to look at two particular examples, one in which we'll have two conditions that we want to counterbalance across participants, and a second example, which will be a little bit more complex, where we'll have a look at how we can counterbalance across three or more conditions. So let's have a look at how we can implement a simple counterbalancing system inside of Open Sesame. Let's say that we want half our participants to receive the order block 1 followed by block 2, and the other half participants receive the order block 2 followed by block 1. A simple way of doing this is actually we can look at the subject number and see whether it's odd or whether it's even. If it's an odd number, we'll give them the order block 1 followed by block 2, and if it's an even number, we'll give them block 2 followed by block 1, ensuring that half our participants have one order and the other half have the other. To demonstrate this, I've got a simple experiment loaded up already. This experiment will display some instructions on the screen to the participant. It'll sit and wait for a space bar to be pressed before starting. We then have block number 1, which just contains one particular trial, I can show you, it's got one variable MSG, and this one trial just puts the message block 1 onto the screen. We then have some second block instructions, so we'd normally say that's the end of block 1, get ready for block 2, wait for the space bar to be pressed, and then we'll start block 2, and block 2 also has just one variable in it, MSG, with the message block 2. Then we have a goodbye message, say thanks to the participant, wait for a space bar, and then quit. So if I run this experiment right now, so I run it in a window with subject number 1. So here we have it with the instructions that go in there, we have block 1, instructions for the second block, and then we have block 2, and then the goodbye message, and that's the experiment. That's exactly the order we would want for odd number participants, but not for the even number participants. Now a very crude way of sorting this out is that we could actually create a second version of the script, and literally just move around the order of these two blocks. So we could put block 1 up here, and we could put block 1 down here, and that would create the opposite order for us, put it in the right place, it's better. It would create the opposite order for us, but then we'd have to remember to open up each particular script, and make sure that we have the right script for the right participant, and so on. You can get a little bit out of hand that, and it's much more simple to let open sesame take care of this for us. We can actually make use of a variable that's built inside of open sesame called subject parity. So I've got the show variable inspector window, and you can see it down here, subject parity. It takes two values, odd if the participant number is odd, and even if it's an even number participant. We can actually use this as one of the conditions for running a particular block. So if we have a look in the main experiment sequence at the moment, let's put these back in the right order. At the moment, we always run every single object inside of the experiment. So we always run the instructions, we always run the space response, then we always run block one, second block instructions, and so on. What we can actually do is specify that we only want certain blocks to run depending upon a certain condition, i.e. that that condition has been met. And what we can basically do is tell open sesame only run a block if the subject parity is even, or if the subject parity is odd. So what we can do is if we add in a second copy of block one and a second copy of block two, they appear down here at the bottom, I'll put them together in two pairs. Now the experiment is ordered instructions followed by block one and block two, then the second block instructions followed by block one and block two, which essentially just give us the same order done over twice. We can specify certain conditions about where we want to run that particular block. What we can say here is run this block one here if the subject parity is odd, i.e. it's an odd numbered participant, and run this block two here only if the subject parity was even. So it's an even number participant. We can flip that over in the second pairing and say run this block one here only if the participant parity was even and then run this block two here if the subject parity was odd. The way we do that is we put that into the condition box over here. Remember subject parity is a variable so we need to specify it inside of the square brackets. So I'm just type in subject parity equals odd and then for the next one I can type in subject parity equals even. So first time up here it's gonna if you've got an odd numbered participant it's going to run block one and ignore block two. So if I come down here and just flip those two over so that for even numbered participants they get block two followed by block one. So I then need to say subject parity equals even and then for the second copy of block two I need to say subject parity equals odd. So just walk our way through this. If we've got an odd numbered participant we'll have some instructions on the screen. We'll come down to block one because we've got an odd numbered participant it will run block one. However it won't run block two because it will only run that if we've got an even numbered participant so this is going to be skipped. We'll get the second block instructions then we'll get block one won't be run because we've got an odd numbered participant but block two will be run because the subject parity is odd. If you imagine now we've got participant number two we'd have instructions followed by block one being ignored because we've got an even numbered participant and this is only going to be run if the subject parity is odd. However block two will be run because the subject parity is even. So let's do a quick demonstration of that. I'll say subject number one so this should give us the order block one followed by block two and we get block one instructions second block block two goodbye. I'll try running it now with subject number two which should give us the opposite order of the blocks and so there's the instructions we now get block two first there's the instructions second block and now we get block one followed by the goodbye message. So that gives us a nice simple way of implementing a simple counterbalancing system inside of open sesame. Sometimes we want to implement a more complex counterbalancing system. Let's say for example if we have three blocks that we want to counterbalance across participants maybe perhaps using a reduced Latin square design. That would be that participant number one gets the block order one two three. Participant number two will get the order two three one and participant number three we get the block order three one two. For participant number four the sequence would reset so they get the sequence one two three. Now because we've got more than two blocks here we can't use the subject parity variable to help us out. After all subject parity could only contain two values odd or even. That was fine if we've only got two block orders but now we have three block orders to worry about so we have to use something slightly different to determine what that block order is going to be. To determine that block order we'll actually use a bit of arithmetic namely the modulo function. I'll do a demonstration of this using the debug window because that lets me type some Python code in directly. Modular arithmetic basically is you can think of it like the remainder from a division. So if we have say three modulo three it's like saying three divided by three is zero so one remained a zero. If we had one divided by three it would be zero remained a one. In this particular case the result of one modulo three would be that remainder value the one. In the case of two two divided by three or two modulo three it would be two as the remainder and that's what we return to us. If we use four for example four divided by three would be one remained a one so the modulo function would give us the return of one there for the remainder. As you can see we actually end up with three numbers that basically come out of this modulo division. We either get zero when it's a multiple of three we get one in the case of one modulo three or we get two in the case of two modulo three and we can use these three values to determine which block order we want to give the participant. Now in Python the modulo function is defined by the percentage symbol so do the demonstration down here of one modulo three gives us the answer one because that's one modulo three is well it's like the one divided by three which would be zero remainder one. We can use two modulo three gives the result two and three modulo three gives us zero. If I put four in we're back at one again so we've got this sort of cycle we've got here going one two zero one two zero one two zero for all the possible participant numbers that we've got and we can actually exploit this to determine what our block order is going to be in our experiment. So let's have a look at how we can actually implement this inside of open sesame. Let's get rid of the debug window. I don't need that. I've got a simple experiment opened up already which contains this first thing in here is a inline script object which I'll open up. It contains this bit of Python code in here. It takes the form of an if else if else statement and basically what we're doing here is looking for these certain conditions to be met. So we're saying if self get subject number modulo three equals one then if it does indeed equal one B1 should be set to zero B2 should be set to one and B3 should be set to two. We'll talk a little bit about this B1 B2 and B3 in a moment. First of all let's just focus on this bit up here see what that actually means. Subject number is a variable just like things like subject parity was in the simple example but in the actual inline script object we can't just stick subject number inside of those square brackets. Instead what we have to do is use this bit of code here this function that basically means this experiment then go and get the variable called subject number. That return the number of the subject number we then perform the modular arithmetic on it and we'll see what the outcome is and does it equal one. If it does equal one then we set the values as we set up here. However if it does not equal one let's say for example the subject number was two two modulo three as we saw earlier on is actually two we'll actually come down to this next statement which is else if doing the same bit of arithmetic here except this time does it equal two in the case of subject number two yes it will do so B1 will equal two B2 equal zero and B3 will equal one. There's only one other option so I haven't put an else if in I've said else if these two conditions so this condition here and this condition here are not true i.e. the result out the modular division is not one or two then just set B1 to one B2 to two and B3 to zero. This will happen in cases where the subject numbers are multiple of three. So let's have a look at what this B1 B2 and B3 actually mean. You might have guessed they stand for block one block two and block three. The zero one two in that these values have been set to actually indicates which order we're running the block or more precisely which block is run first. In all three cases which ever get set the value of zero will be the first block run so in the case of a subject number one or four or seven and so on the first block to be run will be B1. The subject number two the first block that will be run is B2 and for subject number three the first block that be run will be block three. Then the one indicates the second block so and then the two indicates the third block that's going to be run. The reason we use zero one two here by the way and not one two three will become a bit clearer a little later on. Then we also have to set these values to be experiment wide because otherwise we'd only have access to these in inline scripts and actually what we want to do is access these particular values this B1 B2 and B3 from outside of an inline script. The reason for doing this means that we only need to have one inline script in order to do this counterbalancing. So to make them across the experiment available across the experiment we have to say experiment or exp set the variable B1 to the value B1 that we've defined up here and the value B2 to B2 and the value B3 to B3. So let's make sure that these values are available experiment-wide. So just to briefly recap this particular screen if we run this script and the subject number is number one the very very first condition up here will be satisfied so subject number modulo three it will indeed equal one so we'll set B1 to 0 B2 to 1 and B3 to 2. However if we have the subject number 2 it won't be the first condition that satisfied it will actually be the second condition so that be subject number i.e. 2 modulo 3 will indeed equal 2 in which case we'll set B1 to 2 B2 to 0 and B3 to 1 and in all other cases basically where the subject number modulo 3 is actually equal 0 then B1 will be set to 1, B2 will be set to 2 and B3 will be set to 0 and then finally we just make sure that these variables are available across the entire experiment. So let's take a look at what the rest of this experiment is going to be doing. After we've determined what the block order is going to be for our participants we have some instructions that will be displayed upon the screen to the participant and then we'll sit there and wait for them to press the space bar to actually get started. We then have this loop object called main loop. It doesn't seem to contain very much. All it really is is just three cycles with no variables set in it. The reason it's being set up this way is what we want to happen is to run through three particular blocks of the experiment. Doesn't matter which order we're going in at the moment we just have three blocks that we want to run so you can consider main loop to be sort of the control block the ones who control these three particular cycles of the experiment. By setting the block up this way it's going to run this sequence called main sequence three times. I click on main sequence now and you can see we've got three blocks inside of the experiment block one, block two and block three. These are set up just to display a simple message on the screen so we have this one variable called MSG which is block one for block one. It says block two for block two block three it says block three. All three blocks run the same trial sequence which displays this text render display on the screen that says this is MSG in which case that would say this is block one, block two or block three. Towards the end of the experiment we have a goodbye message and after we've presented that goodbye message we want the computer to wait for the space bar to be pressed before we actually finish. Before explaining how we actually implement the counterbalancing to make this nice and clear let's just have a look at what happens if we run this study right now. We have main loop which contains three cycles so it's going to call main sequence three times. Main sequence contains three blocks block one, block two, block three each of which are going to display a message on the screen that says this is block one, this is block two and this is block three respectively. So what we should see is some instructions come up on the screen followed by the message this is block one, this is block two, this is block three as it runs through main sequence for the first time. Then because we're running through main loop three times we'll actually get this is block one, this is block two, this is block three for a second time and then we'll get it a third time because we're running through this loop three times so it'll be this is block one, this is block two, this is block three the third time. So what we're going to see is basically messages for nine blocks will appear on the screen. Then we get our goodbye message and we'll sit and wait for the spacebar to be pressed. So I'll quickly just run this right now just to demonstrate what we actually get. So there's our instructions. So this is this block one, the first time around with being through that main loop, block two, block three. Then we get block one again, followed by block two, followed by block three. And thirdly, block one, block two, and block three, followed by the goodbye message. The next thing we need to do though is to prevent block one, block two, and block three always running on every particular sequence. What we basically want to do is change the values on the right hand side that say run if, what they're currently set to always, which is the default. We want to put some condition in there that says only run block one if certain conditions are met, only run block two if certain conditions are met, and only run block three if certain conditions are met. This is the reason now coming back to what we talked about at the beginning about why we use the values zero, one, and two for setting our block order. The reason is this particular sequence called main sequence. Every time it's run, there is a variable that's called count main sequence. I'll show you that in the variable inspector. Space for it. So it's over here. Count main sequence. This value will increment every time main sequence is run. Now the thing is that the very first time it runs main sequence, count main sequence will have the value zero. The second time we run it will have the value one, and the third time we run it will have the value two. This is the reason we use these numbers zero, one, two, and not the numbers one, two, and three. So what we want to basically say to open Sesame is that if count main sequence is zero, we need to look at what particular block order we've got and then run that block if indeed we should be running it for that particular counter balancing sequence. Now we don't actually have to use any more inline code here. We can't actually use this run if condition box here and actually put some Python code in directly. If you're going to put Python code in directly, you need to remember to put the equal sign at the start of the condition. I've actually got the condition we're gonna put in in a separate text file, so it's easier to play on the screen. We have the equals sign, and why about one up here at the moment because this is the one we're gonna use for block one. Equals sign, so it indicates to open Sesame where you're gonna use some Python code in here. We're then gonna get the value of B1 that we set earlier on, and we're gonna see if that's equal to the value of count main sequence. It's probably easier to explain this one with a concrete example. If we go back to the determining block loop and block order, and we consider the case where we've got the subject number one, B1 is gonna be set to zero. This means, if we go back to our inline script that we're gonna have, whenever B1 has been set to zero and counts main sequence is also zero, then we want to run that particular block. In the case of B2, for example, on the first time round, we went through the sequence and count main sequence is set to zero. Well, B2 is actually set to one, so this condition will not be met. And likewise, this one here for block three, count main sequence when that is zero is actually set to two for this participant here, so it won't be run on that particular loop through the main sequence. However, on the second time through, we go through the sequence, count main sequence will meditate the value one. That will basically mean then that the self get B1, which are gonna evaluate to zero, and self get count main sequence, which will evaluate to one will no longer be true. So block one won't run. However, if we look at self get B2, B2 has been set to one, and our count main sequence on the second time through is indeed gonna be the value one. So this condition here will be satisfied and this block will run. And then look at the third example here, self get B3, which has been set to two, does it equal the count main sequence, which on the second time through is one. The answer is no, so this block here will not be run. Then the final time we run through, we'll be getting the value of B1, which would be zero again, but this time count main sequence will be two. It's always incrementing every time we go through the sequence. B2, which is set to one, will not equal to either. However, B3, which has been set to two will equal the count of the main sequence, so that block will be run. The result of this is that every time we go through that main sequence, only one of the blocks is going to be run and the other two are not. They're gonna be skipped over because the value that we've set in here does not equal the main sequence. So just to clarify, the reason we use these naught, one, and two is we're actually referring to this value here for count main sequence. That's why we're using those and not one, two, or three. So I'll just copy and paste these into the main sequence. Variable inspector. Paste that in, get the next one, get the last one, and paste that in. So these blocks are only gonna run if these conditions have actually been satisfied, i.e. the result of this particular comparison is true. So in the first time round we run for participant number one, block one, which is being set to B1, it's being set to zero, will indeed equal the main sequence count because the first time round is zero, but it won't satisfy block two because B2 has been set to one, which is not the same value as zero, which is the count main sequence. The same thing goes for block three. So the first time we run through, only that one block is gonna be run, block one. Second time we run through when count main sequence has changed, it's now the value of one, that's gonna equal the value of B2. So block two were run and the other two won't. And then finally, the third time we run through B3, which was set to the value two, will then equal the count main sequence, which was also now set to two on the third time through the loop. So let's just try running this and see what happens. So here's the subject number one. So this should give us the instructions followed by this is block one, this is block two, this is block three, we then should have the goodbye message. So let's see what we get. There's the instructions. This is block one, this is block two, this is block three, and then the goodbye message. Let's try it if we run participant number two. Remember participant number two should have the sequence two, three, and then block one to finish off. So we get that, so there's instructions, and then they get this is block two, this is block three, and this is block one, followed by the goodbye message. And to finish it off, we'll run it with participant number three, and they should get the order three, one, and two, and three, one, and then block two to finish off with the goodbye message. Let's see. No. So that's how we can implement some more complex counterbalancing inside of Open Sesame using minimal amounts of inline Python code. It may seem a little complicated to get your head around it the first time you start looking at it, but essentially what we're just doing here is using some of the inbuilt variables that are inside of Open Sesame. In this particular example, it is this count main sequence that we're actually exploiting to see which cycle through the sequence are we and which blocks should be running on that particular sequence, and that particular value is determined in the inline script depending upon the subject number. So hopefully that gets you started on thinking about how you use these more complicated examples inside of your experiments.