Catch trials or partially fixed stimulus ordering with make_random_timing.py

Hello AFNI experts -

I am developing a rapid event event related design with jittered ITI and random stimulus presentation. The experiment is as follows:

Cue(variable time) - task stimulus (fixed time) - ITI (variable time). There are 2 cue conditions (C1, C2) and 2 task conditions (T1, T2). T1 always follows C1 and T2 always follows C2. There will also be catch trials of C1 and C2. Random stimulus presentation may therefore look like the following:

C1T1… C2T2…C1T1…C2…C2T2…C2…C1…C1T2

Based on the examples listed here I believe the “Catch Trial” example is most appropriate. I’ve included my code below.

I am having a few issues:

  1. First, is my interpretation of this example appropriate for the task I’ve described?
  2. I need my stimuli to be TR locked and I must have a minimum TR of 2.5s. Ideally this would be facilitated through a combination of jittered cue and jittered ITI, with fixed task. For example…
    Full trial: 1.25 cue + 1.5 task + 2.25 ITI = 5 s
    Full trial: 1.75 cue + 1.5 task + 1.75 ITI = 7.5 s
    Catch trial: 1.75 cue + 3.25 ITI = 5 s
    However, I’ve been unable to incorporate this type of variable jitter into a stimulus, and so the math never quite works out to allow me to have appropriate timing for both my catch trials+rest and my full trials+rest while fitting within the bounds of a multiple of my 2.5s TR. Are there any suggestions for workarounds?

Thank you for your assistance,
Kathryn

#!/bin/tcsh

try to find reasonable random event related timing given the experimental

parameters

---------------------------------------------------------------------------

#num_stims: 4 (C1, C2, T1, T2)
#stim_dur: C1: 1.25 C2: 1.25 / T1: 1.25 T2: 1.25 (for initial analysis T1, T2 = 1.252 = 2500)
#run_time: [(1.25
9 + 1.259 + 2.516 + 2.5*16 + (9+9+16+16)*2.5)] * 2 = 705
#tr_locked: TR = 2.5

---------------------------------------------------------------------------

---------------------------------------------------------------------------

#generate stimulus timing for 4 classes

---------------------------------------------------------------------------

make_random_timing.py -num_stim 4 -num_runs 4 -run_time 705
-stim_dur 1.25 1.25 2.5 2.5 -num_reps 9 9 16 16
-stim_labels C1 C2 T1 T2 -min_rest 2.5 -tr_locked -tr 2.5 -seed 54321
-prefix stimesG

---------------------------------------------------------------------------

#separate ‘catch’ trials from the main events and sort

---------------------------------------------------------------------------

1dcat stimesG_C1.1D stimesG_T1.1D > stimesG_C1T1_all.1D
1dcat stimesG_C2.1D stimesG_T2.1D > stimesG_C2T2_all.1D

timing_tool.py -timing stimesG_C1T1_all.1D -sort
-write_timing stimesG_C1T1_sorted.1D
timing_tool.py -timing stimesG_C2T2_all.1D -sort
-write_timing stimesG_C2T2_sorted.1D

---------------------------------------------------------------------------

#get stim times for ‘main’ regressors by adding 1.25 seconds to every time
#run make_random_timing.py again, adding an offset of 1.25 seconds to all times
#save 3dDeconvolve command to run with -nodata

---------------------------------------------------------------------------

make_random_timing.py -num_stim 4 -num_runs 4 -run_time 705
-stim_dur 1.25 1.25 2.5 2.5 -num_reps 9 9 16 16
-stim_labels C1 C2 T1 T2 -min_rest 2500 -tr_locked -tr 2.5 -seed 54321
-offset 1.25 - save_3dd_cmd @cmd.3dd.G -prefix stimesG

---------------------------------------------------------------------------

#Fix the 3dDeconvolve command in @cmd.3dd.G
#Use timing files for stimesG_C1T1_sorted.1D and stimesG_C2T2_sorted.1D

---------------------------------------------------------------------------

Hi Kathryn,

The catch trial method seems reasonable. I could actually implement that locally if I added an option to combine classes together. Maybe that can go on the “todo” list.

I was not aware of that package you are linking the program under. Note that the version you link to is 4 years old. Our current version has many new features. See make_random_timing.py -help .

In any case, your interpretation seems good. The catch trials are designed as separate classes, which can be combined later.

So the full trials need to be TR-locked for some reason? That is actually harder to do, as you are seeing. The effect is just the Cue events start on the TR, but not task events.
Is this interpretation accurate?
To be sure, why this is necessary?

How long can a full trial be? That ITI comes in multiples of 2.5 puts big jumps in the event times that is a little odd. Were you planning to impose a full trial length limit of 10 s, for example?

Is the a minimum Cue or ITI duration? I guess min(Cue+ITI) = 1 s. Should they both have a minimum of 0.5 s, or maybe min(ITI)=1 s?

In your script example, the Cue events are always 1.25 s, so the Task events start in the middle of a TR. Also, it then seems odd that Cue+Task = 2.75 s = 0.25 s longer than a TR, when you want the overall timing TR-locked. Is that what you want? I just want to be sure.

So basically these Cue/Task/ITI events would have to be treated as single events, and then the interior Task phases would have to be randomized within. This is scriptable, but might be a touch messy. If Cue and Task are really fixed durations, then this might be doable differently.

Anyway, maybe it would be good to let you respond to my questions before going into the weeds with details.

Thanks,

  • rick

Hi Rick,

Thanks for your thoughtful response and for making me aware of the newer advanced options, which have been a wonderful improvement over the older version that I was trying to implement. I’m just having one issue, which is related to TR-locking. Unfortunately this is necessary at this time. I am collecting concurrent eye movement data and my stimulus display program must initiate trials based on a TTL pulse from the scanner. Currently, our scanner only sends TTL pulses at each TR (we are working on changing this but it’s been a process and I need to collect pilot data ASAP).

However, I’ve made some changes in line with your suggestions. For now, I’ve reduced my TR to 1s so that my stimuli can easily be in multiples of the TR. With the new options, I’ve been able to assign unique stimulus timing to my trial types (R1, N1 = 3s, R2,N2 = 4s) and my catch trials (CatchR1,N1 = 1s, CatchR2,N2 = 2s). It seems as though I should easily be able to then set my rest periods to be TR_locked, with the major caveat that this is not ideal timing. However, I’ve been unsuccessful in getting my rest periods to actually reflect this - they’re always set to non-TR-locked values when I view the output.

I currently have my run time set to 2.5*total task time to allow for a significant amount of rest and am allowing for any extra post-stimulus time to be allocated to rest, but otherwise I have no justification for this specific length. My minimum rest is set at 1 with mean and max not specified (previously I had been getting warnings that these were set too low when I tried to give pre-specified values). I’ve also tried setting rest using t_gran instead of TR although my understanding is that t_gran is obsolete when TR is specified as this value is used to determine t_gran.

Do you have any suggestions for what I may be doing wrong? I did read that many of the older options are incompatible with the advanced options, but from the help document it seemed as though this should be possible.

make_random_timing.py -num_runs 4 -run_time 390        \
   -pre_stim_rest 10 -post_stim_rest 10                 \
   -rand_post_stim_rest yes                              \
   -add_timing_class stima 3                           \
   -add_timing_class stimb 4                           \
   -add_timing_class stimc 1                           \
   -add_timing_class stimd 2                           \
   -add_timing_class rest 1 -1 -1 -tr 1 -tr_locked      \
   -add_stim_class R_1 8 stima rest                \
   -add_stim_class N_1 8 stima rest                \
   -add_stim_class R_2 8 stimb rest                \
   -add_stim_class N_2 8 stimb rest                \
   -add_stim_class Catch_R_1 4 stimc rest                \
   -add_stim_class Catch_N_1 4 stimc rest                \
   -add_stim_class Catch_R_2 4 stimd rest                \
   -add_stim_class Catch_N_2 4 stimd rest                \
   -write_event_list events.RANTI             \
   -show_timing_stats                                   \
   -save_3dd_cmd cmd.3dd.RANTI.txt                        \
   -make_3dd_contrasts                                  \
   -seed 31415 -prefix stimes.RANTI

Hi Rick,

Good news! This issue has been solved. Thanks again for your help.

-Kathryn

That’s great to see, Kathryn!

We have been pretty out of the loop for the past couple of weeks…

Thanks for the update,

  • rick