Screen refresh delay in sending parallel port response triggers

OS (e.g. Win10): Win10
PsychoPy version (e.g. 1.84.x): 3.1.0
Standard Standalone? (y/n) If not then what?: Y

What are you trying to achieve?:
I am trying to send parallel port triggers exactly as the response buttons are pressed.
I have used a builder component with the following set up:

When the parallel port component is positioned before the keyboard component, the delay between the response time in the output file and the parallel port trigger is about 13 ms which equates to 2 frames.

When the parallel port component is positioned after the keyboard component. the delay is about 6.7 ms which equates to 1 frame.

What did you try to make it work?:
I have looked at a previous thread:

It suggests to remove the following parts of code in relation to the parallel port component:

callOnFlip()

Originally my coder view script looked like this:


What specifically went wrong when you tried that?:

I removed the callOnFlip commands and run the task again (from the coder view) but the delay was still there.

This was the code:

        # *p_port_prac1b* updates
        if (prac_resp.keys == 'm' or prac_resp.keys == 'c' or prac_resp.status == FINISHED) and p_port_prac1b.status == NOT_STARTED:
            # keep track of start time/frame for later
            p_port_prac1b.tStart = t  # not accounting for scr refresh
            p_port_prac1b.frameNStart = frameN  # exact frame index
            win.timeOnFlip(p_port_prac1b, 'tStartRefresh')  # time at next scr refresh
            p_port_prac1b.status = STARTED

        if p_port_prac1b.status == STARTED and t >= (p_port_prac1b.tStart + 0.05):
            # keep track of stop time/frame for later
            p_port_prac1b.tStop = t  # not accounting for scr refresh
            p_port_prac1b.frameNStop = frameN  # exact frame index
            win.timeOnFlip(p_port_prac1b, 'tStopRefresh')  # time at next scr refresh
            p_port_prac1b.status = FINISHED

I also unticked the option Sync to screen in the builder component, but again, the delay persisted.
In the tab Data there is another option called Sync timing with screen refresh which I had ticked. When I unticked it, the trigger timings were completely bizarre and not related to responses.

Should I change something else in the code? Or is there a way to fix this within the builder component?

Thanks!

Heey, I am still struggling with this. Any advice for how I can fix the delay?
Much appreciated!
@dvbridges @jon

Hi @MartaT, the positioning in the routine does count. If you have your pport before the keyboard, and a response is made, the pport does not know this until the next screen refresh (or the next iteration of the routine loop). Then, if you have the sync to screen refresh set for the pport, the trigger is sent at the end of that current frame (1 screen refresh). If you have the pport positioned after the keyboard, and the pport is not synced to the screen refresh (so it triggers as soon as a keypress is registered and the pport keypress condition is satisfied), is the timing any better?

Hi @dvbridges!
So I have been playing around with this again today and I literally tried most of possible combinations of the position of the pport and the keyboard, and the different sync to screen options.

The most successful coordination of these two components happened when I unticked all of the sync to screen options for both the pport and the keyboard. When the pport was positioned before the keyboard, the first delay was 2 frames and all other trials had a delay of 1 frame.
I moved the pport component back to the very bottom (after the keyboard) with the same setting of no sync to screen options. The first delay was just slightly less than one frame and all other delays are between 0.3 - 1 ms.

This is a much better result and I can take this into account when analysing the EEG data. But I was wondering whether you think it would be possible to send the signal precisely at the button press or whether I should give up now. (I can use the output file to manually mark on the EEG output when the responses happened exactly, although it would be more helpful to have the pport signal).

Thanks!

That effectively is exactly at the time the button is (recorded as being) pressed. i.e. this is far more precise than the timing of the keypress itself. If you are using a regular computer keyboard, it could typically have a lag of say, 30 ms, and a variability of say 15 ms. In that context, 0.3 - 1 ms is no time at all. If this level of precision is necessary, you should look at using dedicated response hardware rather than a standard keyboard.

@Michael this clarifies it for me, thanks a lot!

Hi Marta,

Apologies I am late to this - I have been on leave. I have been working on this for a while now with help from @Michael and previous similar posts/replies. Response triggers cannot be sent as many times as the response key is pressed / Word by word sentence presentation with parallel port output

I am using a code component in builder - rather than using the parallel port component. I am experiencing 1-2ms delay on triggers including key response - so perhaps yours can be resolved to reduce from the 1 frame currently?

Please note, I am still doing some final testing now so the below is still work in progress but may be of use if you are still experiencing delays with your method.

I have something similar to the following, although i tried to use your variable names to avoid confusion. My keyboard response is set to syn with screen.

good luck!

begin experiment tab

from psychopy import parallel
p_port_prac1b = parallel.ParallelPort(address=0x7F88)

begin routine tab

 # keep track of whether a signal has been sent yet
pulse_sent = False  

# tidy any that may have not been terminated properly
p_port_prac1b.setData(0) 
pulse_terminated = True

Each frame tab

if prac_resp.status == STARTED:
    if prac_resp.keys == 'm' or prac_resp.keys == 'c': #write your condition here - I didn't include any code for the status of the p_port component, only the keyboard response
         response_space.setData(1) 
          logging.log(level=logging.EXP, msg = 1) #print this in the logfile, you check the psychopy logfile timing compared to your output from the EEG marker file
          pulse_start_time = t
          pulse_sent = True
          pulse_terminated = False

# terminate the trigger at least 0.0167 ms (1 frames) later:
if pulse_sent and not pulse_terminated:
    if t - pulse_start_time >= 0.0167:
        p_port_prac1b.setData(0)
        pulse_terminated = True
1 Like

Hi Mica,

Thanks a lot for all these helpful resources! I have managed to reduce the delay with the parallel port component which seems to do the trick and most of the responses are sent pretty much at the button press. Only now and then I would get some odd delays but I don’t suppose this would be too problematic. I will try and account for that.

Thank you!