Jeremy

Forum Replies Created

Viewing 15 posts - 511 through 525 (of 1,522 total)
  • Author
    Posts
  • in reply to: Can we randomize time with newTimer() ? #7928
    Jeremy
    Keymaster

    Well, there are the differences I just described, having to do with cumulative delays when setting a final Timer element using the VAR method, vs using an overall 4000ms Timer element which introduces no such delay

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7925
    Jeremy
    Keymaster

    The event times reported in the results file correspond to when the relevant events occurred. For the Key element, it stands for when the relevant key was pressed, and for the Canvas element, it stands for when the print command was executed. So the difference you calculate corresponds to how many milliseconds passed between when the print command of the Canvas element was executed (which should be almost exactly when its content started being visible on the page, barring performance issues) and when the keypress was detected (which should be almost instantaneous, again barring performance issues). That difference includes the time it took for all the commands between the printing of the Canvas element and the keypress to be executed (basically,just newKey and log, so maybe 1ms) but that shouldn’t matter because all you care about is how long it actually took for the participant to press a key after seeing the Canvas element, regardless of whether the script executed commands during that time

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7923
    Jeremy
    Keymaster

    No, performance issues are orthogonal to the method you use: if a participant’s browser is having a hard time running the script of the pages they are visiting, the whole execution of the experiment will be affected

    The delays, as I said, come from the fact that every single command takes a non-null time to be executed, which means that even two consecutive commands cannot be considered to happen at the same time, so that a sequence newTimer(100).start().wait(),newTimer(200).start().wait() cannot be taken to last exactly 300ms with 100% certainty. The advantage of creating an overall Timer element of 4000ms is that you don’t depend on a sequence of commands to calculate its duration, and are therefore not at risk of accumulating such delays in doing so

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7921
    Jeremy
    Keymaster

    My initial suggestion is to set a duration of 4000ms, so the duration between the start command of the Timer element and its end (which would coincide with the completion of its wait command) would be as close to 4000ms as you could get, barring any performance or technical issue with the participant’s browser/device

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7918
    Jeremy
    Keymaster

    You would need to use the method that you use with the Var element named localRT to dynamically calculate the duration in another Var element, and set the duration of a final Timer element using that Var element. Be aware, though, that each command takes a non-null time to be executed, so the value of a Var element set the way localRT is set is not guaranteed to be exact to the millisecond:

    newVar("localRT").set(v=>Date.now()),
    newKey("keypress1","SK").wait(),
    getVar("localRT").set(v=>Date.now()-v),

    Both newKey and wait (and set too, to some extent) take some time to be executed, which means that Date.now()-v might represent a time difference that’s slightly greater (by up to a couple milliseconds) than the actual time that passed between the creation of the Key element and a keypress. Also, all the commands that come after the wait command of the previous Timer element (timer_D3) and before newVar take time to be executed too, so those few milliseconds are not taken into account either if you create the Var element a few commands after waiting for the end of the previous Timer element

    Moreover, your actual trials won’t have the wait command on the Key element, but rather on the Timer element named timer-RT, so that’s the one after which you would need to set a Var element like localRT. So simplifying the structure a little bit, you would have something like this:

    timerd1duration = 400+Math.round(1200*Math.random())
    ,
    newTimer("timer-D1",timerd1duration).start().wait()
    ,
    getText("D1").remove()
    ,
    newText("cue", "*").color("green")
    ,
    newTimer("timer_cue_D2",100).start().wait()
    ,
    getText("cue").remove()
    ,
    newText("D3", "+").color("pink")
    ,
    newTimer("timer_D3",400).start().wait()
    ,
    newVar("newTimerDuration").set( v=>Date.now() )
    ,
    getText("D3").remove()
    ,
    newTimer("timer-RT",1700).start()
    ,
    newImage("imagens", row.imagem).size(500, 200)
    ,
    newText("cruz_central", "+").color("black")
    ,
    newCanvas("center", 150,150).add( "center at 50%" , "center at 50%" , getImage("imagens")).print()
    ,
    newKey("keypress1","SK").log().callback( getTimer("timer-RT").stop() )
    ,
    getTimer("timer-RT").wait()
    ,
    getVar("newTimerDuration").set( v=> 3500 - timerd1duration - (Date.now()-v) )
    ,
    newTimer("separacao").set( getVar("newTimerDuration") ).start()
    ,
    getKey("keypress1").disable(),getText("cruz_central"),getCanvas("center").remove()
    ,
    newText("+").color("yellow")
    ,
    getTimer("separacao").wait()

    Finally, let me point that any reviewer who would argue that the design is not replicated using the method I suggested earlier either would not understand it, or (unless I myself misunderstood the design as described in the excerpt you quoted) would be completely dishonest in their assessment (keeping in mind that there is a myriad of other technical points of divergence when implementing the same design using different codes and engines)

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7916
    Jeremy
    Keymaster

    The solution I give does *not* create a final Timer element with a variable duration. Instead, the solution I suggest (which, in my opinion, is simpler and cleaner, at least when implemented in PCIbex) consists in starting a Timer element at the beginning of the trial of a fixed duration, ie. the intended overall duration of the trial, and wait for it to elapse at the end of the trial before proceeding to the next one

    The excerpt you quote includes three timers with a variable duration: D1 (400ms–1600ms) RT (0ms–1700ms) and WAIT (3500ms minus D1 minus RT). Then there are two timers with a fixed duration: D2 (100ms) and D3 (400ms) which makes for a total of 500ms. Because of how WAIT is calculated, adding the duration of the five timers totals to 4000ms

    I misunderstood your previous messages as suggesting that you meant to have a total trial duration of max(D1)+max(RT)+D2+D3, which is why I proposed creating a Timer element of 3800ms. But if you want to replicate the design from that quote, set the very first Timer element (the one you need to wait for at the end) to 4000 instead

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7914
    Jeremy
    Keymaster

    Place the commands in the success and the feedback commands, eg. for success from the code in your message:

    .success(
        newVar("positiveFeedback").set( getVar("localRT") ).set( v=> "Correto! You spent "+v+"ms on this trial" )
        ,
        newText("success")
            .text( getVar("positiveFeedback") )
            .cssContainer({"font-size":"30px", "margin-top":"255px","font-family":"Comic Sans MS", "color":"green"})
        ,
        getVar("accurate").set(v=>[...v,true])
    )

    Your script already achieves including a trial (labeled “feedback”) that prints the average time spent on the practice trials

    Jeremy

    in reply to: Pictures won't load #7912
    Jeremy
    Keymaster

    Hi Sabrina,

    It looks like there was a problem with imagelist.CSV in the first project: when I click it to edit it, it says “Error opening file chunk_includes/imagelist.CSV: Internal Server Error”

    I’m not sure what caused the file corruption, but the problem should be fixed if you delete the file and create/upload it again

    Jeremy

    in reply to: Problem "Bug" with loading picture with audio #7911
    Jeremy
    Keymaster

    Hi,

    I was able to reproduce the problem, and it doesn’t look like it’s coming from a filename mismatch: in my case, the file A10-3.mp3 failed to play, and it looks like my browser never even sent a request to fetch it. PennController keeps only up to 4 pending requests in parallel, to prevent flooding distant servers with requests. It could be that sometimes, 4 audio files fail to fully preload, so PennController never gets to the remaining resources. In my experience, this is more likely to happen with Firefox (and when requests lots of resources) because of the way it loads media streams. I have updated the way that preloading is detected in PennController 2.1beta, so you could try overwriting the copy of PennController.js from your project’s Modules folder with it, and hopefully that should address the issue

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7910
    Jeremy
    Keymaster

    Hi Larissa,

    If you want the totality of your trial to be 3800ms (because timer-RT = 1700ms, max timer-D1 = 1600ms, timer_cue_D2 = 100ms and timer_D3 = 400ms) start the timer at the beginning of the trial, and wait for it at the end:

    Template("tabela-target.csv" , row => 
      newTrial("trial_2_center_cue_UP",
        defaultText
            .center()
            .cssContainer({"position": "absolute",
                           "top": "50%",
                           "left": "50%",
                           "transform": "translate(-50%, +50%)"})
            .print()
        ,
        newTimer("wait-separacao",3800).start()
        ,
        newText("D1", "<br><b>+</b>")
            .cssContainer({"font-size":"100px",
                           "color":"blue"})
            .center()
            .print()
        ,
        newTimer("timer-D1",400+Math.round(1200*Math.random())) // if you want between 400ms and 1600ms, you need 400+[0--1200]
            .start()
            .wait()
        ,
        getText("D1").remove()
        ,
        newText("cue", "<br> <b>*</b>")
           .cssContainer({"font-size":"100px",
                          "color":"green"})
           .center()
           .print()
        ,
        newTimer("timer_cue_D2",100)
            .start()
            .wait()
        ,
        getText("cue","D2").remove()
        ,
        newText("D3", "<br> <b>+</b>")
           .cssContainer({"font-size":"100px",
                          "color":"pink"})
           .center()
           .print()
        ,
        newTimer("timer_D3",400)
            .start()
            .wait()
        ,
        getText("D3").remove()
        ,
        newTimer("timer-RT",1700).start()
        ,
        newImage("imagens", row.imagem).size(500, 200)
        ,
        newText("cruz_central", "<br> <b>+</b>")
            .cssContainer({"font-size":"100px",
                           "color":"black"})
            .center()
            .print()
        ,
        //para cima//
        newCanvas("center", 150,150)
            .add( "center at 50%" , "center at 50%" , getImage("imagens"))
            .cssContainer({"position": "absolute",
                           "margin-top": "85px"})
            .center()
            .log()
            .print()
        ,
        newKey("keypress1","SK")
            .log()
            .callback( getTimer("timer-RT").stop() )
        ,
        getTimer("timer-RT").wait()
        ,
        getKey("keypress1").disable(),
        getText("cruz_central"),
        getCanvas("center").remove()
        ,
        newText("separacao", "<br> <b>+</b>")
            .cssContainer({"font-size":"100px",
                           "color":"yellow"})
            .center()
            .print()
        ,
        getTimer("wait-separacao").wait()
      )
      .log("imagens", row.imagem)
      .log("item", row.versao)
    );

    Also, re. the feedback on each trial, just use the Var named localRT to set a Text element in the success/failure commands. For example, in success:

    newVar("positiveFeedbackText").set( getVar("localRT") ).set( v => "Correct! Your speed was: "+v+"ms!" )
    ,
    newText("positiveFeedback").text( getVar("positiveFeedbackText") ).print()

    Jeremy

    in reply to: results cannot be downloaded #7900
    Jeremy
    Keymaster

    Hi,

    The results should be accessible again (for now). The server is having a hard time handling results submissions and requests to access results these past days, so I restart the server periodically to ease the burden on it. Unfortunately the issue is likely to happen again until I revise the code of the farm (which I am actively working on)

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7895
    Jeremy
    Keymaster

    The logic for average RT per trial is the same as average accuracy: add newVar("localRT").set(v=>Date.now()) above newKey("keypress1","SK") and below the wait command add getVar("localRT").set(v=>Date.now()-v) , newVar("practiceRTs",[]).global().set(v=>[...v,getVar("localRT").value])

    Then your feedback trial would look like this:

    newTrial("feedback",
      newVar("timeText").set( getVar("practiceRTs").global() ).set(v=> "You spent "+(v.reduce((n,m)=>n+m)/v.length)/1000+"s per trial on average" ),
      newText( "feedbackTime" ).text( getVar("timeText") ).print()
      ,
      newVar("accuracyText").set( getVar("accurate").global() ).set(v=> "You got "+v.filter(a=>a==true).length+" correct answers out of "+v.length ),
      newText( "feedbackAccuracy" ).text( getVar("accuracyText") ).print()
      ,
      newButton("Continue").print().wait()
    )

    Jeremy

    in reply to: Problem with preloading audios #7894
    Jeremy
    Keymaster

    Thanks, I’ve been unable to replicate the issue so far, so I can’t be sure that PennController 2.1beta would fix it. However, the way PennController 2.0 downloads and decompresses zip archives occasionally yields a corrupt output, so if the crash is related to that, chances are that 2.1beta would take care of it

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7891
    Jeremy
    Keymaster

    would it be possible to show them how much time they’ve spent on the practice trial as well as their accuracy? If so, how?

    EDIT: I just saw your new message, which asks about average response time per practice trial rather than time spent on the whole practice block. I’ll address that later

    You could add this at the end of your keyboard_warning trial, after getText("keyboard-text").remove(): newVar("startPractice").global().set(()=>Date.now())

    Then before the test on your Key element in the code of your practice trials, add newVar("accurate", []).global() and inside the success and failure commands, add getVar("accurate").set(v=>[...v,true])/getVar("accurate").set(v=>[...v,false]) (respectively)

    You can add a trial before instructions_E that would do something like:

    newTrial("feedback",
      newVar("timeText").set( getVar("startPractice").global() ).set(v=> "You spent "+Math.round((Date.now()-v)/600)/100+"min practicing" ),
      newText( "feedbackTime" ).text( getVar("timeText") ).print()
      ,
      newVar("accuracyText").set( getVar("accurate").global() ).set(v=> "You got "+v.filter(a=>a==true).length+" correct answers out of "+v.length ),
      newText( "feedbackAccuracy" ).text( getVar("accuracyText") ).print()
      ,
      newButton("Continue").print().wait()
    )
    

    Jeremy

    in reply to: Can we randomize time with newTimer() ? #7888
    Jeremy
    Keymaster

    My bad, it’s a typo from a previous version of my code, it should be timer-D1—I have edited my message accordingly

    Jeremy

Viewing 15 posts - 511 through 525 (of 1,522 total)