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