-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/two fixed transmons qua (#250)
* init * rename_renumber_files_tree * adopted to the simple qua config * Working in 08_ramsey_chevron * finished_08_ramsey_chevron * ro_freq_opt * 09b_ro_opt_amp_finished * up_to_ro_weights * iq_blobs_ready * coherent_done * stark_drag_done * revised for Two-Fixed-Transmons * added a parameter for phase correction * end of allxy, RB, interleaved BR * removed a line * added CNOT * end of allxy, RB, interleaved BR * tested until 13 -> WIP 14_drag * all-cross-resonance_runs * opx_configuration_pass_execution * configuration_lf_fem_validated * configuration_with_octave - opx and lf * applied black * applied black * applied black --------- Co-authored-by: HiroQM <[email protected]>
- Loading branch information
Showing
119 changed files
with
11,845 additions
and
422 deletions.
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
Quantum-Control-Applications/Superconducting/Two-Fixed-Coupled-Transmons/00_hello_qua.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" | ||
A simple sandbox to showcase different QUA functionalities during the installation. | ||
""" | ||
|
||
from qm.qua import * | ||
from qm import QuantumMachinesManager, SimulationConfig | ||
from configuration_lf_fem_and_octave import * | ||
|
||
################### | ||
# QUA Program # | ||
################### | ||
|
||
with program() as PROGRAM: | ||
|
||
play("cw", "rr1") | ||
play("cw", "q2_xy") | ||
|
||
##################################### | ||
# Open Communication with the QOP # | ||
##################################### | ||
qmm = QuantumMachinesManager(host=qop_ip, port=qop_port, cluster_name=cluster_name, octave=octave_config) | ||
|
||
########################### | ||
# Run or Simulate Program # | ||
########################### | ||
|
||
simulate = False | ||
|
||
if simulate: | ||
# Simulates the QUA program for the specified duration | ||
simulation_config = SimulationConfig(duration=1_000) # In clock cycles = 4ns | ||
# Simulate blocks python until the simulation is done | ||
|
||
job = qmm.simulate(config, PROGRAM, simulation_config) | ||
# Plot the simulated samples | ||
job.get_simulated_samples().con1.plot() | ||
|
||
else: | ||
# Open a quantum machine to execute the QUA program | ||
qm = qmm.open_qm(config) | ||
|
||
# Send the QUA program to the OPX, which compiles and executes it - Execute does not block python! | ||
job = qm.execute(PROGRAM) |
147 changes: 147 additions & 0 deletions
147
...tum-Control-Applications/Superconducting/Two-Fixed-Coupled-Transmons/01_time_of_flight.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
""" | ||
TIME OF FLIGHT | ||
This sequence involves sending a readout pulse and capturing the raw ADC traces. | ||
The data undergoes post-processing to calibrate three distinct parameters: | ||
- Time of Flight: This represents the internal processing time and the propagation delay of the readout pulse. | ||
Its value can be adjusted in the configuration under "time_of_flight". | ||
This value is utilized to offset the acquisition window relative to when the readout pulse is dispatched. | ||
- Analog Inputs Offset: Due to minor impedance mismatches, the signals captured by the OPX might exhibit slight offsets. | ||
These can be rectified in the configuration at: config/controllers/"con1"/analog_inputs, enhancing the demodulation process. | ||
- Analog Inputs Gain: If a signal is constrained by digitization or if it saturates the ADC, | ||
the variable gain of the OPX analog input can be modified to fit the signal within the ADC range of +/-0.5V. | ||
This gain, ranging from -12 dB to 20 dB, can also be adjusted in the configuration at: config/controllers/"con1"/analog_inputs. | ||
""" | ||
|
||
from qm.qua import * | ||
from qm import QuantumMachinesManager, SimulationConfig | ||
from qm import SimulationConfig | ||
|
||
from configuration_mw_fem import * | ||
import matplotlib.pyplot as plt | ||
from scipy.signal import savgol_filter | ||
from qualang_tools.results.data_handler import DataHandler | ||
|
||
################## | ||
# Parameters # | ||
################## | ||
|
||
n_avg = 5000 # The number of averages | ||
save_data_dict = { | ||
"n_avg": n_avg, | ||
"config": config, | ||
} | ||
|
||
################### | ||
# QUA Program # | ||
################### | ||
|
||
with program() as PROGRAM: | ||
n = declare(int) # QUA variable for the averaging loop | ||
adc_st = declare_stream(adc_trace=True) # The stream to store the raw ADC trace | ||
|
||
# # OPTIONAL to check time-of-flight at arbitrary frequency | ||
# update_frequency('q1_rr', 100e6) | ||
|
||
with for_(n, 0, n < n_avg, n + 1): | ||
# Reset the phase of the digital oscillator associated to the resonator element. Needed to average the cosine signal. | ||
reset_if_phase("rr1") | ||
reset_if_phase("rr2") | ||
# Sends the readout pulse and stores the raw ADC traces in the stream called "adc_st" | ||
measure("readout", "rr1", adc_st) | ||
measure("readout", "rr2", None) | ||
# Wait for the resonators to empty | ||
wait(depletion_time * u.ns, "rr1") | ||
wait(depletion_time * u.ns, "rr2") | ||
|
||
with stream_processing(): | ||
# Will save average: | ||
adc_st.input1().average().save("adc1") | ||
# # Will save only last run: | ||
adc_st.input1().save("adc1_single_run") | ||
|
||
|
||
##################################### | ||
# Open Communication with the QOP # | ||
##################################### | ||
qmm = QuantumMachinesManager(host=qop_ip, port=qop_port, cluster_name=cluster_name, octave=octave_config) | ||
|
||
########################### | ||
# Run or Simulate Program # | ||
########################### | ||
|
||
simulate = False | ||
|
||
if simulate: | ||
# Simulates the QUA program for the specified duration | ||
simulation_config = SimulationConfig(duration=1_000) # In clock cycles = 4ns | ||
# Simulate blocks python until the simulation is done | ||
job = qmm.simulate(config, PROGRAM, simulation_config) | ||
# Plot the simulated samples | ||
job.get_simulated_samples().con1.plot() | ||
|
||
else: | ||
try: | ||
# Open a quantum machine to execute the QUA program | ||
qm = qmm.open_qm(config) | ||
# Send the QUA program to the OPX, which compiles and executes it | ||
job = qm.execute(PROGRAM) | ||
# Creates a result handle to fetch data from the OPX | ||
res_handles = job.result_handles | ||
# Waits (blocks the Python console) until all results have been acquired | ||
res_handles.wait_for_all_values() | ||
# Fetch the raw ADC traces and convert them into Volts | ||
adc1 = u.raw2volts(res_handles.get("adc1").fetch_all()) | ||
adc1_single_run = u.raw2volts(res_handles.get("adc1_single_run").fetch_all()) | ||
|
||
save_data_dict["adc1"] = adc1 | ||
save_data_dict["adc1_single"] = adc1_single_run | ||
|
||
# Derive the average values | ||
adc1_mean = np.mean(adc1) | ||
# Remove the average values | ||
adc1_unbiased = adc1 - np.mean(adc1) | ||
# Filter the data to get the pulse arrival time | ||
signal = savgol_filter(np.abs(adc1_unbiased), 11, 3) | ||
# Detect the arrival of the readout signal | ||
th = (np.mean(signal[:100]) + np.mean(signal[:-100])) / 2 | ||
delay = np.where(signal > th)[0][0] | ||
|
||
# Plot data for each rl | ||
fig = plt.figure(figsize=(12, 6)) | ||
|
||
# Plot for single run | ||
plt.subplot(121) | ||
plt.title("Single run") | ||
plt.plot(adc1_single_run.real, label="Input 1 real") | ||
plt.plot(adc1_single_run.imag, label="Input 1 image") | ||
plt.axhline(y=0) | ||
plt.xlabel("Time [ns]") | ||
plt.ylabel("Signal amplitude [V]") | ||
plt.legend() | ||
|
||
# Plot for averaged run | ||
plt.subplot(122) | ||
plt.title("Averaged run") | ||
plt.plot(adc1.real, label="Input 1 real") | ||
plt.plot(adc1.imag, label="Input 1 imag") | ||
plt.axhline(y=0) | ||
plt.xlabel("Time [ns]") | ||
plt.legend() | ||
plt.tight_layout() | ||
|
||
# Save results | ||
script_name = Path(__file__).name | ||
data_handler = DataHandler(root_data_folder=save_dir) | ||
save_data_dict.update({"fig_live": fig}) | ||
data_handler.additional_files = {script_name: script_name, **default_additional_files} | ||
data_handler.save_data(data=save_data_dict, name="time_of_flight") | ||
|
||
except Exception as e: | ||
print(f"An exception occurred: {e}") | ||
|
||
finally: | ||
qm.close() | ||
print("Experiment QM is now closed") | ||
plt.show() |
143 changes: 143 additions & 0 deletions
143
...lications/Superconducting/Two-Fixed-Coupled-Transmons/02_resonator_spectroscopy_single.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
""" | ||
RESONATOR SPECTROSCOPY INDIVIDUAL RESONATORS | ||
This sequence involves measuring the resonator by sending a readout pulse and demodulating the signals to extract the | ||
'I' and 'Q' quadratures across varying readout intermediate frequencies. | ||
The data is then post-processed to determine the resonator resonance frequency. | ||
This frequency can be used to update the readout intermediate frequency in the configuration under "resonator_IF". | ||
Prerequisites: | ||
- Ensure calibration of the time of flight, offsets, and gains (referenced as "time_of_flight"). | ||
- Calibrate the IQ mixer connected to the readout line (whether it's an external mixer or an Octave port). | ||
- Define the readout pulse amplitude and duration in the configuration. | ||
- Specify the expected resonator depletion time in the configuration. | ||
Before proceeding to the next node: | ||
- Update the readout frequency, labeled as "resonator_IF_q1" and "resonator_IF_q2", in the configuration. | ||
""" | ||
|
||
from qm.qua import * | ||
from qm import QuantumMachinesManager, SimulationConfig | ||
from configuration_mw_fem import * | ||
from qualang_tools.results import fetching_tool | ||
from qualang_tools.loops import from_array | ||
import matplotlib.pyplot as plt | ||
from scipy import signal | ||
from qualang_tools.results.data_handler import DataHandler | ||
|
||
################## | ||
# Parameters # | ||
################## | ||
|
||
resonator = "rr1" | ||
resonator_LO = resonator_LO | ||
|
||
n_avg = 200 # The number of averages | ||
frequencies = { | ||
"rr1": np.arange(-50e6, +50e6, 100e3), | ||
"rr2": np.arange(-50e6, +50e6, 100e3), | ||
} | ||
|
||
save_data_dict = { | ||
"resonator": resonator, | ||
"resonator_LO": resonator_LO, | ||
"frequencies": frequencies, | ||
"n_avg": n_avg, | ||
"config": config, | ||
} | ||
|
||
################### | ||
# QUA Program # | ||
################### | ||
|
||
with program() as PROGRAM: | ||
n = declare(int) # QUA variable for the averaging loop | ||
f = declare(int) # QUA variable for the readout frequency --> Hz int 32 up to 2^32 | ||
I = declare(fixed) # QUA variable for the measured 'I' quadrature --> signed 4.28 [-8, 8) | ||
Q = declare(fixed) # QUA variable for the measured 'Q' quadrature --> signed 4.28 [-8, 8) | ||
I_st = declare_stream() # Stream for the 'I' quadrature | ||
Q_st = declare_stream() # Stream for the 'Q' quadrature | ||
n_st = declare_stream() # Stream for the averaging iteration 'n' | ||
|
||
with for_(n, 0, n < n_avg, n + 1): # QUA for_ loop for averaging | ||
with for_(*from_array(f, frequencies[resonator])): # QUA for_ loop for sweeping the frequency | ||
# Update the frequency of the digital oscillator linked to the resonator element | ||
update_frequency(resonator, f) | ||
# Measure the resonator (send a readout pulse and demodulate the signals to get the 'I' & 'Q' quadratures) | ||
measure( | ||
"readout" * amp(1), | ||
resonator, | ||
None, | ||
dual_demod.full("cos", "sin", I), | ||
dual_demod.full("minus_sin", "cos", Q), | ||
) | ||
# Wait for the resonator to deplete | ||
wait(depletion_time * u.ns, resonator) | ||
# Save the 'I' & 'Q' quadratures to their respective streams | ||
save(I, I_st) | ||
save(Q, Q_st) | ||
|
||
with stream_processing(): | ||
# Cast the data into a 1D vector, average the 1D vectors together and store the results on the OPX processor | ||
I_st.buffer(len(frequencies[resonator])).average().save("I") | ||
Q_st.buffer(len(frequencies[resonator])).average().save("Q") | ||
|
||
##################################### | ||
# Open Communication with the QOP # | ||
##################################### | ||
qmm = QuantumMachinesManager(host=qop_ip, port=qop_port, cluster_name=cluster_name, octave=octave_config) | ||
|
||
####################### | ||
# Simulate or execute # | ||
####################### | ||
simulate = False | ||
|
||
if simulate: | ||
# Simulates the QUA program for the specified duration | ||
simulation_config = SimulationConfig(duration=1_000) # In clock cycles = 4ns | ||
# Simulate blocks python until the simulation is done | ||
job = qmm.simulate(config, PROGRAM, simulation_config) | ||
# Plot the simulated samples | ||
job.get_simulated_samples().con1.plot() | ||
plt.show(block=False) | ||
else: | ||
try: | ||
# Open a quantum machine to execute the QUA program | ||
qm = qmm.open_qm(config) | ||
# Send the QUA program to the OPX, which compiles and executes it | ||
job = qm.execute(PROGRAM) | ||
# Get results from QUA program | ||
results = fetching_tool(job, data_list=["I", "Q"]) # this one already waits for all values | ||
# plotting | ||
fig = plt.figure() | ||
I, Q = results.fetch_all() | ||
# Convert results into Volts | ||
S = I + 1j * Q | ||
R = np.abs(S) # Amplitude | ||
phase = np.angle(S) # Phase | ||
plt.suptitle(f"Resonator spectroscopy for {resonator} - LO = {resonator_LO / u.GHz} GHz") | ||
ax1 = plt.subplot(211) | ||
plt.plot((frequencies[resonator]) / u.MHz, R, ".") | ||
plt.ylabel(r"$R=\sqrt{I^2 + Q^2}$ [V]") | ||
plt.subplot(212, sharex=ax1) | ||
plt.plot((frequencies[resonator]) / u.MHz, signal.detrend(np.unwrap(phase)), ".") | ||
plt.xlabel("Intermediate frequency [MHz]") | ||
plt.ylabel("Phase [rad]") | ||
plt.tight_layout() | ||
|
||
save_data_dict[resonator + "_I"] = I | ||
save_data_dict[resonator + "_Q"] = Q | ||
|
||
# Save results | ||
script_name = Path(__file__).name | ||
data_handler = DataHandler(root_data_folder=save_dir) | ||
save_data_dict.update({"fig_live": fig}) | ||
data_handler.additional_files = {script_name: script_name, **default_additional_files} | ||
data_handler.save_data(data=save_data_dict, name="resonator_spectroscopy_single") | ||
|
||
except Exception as e: | ||
print(f"An exception occurred: {e}") | ||
|
||
finally: | ||
qm.close() | ||
print("Experiment QM is now closed") | ||
plt.show(block=True) |
Oops, something went wrong.