labscript-suite-temp-2 / labscript

The labscript Python library provides a translation from simple Python code to complex hardware instructions. The library is used to construct a "connection table" containing information about what hardware is being used and how it is interconnected. Devices described in this connection table can then have their outputs set by using a range of functions, including arbitrary ramps.
BSD 2-Clause "Simplified" License
0 stars 0 forks source link

Pseudoclock/clockline collision #53

Open philipstarkey opened 5 years ago

philipstarkey commented 5 years ago

Original report (archived issue) by David Meyer (Bitbucket: dihm, GitHub: dihm).

The original report had attachments: 20190725T165847_main_labscript_0.h5, 20190725T170000_main_labscript_0.h5, 20190725T170006_main_labscript_0.h5


The other project in my lab has encountered a strange issue that produces the following traceback during compilation.

I don’t really understand the error message at all. Why is the clock limitation of our slow clockline being applied to updates of the master pseudoclock? Am I just reading that wrong.

Anyway, doing some digging we found the offending portion of the script to be

    ### note t=0.8047 here ###
    Shutter_MOT.go_high(t)
    Shutter_Repump.go_high(t)

    MOT_BN.setfreq(t,91.7*MHz) #65.8+(266)/16+157/16 #Tuned by looking at imaging
    REP_BN.setfreq(t,83.8*MHz) #Use Horizontal Repumping beam (along xhat (table) (that is, the y coil in Blacs)) to pump 1-1'.
    zCoil.constant(t,value = -0.35) #-.365 #SET FIELD Vertical for opt Pump
    xCoil.constant(t, value = -0.02) #-0.02
    yCoil.constant(t, value = -1.5) #0.25
    print("there: ", t)
    #xCoil.constant(t,value = bx_sweep)
    #yCoil.constant(t,value = by_sweep)
    #zCoil.constant(t,value = bz_sweep)

    t +=2.011e-3 #Coils update.
    #Keep this short, so that don't get too much extra pumping.
    #Turn on light to Pump to F=1

    MOT_AOM_Switch.go_high(t)
    Rep_AOM_Switch.go_high(t)
    t += 0.10e-3
    Rep_AOM_Switch.go_low(t)

    t+= 0.3e-3
    MOT_AOM_Switch.go_low(t)

   #Blow away
    MOT_BN.setfreq(t,65.5*MHz)
    t+=0.2e-3
    MOT_AOM_Switch.go_high(t)
    t+=0.7e-3
    MOT_AOM_Switch.go_low(t)

    MOT_BN.setfreq(t,30*MHz)
    REP_BN.setfreq(t,30*MHz)
    MOT_AOM_Switch.go_low(t)

    t += 0.15e-3
    Shutter_MOT.go_low(t)

If the time in line 14 is set to <=2.01ms the error occurs. The relevant devices are the analog outputs on a fast clocked NI-6733, direct digital outputs of the pulseblaster, and DDS updates from a Novatech 409B-AC on a slow clockline in asynchronous mode. The slow clockline only goes to novatechs and the fast clockline goes to NI-DAQs.

Using runviewer we can look at the clocklines as this time is decreased up to this limit.

This raises a few questions: Why are the fast and slow clocklines identical? What exactly is updating at 804.8 ms? Why does the timing of instructions happening after the offending one matter?

I don’t spend as much time on this experiment so I’m not intimately familiar with their script, but I believe it is configured correctly. Two of the corresponding shots to those shown in runviewer are attached (accidentally grabbed an error shot as well, T170000).

Help diagnosing (and hopefully fixing this) would be appreciated.

philipstarkey commented 5 years ago

Original comment by Philip Starkey (Bitbucket: philipstarkey, GitHub: philipstarkey).


This sounds similar to #51. I am not sure when I'll get a chance to look at your h5 files so you might want to read through that issue and see if it is relevant. Even if it not the same, it might shed some light on how clocklines and pseudoclocks interact, and thus why you get the error.

Let me know if this helps! Hopefully Chris or I can take a look at the h5 files soon.

philipstarkey commented 5 years ago

Original comment by David Meyer (Bitbucket: dihm, GitHub: dihm).


Ah yes. I remember reading that one when Lincoln first put it up and not really getting it. Reading it again, I can almost guarantee this is related to that. I do think it is different: for starters, there are no instructions to any devices for 2ms after the novatech updates, which should be plenty of time. I wonder if the NT asynchronous mode (which makes the precise falling edge timing beyond minimum pulse duration irrelevant) is finding an edge case of the gated-clocks?

Regardless, it looks like I need to understand the gated clocks thing better. I was always under the impression that clocklines were subsets of the pseudo-clock rise-fall times, depending on what devices were connected to which clockline. Assuming that is true, why do the trigger times of one clockline dictate those of another for unrelated instructions? Taking Lincoln’s example: if the DDS and digital out are on different clocklines, why does updating a DO 40us after the DDS force the trigger pulse to go low on the DDS clockline? Couldn’t the DDS clockline just ignore that pseudoclock tick and put the fall at a later pseudoclock tick, completely independent of the other clockline? Sure it would result in a lot of pseudoclock ticks that would need to be tracked to prevent clock over-runs (scaling with independent clocklines), but that seems doable and would seem to allow for not having the entire experiment tied to slow devices.

philipstarkey commented 5 years ago

Original comment by Chris Billington (Bitbucket: cbillington, GitHub: chrisjbillington).


Just updated a NIST lab to latest labscript and also hitting something similar:

Traceback (most recent call last):
  File "20190523_BEC_F1_NewODT_DMD.py", line 630, in <module>
  File "C:\labscript_suite\labscript\labscript.py", line 2467, in stop
    generate_code()
  File "C:\labscript_suite\labscript\labscript.py", line 2304, in generate_code
    device.generate_code(hdf5_file)
  File "C:\labscript_suite\labscript_devices\PulseBlaster_No_DDS.py", line 54, in generate_code
    PseudoclockDevice.generate_code(self, hdf5_file)
  File "C:\labscript_suite\labscript\labscript.py", line 1095, in generate_code
    Device.generate_code(self, hdf5_file)
  File "C:\labscript_suite\labscript\labscript.py", line 478, in generate_code
    device.generate_code(hdf5_file)
  File "C:\labscript_suite\labscript\labscript.py", line 921, in generate_code
    self.generate_clock()
  File "C:\labscript_suite\labscript\labscript.py", line 891, in generate_clock
    all_change_times, change_times = self.collect_change_times(all_outputs, outputs_by_clockline)
  File "C:\labscript_suite\labscript\labscript.py", line 680, in collect_change_times
    'One or more connected devices on ClockLine %s cannot support update delays shorter than %s sec.'%(clock_line.name, str(1.0/clock_line.clock_limit)))
labscript.labscript.LabscriptError: Commands have been issued to devices attached to pb_0_pseudoclock at t= 12.46651408 s and 12.466664080000001 s. One or more connected devices on ClockLine DMD_trig cannot support update delays shorter than 0.00025 sec.
Compilation aborted.

Backing out the gated clocks commit seemingly resolves the issue, though I understand if this is just masking an underlying issue.

Again, the device in question (a LightCrafter DMD) is one with a much slower update rate than others. So it sounds like the same issue.

philipstarkey commented 5 years ago

Original comment by Philip Starkey (Bitbucket: philipstarkey, GitHub: philipstarkey).


@dihm Yes, in theory you could have the falling pulse happen in a later pseudoclock instruction, provided the pseudoclock uses 2 hardware instructions per change in clock frequency. But not all devices do this (however currently those that do not do this also only have one output, so don't use gated clocks anyway). The underlying labscript algorithm doesn't know anything about this sort of capability though, so we'd have to add that in so that PseudoclockDevice subclasses to indicate if they support the proposed behaviour. You might also find it's difficult to do if the subsequent instruction is a ramp (because you would have to break that ramp up into two or three instructions in order to insert the falling transition of the slower clock). It seems like it would be quite complicated, and personally I would just advocate for people adding more (10 MHz referenced) pseudoclock devices to their experiment rather than trying to clock multiple devices from one pseudoclock.

But I’m not opposed to someone trying to do this, although such a complicated change would benefit from having some test cases to test against to make sure we don’t introduce more regressions (I kind of hope we might be able to use runviewer to compare output signals to see if things are generated the same?). An attempt to fix #39 should probably be made at the same time, as it is sort of related.

Edit: The alternative of course is to allow intermediate devices to specify the minimum high time for a clock tick as well as the clock frequency, thus adding information regarding support for asymmetric clock pulses. My recent commit could then be update to check if the time between adjacent instructions is longer than the minimum high time and also if the time between instructions with the clockline enabled is longer than that derived from the maximum clock rate (I think this was suggested as an option in #51)