<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Initializing test sample
Step1:  Building sequences
Sequences are python objects, encoding the experiment you want to run on your pulse generator.
They are built from pulses (another type of object), wait times, and the readout.
The pulse object
Pulse objects are initialized with
Step2:  Building sequences from pulses
Step3:  As you can see, wait times can be added with the add_wait command. In this case the wait time is given by a lambda function. This enable the implementation of variable time steps. This can also be used to add pulses with variable length and amplitude. The variable name t is later used to set values for this wait time. <br>
Of course, there are also pre-built sequences for standard experiments, which you can find in the sequence_library class (here imported as sl).
Currently, this includes sequences for Rabi, T1, Ramsey, spin-echo and spin-locking experiments.
Step4:  Single channel virtual AWG
Step5:  Please note, that this plot always displays the amplitude of your signal (not I or Q).
We refrained from displaying the pulses with their iq_frequency to prevent confusion.
Similarly, it is not necessary to initialize the virtual awg with a channel for each I and Q. Whether two physical channels are needed to generate the desired output is determined automatically by the load script (see below).
Step6:  If you are satisfied with the results, load the sequences onto your physical device with
<ASSISTANT_TASK:>
Python Code:
testsample = sample.Sample()
testsample.readout_tone_length = 200e-9 # length of the readout tone
testsample.clock = 1e9 # sample rate of your physical awg/pulse generator
testsample.tpi = 100e-9 # duration of a pi-pulse
testsample.tpi2 = 50e-9 # duration of a pi/2-pulse
testsample.iq_frequency = 20e6 # iq_frequency for iq mixing (set to 0 for homodyne measurements)
#testsample.awg = my_awg #<- qkit instrument (your actual awg)
Explanation: Initializing test sample
End of explanation
#example:
pi = ps.Pulse(50e-9, name = "pi-pulse", shape = ps.ShapeLib.gauss, iq_frequency=50e6)
#this creates a 50ns gaussian pulse with name "pi-pulse" at an iq_frequency of 50MHz.
Explanation: Building sequences
Sequences are python objects, encoding the experiment you want to run on your pulse generator.
They are built from pulses (another type of object), wait times, and the readout.
The pulse object
Pulse objects are initialized with:
mypulse = ps.Pulse(length, pulse-shape, name, amplitude, phase, iq_frequency, iq_dc_offset, iq_angle)
<br>
length is the pulse length in seconds <br>
pulse-shape is the shape of the pulse. Currently rect (square pulse, this is the default) and gaussian shapes are implemented. To use gaussian shape, write shape = ps.ShapeLib.gauss<it><br>
name is the name you want to give your pulse. This is not mandatory and only used for plotting.<br>
amplitude: relative amplitude of your pulse.<br>
phase: relative phase of your pulse in degree.<br>
iq_frequency: If iq_frequency is 0, homodyne mixing is used.<br>
iq_dc_offset, iq_angle are currently not in use, but will be used in the near future to enable a calibration of the mixers.
End of explanation
my_sequence = ps.PulseSequence(testsample) # create sequence object
my_sequence.add(pi) # add pi pulse, as defined in the example above
my_sequence.add_wait(lambda t: t) # add a variable wait time with length t
my_sequence.add_readout() # add the readout
my_sequence.plot() # show SCHEMATIC plot of the pulse sequence
Explanation: Building sequences from pulses:
Sequences are built from pulse objects in an intuitive way: You just start adding pulses to your sequence, which are then appended. In the example below, a simple T1 measurement sequence is built, using our recently defined pi-pulse.
End of explanation
spinecho = sl.spinecho(testsample, n_pi = 2) # spinecho with 2 pi-pulses
spinecho.plot()
Explanation: As you can see, wait times can be added with the add_wait command. In this case the wait time is given by a lambda function. This enable the implementation of variable time steps. This can also be used to add pulses with variable length and amplitude. The variable name t is later used to set values for this wait time. <br>
Of course, there are also pre-built sequences for standard experiments, which you can find in the sequence_library class (here imported as sl).
Currently, this includes sequences for Rabi, T1, Ramsey, spin-echo and spin-locking experiments.
End of explanation
vawg = VirtAWG.VirtualAWG(testsample) # by default, the virtual awg is initialized with a single channel
time = np.arange(0, 500e-9, 50e-9) # time t for the sequence
vawg.set_sequence(my_sequence, t=time) # set_sequence deletes all previously stored sequences in a channel
vawg.add_sequence(spinecho, t=time*2) # add_sequence appends the next sequence to the sequences stored in the channel
# Note, this enables you to run multiple experiments, such as T1-measurement and spin-echo in parallel!#
vawg.plot()
# In the plot, the time starts at 0 together with the readout. 
# The position of the readout is also used as a phase reference for all pulses.
Explanation: Single channel virtual AWG
End of explanation
# If you do not want the experiments to run consecutively, but to interleave them instead:
vawg.set_interleave(True)
# This also works for more than 2 sequences.
vawg.plot()
Explanation: Please note, that this plot always displays the amplitude of your signal (not I or Q).
We refrained from displaying the pulses with their iq_frequency to prevent confusion.
Similarly, it is not necessary to initialize the virtual awg with a channel for each I and Q. Whether two physical channels are needed to generate the desired output is determined automatically by the load script (see below).
End of explanation
vawg = VirtAWG.VirtualAWG(testsample, channels=2) #Initialize with two channels channel (number is arbitrary)
vawg.set_sequence(my_sequence, channel=1, t=time) # set my_sequence (T1 measurement) on channel 1
vawg.set_sequence(spinecho, channel=2, t=time) # set spinecho on channel 2
vawg.plot()
Explanation: If you are satisfied with the results, load the sequences onto your physical device with:
<br>vawg.load() <br>
Currently, this is only enabled for the tabor awg.
Multi-channel virtual AWG
This feature enables the user to run multiple sequences on different channels at the same time. <br>
The readout of each sequence is used to synchronize the channels (i.e. it is expected that the readout happens simultaneously).
End of explanation
<END_TASK>