thartbm / PyVMEC

A Python-based GUI to create and run visuo-motor experiments.
GNU General Public License v3.0
1 stars 3 forks source link

pseudorandom targets #71

Closed thartbm closed 6 years ago

thartbm commented 6 years ago

Maybe it's unclear what we mean by "pseudorandom" targets. First of all, per block of trials, each target should occur once, which is already not truly random. Shanaa will test this too, but I've noticed oddities as well.

In addition we do want them shuffled per block (which is easy), and we want that shuffling to be reproducible (which may be a source of confusion). This ensures that when we run a participant a second time, they will have the exact same target order, which is still different from every (or most) other participants and should appear random to them. We need this for statistical reasons that I won't go into here.

But here's some simplified code that does what we need:

from random import seed, shuffle

def setParticipantSeed(participant):

    seed(sum([ord(c) for c in participant + 'PyVMEC']))

def shuffleTargets4task(targets, blocks):

    taskTargets = []

    for block in range(blocks):
      shuffle(targets)
      taskTargets = taskTargets + targets

    return(taskTargets)

In setParticipantSeed(), you use the name of the experiment instead of PyVMEC, or nothing at all. That function puts the random number generator in a specific state before generating the target sequence(s) for every participant. However, it will be the exact same state whenever you restart with the same participant.

Then you can use shuffleTargets4task (for every task) to get those target sequences:

In [23]: setParticipantSeed('1')

In [24]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[24]: [90, 45, 135, 135, 45, 90]

Now if I wanted to run the same participant, the random number generator should be seeded the same way:

In [25]: setParticipantSeed('1')

In [26]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[26]: [90, 45, 135, 135, 45, 90]

And I get the same sequence of targets, however, when running another participant, the sequence should be different:

In [27]: setParticipantSeed('13')

In [28]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[28]: [90, 45, 135, 90, 135, 45]

But still the same when I run that participant again:

In [29]: setParticipantSeed('13')

In [30]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[30]: [90, 45, 135, 90, 135, 45]

However, we only set the seed 1 time for every participant, so that subsequent blocks have different target sequences (that should still be the same whenever the participant is ran again):

In [31]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[31]: [90, 45, 135, 90, 135, 45]

In [32]: shuffleTargets4task(targets=[45,90,135],blocks=2)
Out[32]: [45, 90, 135, 135, 90, 45]

As you can see, this approach will generate a unique, apparently random target sequence for every participant, but it will be the same every time we ask for a target sequence for that participant.

So that way, you just generate the whole sequence whenever the experiment is started, and in case of 'continue run' you generate the whole sequence, but skip that part that is already done.

thartbm commented 6 years ago

OK, so it seems that the code that generates the trials is different on first running an experiment and on continuing a run (See issue posted by Shanaa). It should be the same code. On continuing we then skip ahead to whatever part was not completed yet.

shanaam commented 6 years ago

Right. The first time through the experiment, the order of the first 3 targets seems to be generated and then repeated over and over again. However, when Continuing Run, it seems to be randomized. Maybe something is missing when initially running the experiment where it's not reading the generated pseudorandom target order?