Writing sequences for quantum information experiments

Overview over the sequencer2 programming style

The sequencer2 software is divided up in three different layers:

PCP instructions (machine code)
API layer
End user layer

Here, only the end user layer will be covered. The sequence below performs Doppler cooling, a coherent pulse on a carrier transition and a detection cycle

DopplerCooling()
pulse_729(theta, phi, "carrier")
Detection()

This is then translated into an API layer program that describes the timing of the TTL channels and DDS commands:

# Doppler cooling
set_ttl("doppler", 1)
wait(doppler_time)
set_ttl("doppler", 0)
# Generate coherent pulse
switch_on_dds(frequency, phase, amplitude)
wait(rf_time)
switch_off_dds()
# Detection
set_ttl("detection", 1)
wait(detection_time)
set_ttl("detection", 0)

Which is then translated into a PCP instruction list that can be exectued directly on the special purpose micro-controller on the PBox mainboard.

A list of the most important end-user commands is available in the PBox cheatsheet.

The PBox cheatsheet

Writing a sequence file for use with QFP or TRICS

The end-user program is embedded in a Pseudo-XML file that is compatible with both experiment control programs, QFP and TRICS.

# Define the sequence variablesxt
<VARIABLES>
det_time=self.set_variable("float","det_time",100000.000000,0.01,2e7)
</VARIABLES>
# The save form specifies which data will be saved and how, when a scan is performed.
# If this is omitted a standard form is used
<SAVE FORM>
  .dat   ;   %1.2f
  PMTcounts;   1;sum;               (1:N);          %1.0f
</SAVE FORM>
# Here the sequence can override program parameters. Syntax follows from "Write Token to Params.vi"
<PARAMS OVERRIDE>
AcquisitionMode fluorescence
DOasTTLword 1
Cycles 1
</PARAMS OVERRIDE>
# The sequence itself
<SEQUENCE>
ttl_pulse(["3", "5"],det_time)
</SEQUENCE>
# Some spooky LabView stuff
<AUTHORED BY LABVIEW>
1
</AUTHORED BY LABVIEW>

The definition of the variables is performed as follows:

# Define the sequence variablesxt
<VARIABLES>
#Syntax Example:
sequence_var = self.set_variable("variable_type", "variable_name", \
                           default_val, min_val, max_val)

#More examples
float_var=self.set_variable("float","name for labview", 10, 0, 100.0)
int_var=self.set_variable("int","name for labview", 10, 0, 100)
bool_var=self.set_variable("bool","det_time")
</VARIABLES>

# Use the variables defined aboce direct in the python script
<SEQUENCE>
if bool_var:
    ttl_pulse(["3", "5"],det_time)
else:
    for item in range(int_var):
        ttl_pulse(["3", "5"],det_time)
</SEQUENCE>

TTL pulses

TTL pulses may act on a list of channels or on a single channel:

ttl_pulse(["channel name1", "channel name2"], pulse_duration)

For a pulse on a single channel there are two different possibilities for defining the pulse:

ttl_pulse("channel name", pulse_duration)
ttl_pulse(["channel name"], pulse_duration)

More complex series of pulses can be achieved by using the is_last and start_time parameters of the pulse methods. By default (when omitting it) is_last is set to True. This means that the pulses are attached one after the other. By manually setting is_last and start_time interleaved pulses are possible:

# Create a pulse from time 0 to 100
ttl_pulse(["3", "5"],100,is_last=False)
# Create a pulse from time 50 to 130
ttl_pulse(["1", "4"],80, start_time=50)
#set start time to zero after last pulse
#Create a pulse from 130 to 330
ttl_pulse(["3", "7"],200)

Adding a pause to the sequence

A pause between two operations in a sequence is generated by the command:

seq_wait(200)

Repeating an operations

A sequence can be simply repeated by the python built in for loop:

for i in xrange(300):
     # Create a pulse from time 0 to 100
     ttl_pulse(["3", "5"],100,is_last=False)
     # Create a pulse from time 50 to 130
     ttl_pulse(["1", "4"],80, start_time=50)
     #set start time to zero after last pulse
     #Create a pulse from 130 to 330
     ttl_pulse(["3", "7"],200)

This creates a machine code where the operations occur 300 times subsequently. This works safely, but the memory of the PBox mainboard is limited and the sequence size is increased:

for i in multiple_pulse(300):
     # Create a pulse from time 0 to 100
     ttl_pulse(["3", "5"],100,is_last=False)
     # Create a pulse from time 50 to 130
     ttl_pulse(["1", "4"],80, start_time=50)
     #set start time to zero after last pulse
     #Create a pulse from 130 to 330
     ttl_pulse(["3", "7"],200)

This creates a machine code where the repeated part is only compiled once and repetition is performed with the aid of a finite loop inside the FPGA micro-controller. This version saves memory and pulse-length. Please note, that the variable i cannot be used within the loop, as the micro-controller does not allow variables in finite loops.

Coherent manipulation - RF pulses

An RF pulse can be generated by the command:

rf_pulse(theta, phi, ion, "transition name")

where theta is the rotation angle in units of Pi. theta=1 corresponds to a rotation from the ground to the excited state. phi is the relative RF (and also laser) phase that determines the rotation axis on the Bloch sphere, ion is an integer corresponding to the ion-number.

The actual parameters for the DDS device are frequency and RF-level. These two parameters are encoded in a “transition”. In the actual end=user sequence only a string identifying the used transition is required. The data corresponding to this transition is sent from TRICS or QFP to the sequencer2. Normally this is NOT included in the VARIABLES or the sequence itself. See the TRICS documentation for more information ;-)

To insert a transition directly into the Pseudo XML file, put following code between the SEQUENCE tags:

transition1 = sequence_handler.transition("test1", {1:1}, 200)
# The transition is used by the following:
rf_pulse(1,0,1,transition1)

There exist operations that allow a frequency, amplitude or phase sweep during an RF pulse. These functions are not properly tested in Innsbruck, so use them at your own risk. Please see the file server/user_function.py for the function definitions.