base timing of a trial on total time taken in previous trials--mismatch error?

David McFarlane mcfarla9 at msu.edu
Fri Jul 1 20:11:20 UTC 2011


The original poster figured out a solution using 
an array, as posted on the PST Forum 
(http://www.pstnet.com/forum/Topic5419-7-1.aspx 
).  Since I already figured out an alternative 
solution without using an array, I am posting it 
here just to show that I could do it.

First, I will restate the specifications:

(1) A block of trials will last for either some 
specified time (e.g., 10 min) or for 12 trials, whichever comes first.

(2) The stimulus on each trial will last for 
either some specified time (2 min), or for the 
remainder of the block duration, or until the 
subject responds, whichever comes 
first.  Unpacking this, in effect it means that 
all trials except the final one last for the 
usual trial duration or until a response 
(whichever comes first), and the final trial 
lasts for the remainder of the block duration or 
until a response (whichever comes first).

I already know some functions for working 
directly with the clock times of events, so for 
this problem I find it handier to think in terms 
of the clock times for when the blocks and trials 
will end, instead of the remaining block 
duration.  So here is my solution (following good 
programming practices, such as using constants in place of "magic numbers").

I would first define a global variable on the 
User tab of the Script window.  This will hold 
the clock time of when the block must end.  (I 
like to use a "g_" prefix to remind me that it's 
a global and not a local variable):

     Dim  g_BlockTargetOffsetTime as Long

Then I would set up a structure with some InLines something like the following:

BlockInitCode
TrialList
     TrialProc
         TrialInitCode
         TrialStimSlide

TrialStimSlide is the stimulus, with Duration set to [TrialDur].

BlockInitCode is an InLine object that simply 
stores the target offset time of the block for 
use later (it assumes that the first event in 
TrialProc is our stimulus, and uses the much 
overlooked GetNextTargetOnsetTime method, see 
that topic in the E-Basic Help facility):

     Const  BlockDur as Long = 10 * 60 * 1000
     g_BlockTargetOffsetTime = GetNextTargetOnsetTime + BlockDur

And TrialInitCode is another InLine object that 
sets the TrialDur attribute according to specifications (1) and (2) above:

     Const  TrialDur as Long = 2 * 60 * 1000
     If ((GetNextTargetOnsetTime + TrialDur) <= 
g_BlockTargetOffsetTime) Then  ' all but the final trial
         c.SetAttrib "TrialDur", TrialDur
     Else  ' final trial
         c.SetAttrib "TrialDur", _
             (g_BlockTargetOffsetTime - GetNextTargetOnsetTime)
     End If

And if you don't mind using one of the less 
common coding conveniences of E-Basic/VBA, then you could shorten that to

     Const  TrialDur as Long = 2 * 60 * 1000
     c.SetAttrib "TrialDur", _
         Iif( ((GetNextTargetOnsetTime + 
TrialDur) <= g_BlockTargetOffsetTime ), _
         TrialDur, (g_BlockTargetOffsetTime - GetNextTargetOnsetTime) )


Pros to this solution:
- It does not use any array, nor require the 
attending complications of computing array indexes.

- It does not require any "If 
c.GetAttrib("Trial") > 1" test on each trial -- 
seems wasteful to run such a test on each trial 
when we know ahead of time that it will succeed 
on all trials except the first.  Usually we can find a better way.

- It works directly in terms of the target offset 
time for the block, which gets computed only 
once.  It is thus more accurate with time 
(without care, accumulated computations of block 
time remaining might not take into account delays 
in actual stimulus duration, etc.).


Criticisms of this solution:
- Some users would find it more natural to work 
in terms of the remaining block duration instead 
of the target block offset time (but, without 
much trouble, this solution could be adapted to 
compute and use remaining block duration instead).

- It uses the GetNextTargetOnsetTime method -- a 
very powerful concept in E-Prime, but kept well 
hidden in the documentation (I stumbled upon it 
myself only while searching the Forum for other things).

- Instead of having all the code compactly 
gathered into one InLine (plus a bit of global 
User code), it is spread across two InLines (plus 
a bit of global User code).  This may make it 
slightly harder for some to follow (I think 
Michiel Spapé has made well-put comments on this 
sort of tradeoff either on the Group or in his E-Primer).

- You already have a perfectly good working 
solution that makes sense to you, so I'm a little late to the game, aren't I?

-- David McFarlane, Professional Faultfinder


At 6/30/2011 05:26 PM Thursday, David McFarlane wrote:
>This got addressed on the PST Forum 
>(http://www.pstnet.com/forum/Topic5419-7-1.aspx 
>), but you did well to post here as well -- 
>generally I respond only here on the E-Prime 
>Group, and now I can post a few more details and 
>provide code with proper indentation.
>
>First, as you might find explained in Chapter 4 
>of the User's Guide that came with E-Prime, and 
>have instead discovered the hard way, attributes 
>propogate only downward through logging levels, 
>they do not persist as you pop back up to higher 
>levels, and as a result they do not persist as 
>you pop up a level and then back down to the 
>same level, as happens at the end of a Procedure 
>run by a List.  IOW, despite some appearance, 
>"attributes" are *not* "variables", and they 
>will not fulfill the role of 
>variables.  Variables and attributes each have their own roles.
>
>So, as explained on the Forum, in short you need 
>to use a global variable.  As explained in 
>Chapter 4 of the User's Guide, you do that in 
>the User tab of the Script view.  Define a variable such as TRemaining, e.g.,
>
>Dim TRemaining as Long
>
>Then use that global variable to keep track of 
>the value from trial to trial, as in ...  well, 
>when I tried to write out the code it didn't 
>seem quite right, and I have to run off and 
>catch a bus now.  Maybe you or someone else can 
>now sort this out based on the clues given so far.
>
>-- David McFarlane, Professional Faultfinder
>
>At 6/30/2011 02:18 PM Thursday, you wrote:
>>I am programming an experiment where the total time a person can take
>>is 10 minutes (600000 ms) (to do 12 trials), with a maximum of 2
>>minutes per trial (the trial terminates and starts the next trial
>>after 2 minutes). I have set the program to terminate the list if the
>>total time is over 10 minutes, however there is a problem--say a
>>person has taken 9:45 do to 7 trials, so they have 15 seconds left.
>>BUT...on trial 8, the duration is still set to max 2 min--so a person
>>can theoretically have a total of 11:45, not 10:00 before it
>>terminates. So I need to have the program know that if more than 8
>>minutes (480000) has been used, the duration of the trial should be
>>600000-however much time has been used so far.
>>
>>I have tried to fix this by putting an attribute in the list object
>>called "trial" which is just the number of the trial, and another
>>attribute called "trialtime", which will be the duration of the slide
>>object (where the stimulus/trial is presented). in the slide object
>>properties, I have set timelimit to be the attribute "trialtime".
>>Lastly, after each trial, the attribute "timertrial" is calculated,
>>which essentially calculates the length of time taken for that trial
>>and adds it to the previous time taken, so that this attribute is
>>constantly updated to reflect the total time taken. All of this seems
>>to work fine, and running through the program shows that "timertrial"
>>is indeed calculating correctly and is recording in the edata file.
>>the problem occurs, however, when I put all this together, and try to
>>change the duration of the next trial based on the "timertrial"
>>attribute. Here is my code:
>>
>>Using the inline statement below, I have set the first trial duration
>>is 120 seconds, and every other trial after that the duration is
>>calculated based on total time taken so far
>>
>>If c.GetAttrib ("trial") = 1 then c.SetAttrib "trialtime", 120000
>>If c.GetAttrib ("trial") > 1 then
>>If c.getAttrib ("timertrial") >= 480000 then c.setAttrib "trialtime",
>>600000 - c.getAttrib ("timertrial")
>>If c.getAttrib ("timertrial") < 480000 then c.SetAttrib "trialtime",
>>120000
>>End If
>>
>>The problem is, the program cannot find the attribute "timertrial"--it
>>calculates fine at the end of each trial, but when I start a new trial
>>(within the same list), it does not have a value yet for timertrial,
>>since that is calculated at the END of the trial. How do I get it to
>>pull the value of "timertrial" from the previous trial and use it as
>>an attribute in the NEXT trial? I am sure this is simple, but I can't
>>seem to get anywhere.
>>
>>Also, Note: I have tried using this code instead:
>>If c.GetAttrib ("Trial") > 1 then
>>if LetterSetList.GetPrevAttrib ("timertrial") >= 480000 then
>>c.setAttrib "trialtime", 600000 - LetterSetList.GetPrevAttrib
>>("timertrial")
>>if LetterSetList.GetPrevAttrib ("timertrial") < 480000 then
>>c.setAttrib "trialtime", 120000
>>End If
>>
>>And I keep getting type mismatch errors, which should be easy to
>>resolve, but this one keep stumping me.  Again, I'm sure this is
>>something simple, but for some reason I can't get it.

-- 
You received this message because you are subscribed to the Google Groups "E-Prime" group.
To post to this group, send email to e-prime at googlegroups.com.
To unsubscribe from this group, send email to e-prime+unsubscribe at googlegroups.com.
For more options, visit this group at http://groups.google.com/group/e-prime?hl=en.



More information about the Eprime mailing list