Closed 4dri8 closed 7 months ago
I am here interceding because I have been made aware of this problem.
WAIT SYNC (to trigger SYNQ) IS A NON-NEGOTIABLE MUST. Please lets have a meeting to ensure this is properly addressed.
Hello @4dri8 and @rsagas. Thank you for raising this. This kind of detail in bug reporting is exactly what we want in order to be able to investigate more.
First of all, are you using main
branch or the development branch of QProgram? Several issues that we found the last two weeks are resolved there.
In that branch, the play
operation has an extra parameter wait_time
to override the default wait time that is the duration of the pulse. So in order to measure with a time of flight you can do:
qp.play(bus=f"readout_bus_{QUBIT_IDX}", waveform=square_wf, wait_time=time_of_flight) # Executing the Square pulse
qp.acquire(bus=f"readout_bus_{QUBIT_IDX}", weights=ql.IQPair(I=weights_shape, Q=weights_shape)) # Measuring
In general, using QProgram, all play
instructions wait for the whole pulse, so there is no need to add an additional wait
instruction afterwards. You are doing
qp.play(bus=f"drive_q{QUBIT_IDX}_bus", waveform=drag)
qp.wait(bus=f"readout_bus_{QUBIT_IDX}",duration=DRAG_DURATION)
and this adds DRAG_DURATION
nanoseconds on top of the duration of the drag
waveform.
Also, all buses are synchronized at the beginning of each loop iteration, so there is no point of having a sync()
there. The sync()
should be between the drive pulse and the readout pulse to enforce the second to begin right after the first.
My recommended way of writing the RABI would be:
time_of_flight = 120
qp = ql.QProgram()
# Defining the variable Frequency for the driving pulse
amplitude = qp.variable(ql.Domain.Voltage) # Just for the renormalization for the Q1ASM
with qp.average(HW_AVG):
# Loop over all frequencies
with qp.for_loop(variable=amplitude, start=AMP_VALUES[0], stop=AMP_VALUES[-1], step=AMP_VALUES[1]-AMP_VALUES[0]):
qp.set_gain(bus=f"drive_q{QUBIT_IDX}_bus", gain=amplitude)
# play the drive pulse
qp.play(bus=f"drive_q{QUBIT_IDX}_bus", waveform=drag)
# sync the two buses
qp.sync()
# wait for some time
qp.wait(bus=f"readout_bus_{QUBIT_IDX}",duration=BUFFER_TIME)
# start measuring by playing the readout pulse and only wait for a time_of_flight duration
qp.play(bus=f"readout_bus_{QUBIT_IDX}", waveform=square_wf, wait_time=time_of_flight)
# acquire results
qp.acquire(bus=f"readout_bus_{QUBIT_IDX}", weights=ql.IQPair(I=weights_shape, Q=weights_shape))
# wait qubit to relax. In the next loop iteration buses will be in sync.
qp.wait(bus=f"readout_bus_{QUBIT_IDX}",duration=REPETITION_DURATION)
Hi @4dri8
main
by the end of the week.
I have tried running your code, adding the definitions of drag
, QUBIT_IDX
and so on. The full code looks like this for me:
import numpy as np
import qililab as ql
from qililab.qprogram.blocks import Block
from qpysequence.utils.constants import AWG_MAX_GAIN, INST_MAX_WAIT
from qililab.qprogram.operations import *
from qililab.qprogram import QbloxCompiler
from qililab.waveforms import DragPair
import numpy as np
platform_name = "/home/victor/qililab/examples/runcards/galadriel.yml" platform = ql.build_platform(runcard=platform_name)
QUBIT_IDX = 0 AMP_VALUES = np.arange(10,20,1) HW_AVG = 10 qp = ql.QProgram() REPETITION_DURATION = 100
amplitude = qp.variable(ql.Domain.Voltage) # Just for the renormalization for the Q1ASM DRAG_DURATION = platform.get_parameter(parameter = ql.Parameter.DURATION, alias=f"Drag({QUBIT_IDX})") drag = DragPair( amplitude=platform.get_parameter(parameter = ql.Parameter.AMPLITUDE, alias=f"Drag({QUBIT_IDX})"), duration=DRAG_DURATION, num_sigmas=platform.get_parameter(parameter = ql.Parameter.NUM_SIGMAS, alias=f"Drag({QUBIT_IDX})"), drag_coefficient=platform.get_parameter(parameter = ql.Parameter.DRAG_COEFFICIENT, alias=f"Drag({QUBIT_IDX})")) t = platform.get_parameter(parameter=ql.Parameter.DURATION, alias=f"M({QUBIT_IDX})") weights = ql.Square(amplitude=1, duration=t) square_wf = waveform=ql.Square( amplitude=platform.get_parameter(parameter=ql.Parameter.AMPLITUDE, alias=f"M({QUBIT_IDX})"), duration=t)
with qp.average(HW_AVG):
with qp.for_loop(variable=amplitude, start=AMP_VALUES[0], stop=AMP_VALUES[-1], step=AMP_VALUES[1]-AMP_VALUES[0]):
qp.set_gain(bus=f"drive_q{QUBIT_IDX}_bus", gain=amplitude)
qp.wait(bus=f"feedline_bus",duration=REPETITION_DURATION)
qp.sync()
qp.play(bus=f"drive_q{QUBIT_IDX}_bus", waveform=drag)
qp.wait(bus=f"feedline_bus",duration=DRAG_DURATION)
qp.play(bus=f"feedline_bus", waveform=square_wf) # Executing the Square pulse
qp.acquire(bus=f"feedline_bus", weights=ql.IQPair(I=weights, Q=weights)) # Measuring
qblox_compiler = QbloxCompiler() sequences = qblox_compiler.compile(qprogram=qp)
for _, sequence in sequences.items(): print(sequence._program)
*note that you don't need to connect to the instruments to run this
This outputs q1asm programs
setup: wait_sync 4
main:
move 10, R0
avg_0:
move 0, R1
move 0, R2
move 0, R3
move 10, R4
move 327670, R5
loop_0:
wait 100
wait 20
play 0, 1, 2000
acquire_weighed 0, R3, R2, R1, 2000
add R3, 1, R3
add R5, 32767, R5
loop R4, @loop_0
loop R0, @avg_0
stop
setup: wait_sync 4
main:
move 10, R0
avg_0:
move 10, R1
move 327670, R2
loop_0:
set_awg_gain R2, R2
wait 100
play 0, 1, 20
wait 4000
add R2, 32767, R2
loop R1, @loop_0
nop
loop R0, @avg_0
stop
tl;dr I dont see the extra 4ns that you're seeing.
Would you mind providing your full code + runcard, as well as the runcard you're running it from so I can try to reproduce it?
Hi guys, I want to have a meeting about this.
A while ago i spoke about MULTIDEVICE INSTRUCTIONS in QPysequence. It is the only scalable solution I know for this.
I am also very concerned about issues that I have written and have dissapeared (specifically the one relevant now, for multidevice instructions).
Could it be this one? https://github.com/qilimanjaro-tech/qililab/issues/74 Be mindful that compilation is already outside of the drivers (we changed this a few weeks ago) and it already supports compiling sequences for different QRMs / QCMs for the same program (and the extension to clusters should be quite straight forward)
We should definitely have a discussion about this though
It is not that PR. I searched in the repo, and it is the second time I cannot find an issue on a vision thing I wrote. Do you (team) erase issues ever if you feel they do not point to an action? Cause these ones were preventing issues that are only now coming up.
Anyhow, I do want to discuss the topic, it is about a QPYSEQUENCE improvement.
Hi @4dri8
- Regarding the long wait issue, we are aware of this and have a fix in
main
by the end of the week. I have tried running your code, adding the definitions ofdrag
,QUBIT_IDX
and so on. The full code looks like this for me:import numpy as np import qililab as ql from qililab.qprogram.blocks import Block from qpysequence.utils.constants import AWG_MAX_GAIN, INST_MAX_WAIT from qililab.qprogram.operations import * from qililab.qprogram import QbloxCompiler from qililab.waveforms import DragPair import numpy as np platform_name = "/home/victor/qililab/examples/runcards/galadriel.yml" platform = ql.build_platform(runcard=platform_name) #QProgram used QUBIT_IDX = 0 AMP_VALUES = np.arange(10,20,1) HW_AVG = 10 qp = ql.QProgram() REPETITION_DURATION = 100 # Defining the variable Frequency for the driving pulse amplitude = qp.variable(ql.Domain.Voltage) # Just for the renormalization for the Q1ASM DRAG_DURATION = platform.get_parameter(parameter = ql.Parameter.DURATION, alias=f"Drag({QUBIT_IDX})") drag = DragPair( amplitude=platform.get_parameter(parameter = ql.Parameter.AMPLITUDE, alias=f"Drag({QUBIT_IDX})"), duration=DRAG_DURATION, num_sigmas=platform.get_parameter(parameter = ql.Parameter.NUM_SIGMAS, alias=f"Drag({QUBIT_IDX})"), drag_coefficient=platform.get_parameter(parameter = ql.Parameter.DRAG_COEFFICIENT, alias=f"Drag({QUBIT_IDX})")) t = platform.get_parameter(parameter=ql.Parameter.DURATION, alias=f"M({QUBIT_IDX})") weights = ql.Square(amplitude=1, duration=t) square_wf = waveform=ql.Square( amplitude=platform.get_parameter(parameter=ql.Parameter.AMPLITUDE, alias=f"M({QUBIT_IDX})"), duration=t) with qp.average(HW_AVG): # Loop over all frequencies with qp.for_loop(variable=amplitude, start=AMP_VALUES[0], stop=AMP_VALUES[-1], step=AMP_VALUES[1]-AMP_VALUES[0]): qp.set_gain(bus=f"drive_q{QUBIT_IDX}_bus", gain=amplitude) qp.wait(bus=f"feedline_bus",duration=REPETITION_DURATION) qp.sync() qp.play(bus=f"drive_q{QUBIT_IDX}_bus", waveform=drag) qp.wait(bus=f"feedline_bus",duration=DRAG_DURATION) qp.play(bus=f"feedline_bus", waveform=square_wf) # Executing the Square pulse qp.acquire(bus=f"feedline_bus", weights=ql.IQPair(I=weights, Q=weights)) # Measuring qblox_compiler = QbloxCompiler() sequences = qblox_compiler.compile(qprogram=qp) for _, sequence in sequences.items(): print(sequence._program)
*note that you don't need to connect to the instruments to run this This outputs q1asm programs
setup: wait_sync 4 main: move 10, R0 avg_0: move 0, R1 move 0, R2 move 0, R3 move 10, R4 move 327670, R5 loop_0: wait 100 wait 20 play 0, 1, 2000 acquire_weighed 0, R3, R2, R1, 2000 add R3, 1, R3 add R5, 32767, R5 loop R4, @loop_0 loop R0, @avg_0 stop setup: wait_sync 4 main: move 10, R0 avg_0: move 10, R1 move 327670, R2 loop_0: set_awg_gain R2, R2 wait 100 play 0, 1, 20 wait 4000 add R2, 32767, R2 loop R1, @loop_0 nop loop R0, @avg_0 stop
tl;dr I dont see the extra 4ns that you're seeing. Would you mind providing your full code + runcard, as well as the runcard you're running it from so I can try to reproduce it?
There are 16ns of delay from the qcm (there you have your Q1ASM with the timings), in the Q1ASM below you can see the timings of every instruction, in this way: "#absolute time (instruction time)"
setup:
wait_sync 4 #4ns (4)
main:
move 10, R0 #8ns (4)
avg_0:
move 0, R1 #12ns (4)
move 0, R2 #16ns (4)
move 0, R3 #20ns (4)
move 10, R4 #24ns (4)
move 327670, R5 #28ns (4)
loop_0:
wait 100 #128ns (100)
wait 20 #148ns (20)
play 0, 1, 2000 #152ns (should be 4, already solved)
acquire_weighed 0, R3, R2, R1, 2000 #2152ns (2000)
add R3, 1, R3 #2164ns (12)
add R5, 32767, R5 #2176ns (12)
loop R4, @loop_0
loop R0, @avg_0
stop
setup:
wait_sync 4 #4ns (4)
main:
move 10, R0 #8ns (4)
avg_0:
move 10, R1 #12ns (4)
move 327670, R2 #16ns (4)
loop_0:
set_awg_gain R2, R2 #24ns (8)
wait 100 #124ns (100)
play 0, 1, 20 #144ns (20)
wait 4000 #2148ns (should be 4 (qrm play)+2000(qrm acquire))
add R2, 32767, R2 #2160ns (12)
loop R1, @loop_0
nop
loop R0, @avg_0
stop
Hello @4dri8
The only instructions that add towards timings are play
, wait
and acquire
. These three instructions are run in the "real-time processor" of the sequencer. The rest of the instructions are run in "classical processor". A deeper explanation is given here: https://www.notion.so/qilimanjaro/Q1ASM-timing-d3bb142a450748209e57f2d585fc31f6
So in your example, timings would be:
setup:
wait_sync 4 #4ns (4)
main:
move 10, R0
avg_0:
move 0, R1
move 0, R2
move 0, R3
move 10, R4
move 327670, R5
loop_0:
wait 100 #104ns (100)
wait 20 #124ns (20)
play 0, 1, 4 #128ns (should be 4, already solved)
acquire_weighed 0, R3, R2, R1, 2000 #2128ns (2000)
add R3, 1, R3
add R5, 32767, R5
loop R4, @loop_0
loop R0, @avg_0
stop
setup:
wait_sync 4 #4ns (4)
main:
move 10, R0
avg_0:
move 10, R1
move 327670, R2
loop_0:
set_awg_gain R2, R2
wait 100 #104ns (100)
play 0, 1, 20 #124ns (20)
wait 2004 #2128ns (should be 4 (qrm play)+2000(qrm acquire))
add R2, 32767, R2
loop R1, @loop_0
nop
loop R0, @avg_0
stop
So at the end the two sequencers are in sync.
Then I cannot identify the problem, but I'm not being able to get a rabi with QProgram, even with the code I showed in the opening of the issue, I'm not able to reproduce it.
I just found an error in the code I was using, I assumed that, as qililab does, qprogram would assume that, if a parameter is not modified in the current code, it is equal to the value in the runcard, as for example frequencies, but this is not done for the amplitudes of the waveforms. Qililab gives all the waveforms' amplitudes equal to 1 and then these are modified in the Q1ASM to the actual value from the runcard, so I did the same with the readout, as I was not modifying it, I gave the amplitude of the readout as 1, and obviously that is too much power. After solving this, it seems to work fine. Sorry for not seeing this before.
Glad to hear it worked! I'll mark this as done then, and if anything else arises you can create a new issue.
Expected behavior
The modules should synchronize by using
QProgram().sync()
. Rabi taken from a well coordinated HW loop:Actual behavior
When trying to synchronize two modules, for example for a Rabi you need a QCM and a QRM, the
QProgram().sync()
is not adding the correctwait
instructions, as the times it is adding are not synchronizing correctly the two modules, you can measure, but on every iteration of the average, the QRM is 16ns behind, this results in a noisy measurement.As you can see below, the last timestamp written is just before the loop, and the QRM is 16ns later, this 16ns accumulate on every iteration, I thought about adding then 16ns of delay to the QCM, but by doing so the
QProgram().sync()
takes it into account and changes the waits again, so it stays behind.QCM Q1ASM
QRM Q1ASM
Rabi taken with this program (Yeah, still a rabi, but a lot noisier, same parameters and same qubit as the first one):
Additional information
There are other bugs to take into account when trying to reproduce this bug, in the
play
instruction on the QRM, there's extra wait time between play and acquire, this time should be the time of flight, but it is the waveform duration now, you can hardcode it to 200ns (more or less the tof) by now until it is solved.Another bug to take into account is that the 2040ns wait of the QCM Q1ASM is coded to be the duration of play+acquire time by the
QProgram().sync()
, and as it takes the waveform duration as the wait for theplay
instruction, it takes double the time it should. It should be just the duration of the readout (2000ns in this case).Source code
Tracebacks
No response
System Information
Existing GitHub issues