labscript-suite / labscript

The 𝗹𝗮𝗯𝘀𝗰𝗿𝗶𝗽𝘁 library provides a translation from expressive Python code to low-level hardware instructions.
http://labscriptsuite.org
BSD 2-Clause "Simplified" License
9 stars 48 forks source link

Unexpected Issue with Labscript Clockline Timing #83

Closed matth2peters closed 2 years ago

matth2peters commented 2 years ago

Hi,

I'll start by introducing a simplified version of the problem I'm having:

I have a connection table + simple sequence below (you'll have to change the location of the connection table in the sequence file), which I am unable to run. When trying to compile the sequence file in runmanager, I get the error

Traceback (most recent call last):
  File "C:\Users\matth\labscript-suite\Rydberg_userlib\labscriptlib\Rydberg\Sequences\Test_Sequences\Device_Testing\Test_Delay.py", line 37, in <module>
    stop(1)
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 3411, in stop
    generate_code()
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 3230, in generate_code
    device.generate_code(hdf5_file)
  File "c:\users\matth\labscript-suite\python_38\lib\site-packages\labscript_devices\PulseBlaster_No_DDS.py", line 48, in generate_code
    PseudoclockDevice.generate_code(self, hdf5_file)
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 1326, in generate_code
    Device.generate_code(self, hdf5_file)
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 592, in generate_code
    device.generate_code(hdf5_file)
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 1091, in generate_code
    self.generate_clock()
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 1064, in generate_clock
    all_change_times, change_times = self.collect_change_times(all_outputs, outputs_by_clockline)
  File "c:\users\matth\labscript-suite\labscript\labscript\labscript.py", line 841, in collect_change_times
    raise LabscriptError('Commands have been issued to devices attached to %s at t= %s s and %s s. '%(self.name, str(t),str(all_change_times[j+1])) +
labscript.labscript.LabscriptError: Commands have been issued to devices attached to pulseblaster_0_pseudoclock at t= 1e-06 s and 1.4e-06 s. One or more connected devices on ClockLine ni_6733_clk cannot support update delays shorter than 1e-06 sec.
Compilation aborted.

The crux of the problem seems to be that in labscript.py line 841, the error checking only looks to see if the timing between pulseblaster commands is less than the minimum clockline recovery time (in this case 1e-6 seconds) without seeing if the clockline output itself is actually changed. I'm expecting that even if the pulseblaster updates faster than the clockline can, it won't affect any of the devices clocked by the pulseblaster so long as the corresponding flag doesn't change its value.

My question is whether I am correctly understanding the problem, and whether altering/removing the conditions for this exception will have unforeseen consequences

Update: After looking more closely at the hdf sequence file, it looks like the clockline that triggers my NI card is programmed such that the trigger is high for half of the time before the next PB update. So if I have a trigger on a different flag some time t after setting my analog card to a new value, the clockline trigger width sent to the analog card will be t/2. I had initially assumed the flag corresponding to the clockline would stay high until just before the next trigger occurs.

For my particular NI card 6733, this isn't an issue (the trigger width only needs to be >=10 ns), and if I comment out the exception thrown on line 841, my sequences still work as expected. I'm also prevented from an error being caused by setting t to be too small since my pulseblaster can only be triggered once every 120 ns anyway. I can imagine something going wrong in general if this exception was removed, but to me it seems like a robust solution for my devices is to comment out this exception unless there's something I'm missing

More Updates: It looks like this is a similar issue to https://github.com/labscript-suite/labscript/issues/51, so I'll close it I see that adding a pseudoclock buffer between the NI cards and my pulseblaster could also address this issue

(Also, apologies if this was the wrong place to post this)

Connection table:

from labscript import start, stop, ClockLine, DigitalOut
from labscript_devices.NI_DAQmx.models.NI_PCI_6733 import NI_PCI_6733
from labscript_devices.PulseBlasterUSB import PulseBlasterUSB

from labscript import (
    ClockLine,
    AnalogOut,
    DigitalOut,
    start,
    stop
)

def cxn_table():

    PulseBlasterUSB(
        name="pulseblaster_0",
        board_number=1,
    )

    ###
    ### Clocks for NI cards and initialize NI cards
    ### 

    ClockLine(
        name="ni_6733_clk",
        pseudoclock=pulseblaster_0.pseudoclock,
        connection='flag 1',
    )

    #####

    NI_PCI_6733(
        name="ni_6733B", 
        parent_device=ni_6733_clk, 
        clock_terminal = "/AO_B/PFI0", 
        MAX_name = "AO_B"
        )

    AnalogOut(
        name="control_aom_power",
        parent_device=ni_6733B,
        connection="ao0",
        default_value=0,
        limits=(0, 3)
    )
    AnalogOut(
        name="dummy",
        parent_device=ni_6733B,
        connection="ao1",
        default_value=0,
        limits=(0, 3)
    )

    DigitalOut(
        name="control_aom_switch",
        parent_device=pulseblaster_0.direct_outputs,
        connection="flag 14",
        default_value=0,
    )   

cxn_table()
start()
stop(1)

Sequence File:

from labscript import (
    start,
    stop,
)

from labscriptlib.Rydberg.Simplied_connection_table import cxn_table

if __name__ == '__main__':

    # Import and define the global variables for devices
    cxn_table()

    t=0.0

    start()

    control_aom_power.constant(1e-6, 2.0)
    control_aom_switch.enable(1.4e-6)
    control_aom_power.constant(3e-6, 0)

    stop(1)
dihm commented 2 years ago

@matth2peters

I'm glad you found the thing I was going to point you to anyway. These types of problems are a rather subtle consequence of the way pulseblasters have to be programmed. Another more recent option that avoids this is to use a pseudoclocking device with independent clocklines (like the Prawnblaster).

Also, this is a perfectly good place for these kinds of questions, especially when you have provided such a thorough explanation and example code. It really is appreciated! My apologies for not getting an answer to you before you found it yourself (though I am glad there is enough out there you could actually find it).