Skip to content

Commit

Permalink
Bug fixes and working towards automated X-Gate calibration.
Browse files Browse the repository at this point in the history
  • Loading branch information
PP501 committed May 21, 2024
1 parent 2e7b149 commit 206938a
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 5 deletions.
7 changes: 4 additions & 3 deletions sqdtoolz/Experiments/Experimental/ExpCalibXrot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqdtoolz.Experiments.Experimental.ExpCalibGE import*

class ExpCalibXrot(Experiment):
def __init__(self, name, expt_config, wfmt_qubit_drive, SPEC_qubit, rotDenom, numPeriods=4, iq_indices = [0,1], **kwargs):
def __init__(self, name, expt_config, wfmt_qubit_drive, SPEC_qubit, rotDenom, numPeriods=4, numPeriodsStep=1, iq_indices = [0,1], **kwargs):
#This assumes that Pi-X and frequency (i.e. Ramsey) have been reasonably calibrated...
#Rotation angle is np.pi / rotDenom

Expand All @@ -16,6 +16,7 @@ def __init__(self, name, expt_config, wfmt_qubit_drive, SPEC_qubit, rotDenom, nu

self._rotDenom = rotDenom
self._numTotalRepeats = numPeriods * self._rotDenom * 2
self._numPeriodsStep = numPeriodsStep

# self._range_amps = kwargs.get('range_amps', None)
self._post_processor = kwargs.get('post_processor', None)
Expand Down Expand Up @@ -64,7 +65,7 @@ def _run(self, file_path, sweep_vars=[], **kwargs):
wfm.set_digital_segments('readout', 'qubit', ['read'])
self._temp_vars = self._expt_config.update_waveforms(wfm, [('Num Pulses', wfm.get_waveform_segment('qubit', 'drivePulses'), 'NumRepeats')] )

sweep_vars = [(self._temp_vars[0], np.arange(0,self._numTotalRepeats+1))]
sweep_vars = [(self._temp_vars[0], np.arange(0,self._numTotalRepeats+1, self._numPeriodsStep))]

kwargs['skip_init_instruments'] = True

Expand All @@ -90,7 +91,7 @@ def _post_process(self, data):
data_y = self.norm_expt.normalise_data(data_raw_IQ, ax=axs[1])

# dpkt = dfit.get_fitted_plot(data_x, data_y, 'Drive Amplitude', 'IQ Amplitude', fig, axs[0])
x_vals = np.arange(0,self._numTotalRepeats+1)
x_vals = np.arange(0,self._numTotalRepeats+1, self._numPeriodsStep)
axs[0].plot(x_vals, data_y, 'kx')
axs[0].set_xlabel('Number of Pulses'); axs[0].set_ylabel('Normalised Population')
axs[0].grid(visible=True, which='minor'); axs[0].grid(visible=True, which='major', color='k');
Expand Down
126 changes: 126 additions & 0 deletions sqdtoolz/Experiments/Experimental/ExpCalibXrotAuto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import numpy as np
from sqdtoolz.Experiment import *
from sqdtoolz.Variable import VariablePropertyTransient
from sqdtoolz.HAL.WaveformGeneric import *
from sqdtoolz.HAL.WaveformSegments import *
from sqdtoolz.Utilities.DataFitting import *
from sqdtoolz.Experiments.Experimental.ExpCalibGE import *
from sqdtoolz.Utilities.QubitGates import QubitGatesBase

import matplotlib.pyplot as plt
import scipy.interpolate
import scipy.optimize
from sqdtoolz.Utilities.Miscellaneous import Miscellaneous

class ExpCalibXrotAuto(Experiment):
def __init__(self, name, expt_config, qubit_gate_obj, gate_calib, ampl_offsets, num_samples, sample_skip_step=1, **kwargs):
super().__init__(name, expt_config)

# assert isinstance(qubit_gate_obj, QubitGatesBase), "qubit_gate_obj must be a QubitGates object (e.g. TransmonGates)"
self._qubit_gate_obj = qubit_gate_obj

if gate_calib == 'X':
self._samples = np.arange(0, num_samples*2, 2)*sample_skip_step
elif gate_calib == 'X/2':
self._samples = np.arange(0, num_samples*sample_skip_step, sample_skip_step)*2+1
else:
assert False, "gate_calib must be: 'X' or 'X/2'"
self._ampl_offsets = ampl_offsets

#Calculate default load time via T1 of qubit or default to 80e-6
def_load_time = self._qubit_gate_obj.get_qubit_SPEC()['GE T1'].Value * 6
if def_load_time == 0:
def_load_time = 80e-6
#Override the load-time if one is specified explicitly
self.load_time = kwargs.get('load_time', def_load_time)

self.readout_time = kwargs.get('readout_time', 2e-6)

self.normalise_reps = kwargs.get('normalise_reps', 10)

self._gate_calib = gate_calib
self._sweep_range = kwargs.get('sweep_range', (-0.5,0.5))

def _run(self, file_path, sweep_vars=[], **kwargs):
assert len(sweep_vars) == 0, "Cannot specify sweeping variables in this experiment."

self._setup_progress_bar(**kwargs)
self._expt_config.init_instruments()

data_file = FileIOWriter(file_path + 'data.h5')
varAmpl = VariableInternalTransient('AmplValue')
varNumG = VariableInternalTransient('NumGates')

self._qubit_gate_obj.calib_normalisation(self._expt_config, self.load_time, self.readout_time, file_path)
self._file_path = file_path

origAmplX = self._qubit_gate_obj.get_qubit_SPEC()['GE X-Gate Amplitude'].Value
origAmplXon2 = self._qubit_gate_obj.get_qubit_SPEC()['GE X/2-Gate Amplitude'].Value

for m, ampl_off in enumerate(self._ampl_offsets):
if self._gate_calib == 'X':
cur_gate = 'X'
self._qubit_gate_obj.get_qubit_SPEC()['GE X-Gate Amplitude'].Value = origAmplX + ampl_off
elif self._gate_calib == 'X/2':
cur_gate = 'X/2'
self._qubit_gate_obj.get_qubit_SPEC()['GE X/2-Gate Amplitude'].Value = origAmplXon2 + ampl_off

for g in self._samples:
cur_seq = [cur_gate]*g
final_data = self._qubit_gate_obj.run_circuit(cur_seq, self._expt_config, self.load_time, self.readout_time)
data_file.push_datapkt(final_data, [(varAmpl, self._ampl_offsets), (varNumG, self._samples)])
self._update_progress_bar((m+1)/self._ampl_offsets.size)
data_file.close()

self._qubit_gate_obj.get_qubit_SPEC()['GE X-Gate Amplitude'].Value = origAmplX
self._qubit_gate_obj.get_qubit_SPEC()['GE X/2-Gate Amplitude'].Value = origAmplXon2

self.file_io_read_calib = FileIOReader(file_path + 'dataCalib.h5')

return FileIOReader(file_path + 'data.h5')

def _post_process(self, data):
arr = data.get_numpy_array()
probs = [self._qubit_gate_obj.normalise_data(x) for x in arr]

sds = [np.std(y) for y in probs]

fig, ax = plt.subplots(ncols=3); fig.set_figwidth(18); ax[1].grid(); ax[2].grid()

leSpline = scipy.interpolate.UnivariateSpline(self._ampl_offsets, sds, k=2)
leSpline.set_smoothing_factor(np.mean(np.diff(self._ampl_offsets)*2))
fitX = np.linspace(self._ampl_offsets[0], self._ampl_offsets[-1], 50)

sol = scipy.optimize.minimize(leSpline, np.mean(self._ampl_offsets))

ax[0].pcolormesh(self._samples, self._ampl_offsets, probs)
ax[0].set_xlabel('Number of Gates')
ax[0].set_ylabel('Amplitude Offset')
ax[0].set_title('Ex. Population (should be flat)')

for cur_pops in probs:
ax[1].plot(self._samples, cur_pops, 'x-')
ax[1].legend([Miscellaneous.get_units(x) for x in self._ampl_offsets])
ax[1].set_xlabel('Number of Gates')
ax[1].set_ylabel('Excited State Population')
ax[1].set_title('Population traces over gate count')

ax[2].plot(fitX, leSpline(fitX), 'k')
ax[2].plot(self._ampl_offsets, sds)
ax[2].plot(sol.x, leSpline(sol.x), 'x')
ax[2].set_xlabel('Amplitude Offset')
ax[2].set_ylabel('SD in population')
ax[2].set_title('Optimising Amplitude Offset')

fig.show()
fig.savefig(self._file_path + 'Fitted Parameters.png')

self._opt_val = sol.x[0]

return data

def commit_to_SPEC(self):
if self._gate_calib == 'X':
self._qubit_gate_obj.get_qubit_SPEC()['GE X-Gate Amplitude'].Value += self._opt_val
elif self._gate_calib == 'X/2':
self._qubit_gate_obj.get_qubit_SPEC()['GE X/2-Gate Amplitude'].Value += self._opt_val
2 changes: 1 addition & 1 deletion sqdtoolz/Experiments/Experimental/ExpGateBenchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def _run(self, file_path, sweep_vars=[], **kwargs):
final_data = self._qubit_gate_obj.run_circuit(cur_seq, self._expt_config, self.load_time, self.readout_time)
data_file.push_datapkt(final_data, [(varTrial, np.arange(len(self._gate_seqs)))])
all_seqs[m] = cur_seq
self._update_progress_bar(m+1)/len(self._gate_seqs)
self._update_progress_bar((m+1)/len(self._gate_seqs))
with open(file_path + 'Benchmark_Sequences.json', 'w') as outfile:
json.dump(all_seqs, outfile, indent=4)
data_file.close()
Expand Down
2 changes: 1 addition & 1 deletion sqdtoolz/Utilities/QubitGates.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def calib_normalisation(self, expt_config, load_time, readout_time, file_path =

def normalise_data(self, data):
#data given as Nx2 array of N IQ-values...
return self.norm_calib(data)
return self.norm_calib.normalise_data(data)

def get_qubit_SPEC(self):
return self._spec_qubit
Expand Down

0 comments on commit 206938a

Please sign in to comment.