Setting accuracy and RT thresholds for practice block

PennController for IBEX Forums Support Setting accuracy and RT thresholds for practice block

This topic contains 3 replies, has 2 voices, and was last updated by Jeremy Jeremy 4 months, 2 weeks ago.

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #6041
    Avatar
    agnesgao
    Participant

    Hi Jeremy,

    Hope you are doing well! I am setting up an experiment in which subjects read words and respond to the status of the words as quickly as possible (under 2 seconds). I had finished a pilot using pcibex without giving any accuracy or RT feedback, however, it seems like most subjects were either too slow or had really low accuracy. So I am wondering if there’s a way to keep track of the accuracy and RT and to keep looping the practice trials until the participants reach 90% acc and at least 2 second RT. Once they meet the requirement, then they can move on to the real experiment block.

    Right now, I am able to give a “too slow” alert on trials that exceeds the RT requirement (using newTimer and getKey (test.pressed) ) and to give an average accuracy feedback at the end of the block. Any advice from you would be greatly appreciated!!

    Thank you!!

    Best,
    Agnes

    #6044
    Jeremy
    Jeremy
    Keymaster

    Hi Agnes,

    Unfortunately PCIbex does not support loops at the moment, because the sequence of trials is purely linear: it is computed at the very beginning of the experiment based on the Sequence command (if present) and every trial runs one after the other.

    A suboptimal alternative would be to repeat the sequence of practice trials multiple times, but only run them fully if the grand average is too low. Something like this:

    Sequence(
      "practice" , "post-practice" ,
      "practice" , "post-practice" ,
      "practice" , "post-practice" ,
      "practice" , "post-practice"
      ,
      "pre-experiment" , "experiment" 
    )
    
    Template( "practice.csv" , row => 
      newTrial( "practice" ,
        newVar( "responses" , [] ).global(),
        newVar("grandaverage", 0).global()
            .test.is( v => v>=0.5 ).success( end() )
        ,
        newText( row.Word ).print()
        ,
        newKey( "choice" , "FJ" ).log().callback( getTimer("timewindow").stop() )
        ,
        newTimer( "timewindow" , row.Time ).start().wait()
        ,
        getKey("choice").disable().test.pressed( row.Correct )
            .success(  getVar("responses").set(v=>[true,...v]) )
            .failure(  getVar("responses").set(v=>[false,...v]) )
      )
    )
    
    newTrial( "post-practice" ,
        newVar("grandaverage")
            .global()
            .test.is( v=>v>>0.5 )
            .failure( 
                newButton("Next").print().wait()
                ,
                getVar("grandaverage")
                    .set( getVar("responses") )
                    .set( v=>v.filter(r=>r==true).length/v.length )
            )
        ,
        newVar("responses").global().set( [] )
    )
    
    newTrial( "pre-experiment" , newButton("Start").print().wait() )

    This should run the practice block up to three times, if your participant fails to reach the 50% threshold every time. Otherwise, the test on the grandaverage Var will run the end command at the very beginning of every trial in subsequent blocks, effectively skipping to the experiment trials.

    Let me know if you have questions

    Jeremy

    #6053
    Avatar
    agnesgao
    Participant

    Hi Jeremy,

    Thank you so much for the help! I think this is a great solution to my issue! I have another question: there is a second task following the first key press (sorry i should have mentioned it in my first post), and it doesn’t have ACC or RT limit. For some reason, the modified script skipped the second question automatically to the next trial even when the first key press didn’t exceed the RT time window. I tried using test.is on the var RT but it’s not doing anything and still skipping. The goal is: if the RT is over 2 sec, then it times out and moved on to the next trial; if it’s under 2 sec, then they complete the second question (coded as “pred”). Please see the partial relevant code below:

     newTimer("timewindow", row.Time )
            .start()
            .wait()
            ,
            newKey("LD", "ZM")
            .log("")
            .callback( getTimer("timewindow")
            .stop()
            ,
                    
            getVar("RT")
            .set( v => Date.now() - v ) // finish measuring RT
            .log("first")
            .test.is( v => v<= 2000 )
            .success( getText("pred").print() )
            .failure(newText("failure", "Too slow...please respond faster").print() )
            ,
            
            getKey("LD")
            .disable()
            .test.pressed(row.correct)
            .success(  getVar("responses").set(v=>[true,...v]) )
            .failure(  getVar("responses").set(v=>[false,...v]) )
    
            ,
            
            newTimer("wait", 500) 
             .start()
             .wait()
             ,
            
            getText("fix2")//remove 
            .remove()
            ,
            
            newText("pred","Did you predict the word?")
            .print()
            .log()
    
            ,
            newKey("answer", "ZM")
            .wait() // This waits for a key press
            .log("first")

    Thank you again for your help and patience!

    Best,
    Agnes

    • This reply was modified 4 months, 2 weeks ago by Avatar agnesgao.
    • This reply was modified 4 months, 2 weeks ago by Avatar agnesgao.
    • This reply was modified 4 months, 2 weeks ago by Avatar agnesgao.
    #6057
    Jeremy
    Jeremy
    Keymaster

    Hi Agnes,

    The partial code you posted will launch the timewindow timer and wait that it has elapsed entirely before proceeding past its wait command, at which point it will reach the LD Key block containing the callback command, which will be ineffective since the timer will have already ended at that point. That’s why the callback that makes it possible to end the timer prematurely must come before the wait command on the timer, as in my code above.

    I presume that you declare newVar("RT") before the timewindow timer and set it to Date.now() at that point. Because your getVar("RT") comes after the wait on your timer (and because, as we saw, the Key element cannot end it early) the value of your Var element will be at least as big as row.Time.

    The second question, however, should always appear and never be skipped, given the code you posted (unless there is an end command elsewhere).

    Here is a code that, I think, will do what you want. It should be embedded in Template of course:

    newTrial( "practice" ,
        newVar( "responses" , [] ).global(),
        newVar("grandaverage", 0).global()
            .test.is( v => v>=0.5 ).success( end() )
        ,
        newText( "fix2" , row.Word ).print()
        ,
        newKey( "choice" , "FJ" ).log().callback( getTimer("timewindow").stop() )
        ,
        newVar("RT").set( v=>Date.now() )
        ,
        newTimer( "timewindow" , row.Time ).start().wait()
        ,
        getKey("choice").disable().test.pressed( row.Correct )
            .success(  getVar("responses").set(v=>[true,...v]) )
            .failure(  getVar("responses").set(v=>[false,...v]) )
        ,
        getText("fix2").remove()
        ,
        getVar("RT").set( v=>Date.now()-v )
            .test.is( v => v < 2000 )
            .failure(
                newText("Too slow...please respond faster").print()
                ,
                newTimer(1500).start().wait()
                ,
                end()
            )
        ,
        newTimer("wait", 500) 
            .start()
            .wait()
        ,
        newText("pred","Did you predict the word?").print()
        ,
        newKey("answer", "ZM")
            .wait() // This waits for a key press
            .log("first")
    )

    Note that if row.Time is lower than 2000, then consequently RT will never reach 2000 either (ie. row.Time is the max limit of RT). I chose to print the “Too slow” message for 1.5s before if RT is over 2000, and end the trial immediately after that. If RT is below 2000, the end command is not executed and so the script continues to print the pred Text and wait for a keypress on Z or M before reaching the end of the trial

    Let me know if you have questions

    Jeremy

Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.