def init_MeasurementObject(self, reference_path, output_path, *, auto_init=False): ''' Initialise a Labber MeasurementObject instance. For more information on the MeasurementObject, see the Labber API docs. ''' ## debug message self.logger.log(LogLevels.VERBOSE, "Initialising MeasurementObject...") ## Check that the MeasurementObject has not already been initialised if self.MeasurementObject is not None: if not auto_init: ## This method has been called manually # warnings.warn("Labber MeasurementObject has already been initialised!", RuntimeWarning) self.logger.warning( 'Labber MeasurementObject has already been initialised!') return else: ## Initialise MeasurementObject self.MeasurementObject = ScriptTools.MeasurementObject(\ reference_path, output_path) ## debug message self.logger.debug("MeasurementObject initialised.")
def __init__(self, **kwargs): super().__init__(**kwargs) # Check to see if the template file has been saved in the DySART database; # if not, deserialize the .hdf5 on disk. if not self.template: self.deserialize_template() # Deprecated by Simon's changes to Labber API? self.config = st.MeasurementObject(self.template_file_path, self.output_file_path) self.log_history = LogHistory(self.id, conf.config['labber_data_dir'], os.path.split(self.output_file_path)[-1])
def RunMeasurement(ConfigName, MeasLabel, ItemDict={}, DataFolderName='Z:\Projects\Fluxonium\Data\\AugustusXVII', ConfigPath='', PrintOutFileName=False): # set path to executable ScriptTools.setExePath('C:\Program Files\Labber\Program') TimeNow = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') TimeStr = str(TimeNow) Year = TimeStr[:4] Month = TimeStr[5:7] Day = TimeStr[8:10] # define measurement objects # ConfigPath = 'C:\SC Lab\GitHubRepositories\measurement-with-labber\measurement setting/' DataPath = DataFolderName + '/' + Year + '/' + Month + '/' + 'Data_' + Month + Day + '/' if not os.path.exists(DataPath): os.makedirs(DataPath) ConfigFile = ConfigPath + ConfigName OutputFile = DataPath + MeasLabel + '_' + TimeStr if PrintOutFileName: print(MeasLabel + '_' + TimeStr) MeasObj = ScriptTools.MeasurementObject(ConfigFile, OutputFile) for item, value in ItemDict.items(): if type(value) is list: for subitem in value: MeasObj.updateValue(item, subitem[0], itemType=subitem[1]) else: MeasObj.updateValue(item, value) # if second_channel != '': # MeasObj.setMasterChannel(second_channel) MeasObj.performMeasurement(return_data=False) return [DataPath, MeasLabel + '_' + TimeStr + '.hdf5']
def tune(self, occupation_1, occupation_2, res=1e-3, calibrate_nr=3, plot=False): """ Finds the desired charge regime, given a reference point. Parameters ---------- occupation_1 : int desired charge occupation number for left dot occupation_2 : int desired charge occupation number for right dot res: float, optional default: 1e-3 Resolution with which frames are measured. calibrate_nr: int, optional default: 3 How often the QPC is calibrated. If calibrate_nr == 3, before measuring every third frame, the QPC is calibrated. plot: bool, optional default: False If True, all measurements taken are plotted. Returns ------- tuple PG1 & PG2 voltage """ # initialize variables self.occupation_1_f = occupation_1 self.occupation_2_f = occupation_2 # direction variable defines where the next frame is drawn # direction == 0: lower right corner (i.e. right) # direction == 1: upper right corner (i.e. top-right) # direction == 2: upper left corner (i.e. up) direction = 1 found = False reverse = False # if charge occupation too high, go back counter = 0 # length of path in frames print('Start tuning Charge States.') self.PG1['n_pts'] = self.f + 2 * self.p + 1 self.PG2['n_pts'] = self.f + 2 * self.p + 1 while not found: # define measurement variables self.PG1['stop'] = self.trans_path_x[-1] - (self.p + 0.5) * res self.PG1['start'] = self.trans_path_x[-1] + (self.f + self.p + 0.5) * res self.PG2['stop'] = self.trans_path_y[-1] - (self.p + 0.5) * res self.PG2['start'] = self.trans_path_y[-1] + (self.f + self.p + 0.5) * res # overwrite when necessary if reverse: if direction == 0: self.PG1['stop'] = self.trans_path_x[-1] - ( self.f + self.p + 0.5) * res self.PG1['start'] = self.trans_path_x[-1] + (self.p + 0.5) * res if direction == 2: self.PG2['stop'] = self.trans_path_y[-1] - ( self.f + self.p + 0.5) * res self.PG2['start'] = self.trans_path_y[-1] + (self.p + 0.5) * res # add starting point for plotting reasons self.trans_frame_start.append( (self.PG1['start'], self.PG2['start'])) # define mean PG values for QPC calibration self.PG2['mean'] = self.PG2['start'] + (self.PG2['stop'] - self.PG2['start']) / 2. self.PG1['mean'] = self.PG1['start'] + (self.PG1['stop'] - self.PG1['start']) / 2. # update charge occupation into list self.occupation.append((self.occupation_1, self.occupation_2)) # update path to take if direction == 0: if not reverse: self.trans_path_x.append(self.trans_path_x[-1] + self.f * res) self.trans_path_y.append(self.trans_path_y[-1]) else: self.trans_path_x.append(self.trans_path_x[-1] - self.f * res) self.trans_path_y.append(self.trans_path_y[-1]) elif direction == 1: if not reverse: self.trans_path_x.append(self.trans_path_x[-1] + self.f * res) self.trans_path_y.append(self.trans_path_y[-1] + self.f * res) else: # this is never True - just for completeness self.trans_path_x.append(self.trans_path_x[-1] - self.f * res) self.trans_path_y.append(self.trans_path_y[-1] - self.f * res) elif direction == 2: if not reverse: self.trans_path_x.append(self.trans_path_x[-1]) self.trans_path_y.append(self.trans_path_y[-1] + self.f * res) else: self.trans_path_x.append(self.trans_path_x[-1]) self.trans_path_y.append(self.trans_path_y[-1] - self.f * res) # Print path number and what points the path links print('\n###################\n' 'Path: {}\n' 'PG1: {} -> {}\n' 'PG2: {} -> {}'.format(counter, round(self.trans_path_x[-2], 3), round(self.trans_path_x[-1], 3), round(self.trans_path_y[-2], 3), round(self.trans_path_y[-1], 3))) # define measurement object output_path = os.path.join(self.path_out, 'tune_' + str(counter)) measurement = ScriptTools.MeasurementObject( self.path_in, output_path) # recalibrate QPC every calibrate_nr frames if counter % calibrate_nr == calibrate_nr - 1 or self.sweet_spot is None: calibrate = True gate_config = None else: calibrate = False gate_config = {self.gate_names['QPC_G']: self.sweet_spot} # get the measured QPC signal and reshape it measurement_signal = self.get_data_( measurement, output_path, DQD_log_channel=self.gate_names['I_DQD'], calibrate=calibrate, rescale=True, config=gate_config) self.trans_frames.append(measurement_signal['I_QPC']) I_DQD = measurement_signal['I_DQD'] reshaped_signal = self.trans_frames[-1].reshape( (1, self.f + 2 * self.p, self.f + 2 * self.p, 1)) # check whether there is a current through the dot, if so - abort # TODO introduce threshold as a variable if self.is_current_(I_DQD, 7e-12): print( 'There is too much current through the dot. Tuning stopped.\n' 'Last PG values:\n' 'PG1: {}\n' 'PG2: {}'.format(self.trans_path_x[-1], self.trans_path_y[-1])) break # Make the predictions # (QD1 transition, QD2 transition) # transition[i] == [1, 0, 0, 0]: (False, False) # transition[i] == [0, 1, 0, 0]: (False, True) # transition[i] == [0, 0, 1, 0]: (True, False) # transition[i] == [0, 0, 0, 1]: (True, True) # for i in {0, 1, 2} transition = self.trans_rec.predict(reshaped_signal) self.trans_classif.append(transition) # Check whether there is a contradiction. If there is one, # measure the same frame again and redo the classifications. is_contra = self.is_contradiction_(transition) if is_contra: print('There is a contradiction.\n' '{}'.format(transition)) # Remeasure the frame. self.trans_frames.append( self.get_data_(measurement, output_path, calibrate=calibrate, config=gate_config)['I_QPC']) # Redo the classifications reshaped_signal = self.trans_frames[-1].reshape( (1, self.f + 2 * self.p, self.f + 2 * self.p, 1)) transition = self.trans_rec.predict(reshaped_signal) # check again whether there is still a contradiction if self.is_contradiction_(transition): print('There is still a contradiction. Proceed anyways.') else: print( 'There is no contradiction anymore. Proceed as normal.' ) # plot the data if plot: pass # grid = plt.GridSpec(20, 20) # fig = plt.figure() # ax = plt.subplot(grid[:20, :20]) # axins1 = inset_axes(ax, # width="3%", # height="100%", # loc='lower left', # bbox_to_anchor=(1.01, 0., 1, 1), # bbox_transform=ax.transAxes, # borderpad=0, # ) # # im1 = ax.pcolormesh(self.trans_frames[-1][:, :], linewidth=0, rasterized=True) # cbar = fig.colorbar(im1, cax=axins1) # ax.axhline(y=self.p, color='black', linewidth=2) # ax.axhline(y=self.f+self.p, color='black', linewidth=2) # ax.axvline(x=self.p, color='black', linewidth=2) # ax.axvline(x=self.f+self.p, color='black', linewidth=2) # ax.plot(self.trans_path_x[-1], self.trans_path_y[-1]) # ax.set_ylim(0, self.f+2*self.p) # ax.set_xlim(0, self.f+2*self.p) # plt.title('Path {}'.format(counter)) # plt.show() # Trigger charge transitions if np.argmax(transition[direction]) == 0: # no transition at all print('No transition.\n' 'Confidence: {}\n' 'Current charge occupation({},{})'.format( np.max(transition[direction]), self.occupation_1, self.occupation_2)) elif np.argmax(transition[direction]) == 1: # transition in QD2 if not reverse: self.occupation_2 += 1 else: self.occupation_2 -= 1 print('Transition in QD2.\n' 'Confidence: {}\n' 'Current charge occupation({},{})'.format( np.max(transition[direction]), self.occupation_1, self.occupation_2)) elif np.argmax(transition[direction]) == 2: # transision in QD1 if not reverse: self.occupation_1 += 1 else: self.occupation_1 -= 1 print('Transition in QD1.\n' 'Confidence: {}\n' 'Current charge occupation({},{})'.format( np.max(transition[direction]), self.occupation_1, self.occupation_2)) elif np.argmax( transition[direction]) == 3: # transition in both QDs if not reverse: self.occupation_2 += 1 self.occupation_1 += 1 else: self.occupation_2 -= 1 self.occupation_1 -= 1 print('Transition in both QDs.\n' 'Confidence: {}\n' 'Current charge occupation({},{})'.format( np.max(transition[direction]), self.occupation_1, self.occupation_2)) # define where to go based on current charge occupation if self.occupation_1 < self.occupation_1_f and self.occupation_2 < self.occupation_2_f: direction = 1 reverse = False print('-> Going up right.') elif self.occupation_1 == self.occupation_1_f and self.occupation_2 < self.occupation_2_f: direction = 2 reverse = False print('-> Going up.') elif self.occupation_1 < self.occupation_1_f and self.occupation_2 == self.occupation_2_f: direction = 0 reverse = False print('-> Going right.') # go back, if one of the dots has too many electrons elif self.occupation_1 > self.occupation_1_f: direction = 0 reverse = True print('-> Going left.') elif self.occupation_2 > self.occupation_2_f: direction = 2 reverse = True print('-> Going down.') # Terminate if desired charge configuration is reached elif self.occupation_1 == self.occupation_1_f and self.occupation_2 == self.occupation_2_f: print('\nTuning successful\n' 'PG1: {}V\n' 'PG2: {}V'.format(self.trans_path_x[-1], self.trans_path_y[-1])) found = True if counter >= 15: print('Could not find desired charge configuration.\n' 'Program stopped.') found = True counter += 1
def find_reference(self, f, b, x_0, y_0, res=8e-3, calibrate_nr=3, confidence=0.7, plot=False): """ Finds a plunger gate voltage configuration for which the charge occupation is given as (0,0). That is, both dots are empty. This plunger gate voltage configuration can then be used as a reference point in the charge occupation tuning process. Needs a boundary for the plunger gate voltages from which a random starting point is chosen. Parameters ---------- f : int coarse frame size b : int coarse frame border x_0 : float starting point for PG1 from which a reference point is searched. y_0 : float starting point for PG2 from which a reference point is searched. res : float, optional default: 8e-3 coarse resolution in V calibrate_nr : int, optional default: 3 How often the QPC is calibrated. If calibrate_nr == 3, before measuring every third frame, the QPC is calibrated. confidence : float, optional default: 0.8 Determines the confidence threshold with which we recognize the empty region. plot: bool, optional default: False If True, a plot of every frame plus its convolution filters is made. Returns ------- float, float Voltage for PG1 and PG2 for which both quantum dots are unoccupied. """ found = False counter = 0 self.PG1['n_pts'] = f + b + 1 self.PG2['n_pts'] = f + b + 1 self.ref_path_x.append(x_0) self.ref_path_y.append(y_0) while not found: print('\n#####################' '\n Frame nr. {}'.format(counter + 1)) # update measurement information self.PG1['start'] = self.ref_path_x[-1] + (b + 0.5) * res self.PG1['stop'] = self.ref_path_x[-1] - (f + 0.5) * res self.PG1['mean'] = self.PG1['start'] + (self.PG1['stop'] - self.PG1['start']) / 2. self.PG2['start'] = self.ref_path_y[-1] + (b + 0.5) * res self.PG2['stop'] = self.ref_path_y[-1] - (f + 0.5) * res self.PG2['mean'] = self.PG2['start'] + (self.PG2['stop'] - self.PG2['start']) / 2. # define measurement object output_path = os.path.join(self.path_out, 'reference_' + str(counter)) measurement = ScriptTools.MeasurementObject( self.path_in, output_path) # recalibrate QPC every 3 frames if counter % calibrate_nr == 0 or self.sweet_spot is None: calibrate = True gate_config = None else: calibrate = False gate_config = {self.gate_names['QPC_G']: self.sweet_spot} # perform measurement / get data measurement_signal = self.get_data_( measurement, output_path, DQD_log_channel=self.gate_names['I_DQD'], calibrate=calibrate, rescale=False, config=gate_config) self.ref_frames.append(measurement_signal['I_QPC']) I_DQD = measurement_signal['I_DQD'] # reshape data in order to make it suitable for classifier reshaped_signal = self.ref_frames[-1].reshape((1, f + b, f + b, 1)) # predict occupation state occupation = self.occupation_ref_rec.predict(reshaped_signal)[0] self.ref_classif.append(occupation) print('Classification confidences:\n{}'.format(occupation)) print('PG1: {}V\n' 'PG2: {}V'.format(self.ref_path_x[-1], self.ref_path_y[-1])) counter += 1 # plot measurement and visualize filters if plot: grid = plt.GridSpec(20, 20) fig = plt.figure() ax = plt.subplot(grid[:20, :20]) axins1 = inset_axes( ax, width="3%", height="100%", loc='lower left', bbox_to_anchor=(1.01, 0., 1, 1), bbox_transform=ax.transAxes, borderpad=0, ) im1 = ax.pcolormesh(self.ref_frames[-1][:, :], linewidth=0, rasterized=True) cbar = fig.colorbar(im1, cax=axins1) ax.axhline(y=16, color='black', linewidth=2) ax.axvline(x=16, color='black', linewidth=2) ax.plot(self.ref_path_x[-1], self.ref_path_y[-1]) ax.set_ylim(0, 20) ax.set_xlim(0, 20) plt.title('Reference {}'.format(counter)) plt.show() # If confidence that DQD empty is larger than a certain threshold -> terminate # Classification outcome: [1, 0] -> dots occupied, [0, 1] -> dots empty if (occupation[1] > confidence and not self.is_current_(I_DQD, threshold=7e-12)): found = True print(self.ref_path_x[-1]) print(self.ref_path_y[-1]) self.occupation_1 = 0 self.occupation_2 = 0 self.trans_path_x.append(self.ref_path_x[-1]) self.trans_path_y.append(self.ref_path_y[-1]) print('Found a reference point at\n' 'PG1: {}V\n' 'PG2: {}V'.format(self.ref_path_x[-1], self.ref_path_y[-1])) else: self.ref_path_x.append(self.ref_path_x[-1] - f * res / 3) self.ref_path_y.append(self.ref_path_y[-1] - f * res / 3) return self.ref_path_x[-1], self.ref_path_y[-1]
'step': 1e-3 } # create configurations configs = [] keys, values = zip(*setup.items()) for v in product(*values): config = dict(zip(keys, v)) config['WGR'] = config['WGL'] configs.append(config) ScriptTools.setExePath(r'C:\\Program Files (x86)\\Labber\\Program') sPath = os.path.abspath( r'C:\\Users\\Measure2\\Desktop\\measurement_series\\charge transitions') path_in = os.path.join(sPath, 'coarse_msm_config2.hdf5') # Measure the configuration for k in range(132, 136): print('Currently measuring:\n' 'Configuration: {}\n' 'Number: {}'.format(configs[k - 132], k)) path_out = os.path.join(sPath, 'test\\{}.hdf5'.format(k)) Measurement = ScriptTools.MeasurementObject(path_in, path_out) path = os.path.join(sPath, 'msm5\\{}'.format(k)) measure(PG1, PG2, Measurement, path, calibrate=True, config=configs[k - 132])
scenario = Scenario(config_path).get_config_as_dict() optimizer_channels = [] for step in scenario['step_items']: if step['optimizer_config']['enabled'] == True: optimizer_channels.append(step['optimizer_config']) optimizer_config = scenario['optimizer'] optimizer_config['optimizer_channels'] = optimizer_channels return optimizer_config if __name__ == "__main__": sPath = os.path.dirname(os.path.abspath(__file__)) config_json = 'RandomizedBenchmarking.json' config_out = 'RandomizedBenchmarkingOut.hdf5' # Read in the optimization configuration as defined in the exported config config = extract_nelder_mead_rb_tuneup_config( os.path.join(sPath, config_json)) # Read in the measurement configuration as it will be run to execute tuneup measurement_config = ScriptTools.MeasurementObject( os.path.join(sPath, config_json), os.path.join(sPath, config_out)) cost_function = lambda x: tuneup_cost_function(x, measurement_config) optimum = optimize(config, cost_function) print(optimum)
def main(): ATS_var = 'AlazarTech Signal Demodulator - Channel A - Average demodulated value' readout_freq_var = 'readout - Frequency' readout_power_var = 'readout - Power' # set path to executable ScriptTools.setExePath(r'C:\Program Files (x86)\Labber\Program') test_path = r'E:\Data\2018\05\Data_0531' filename_sfx = time.strftime('%m_%d_%H_%M_%S', time.localtime()) test_meas = os.path.join(test_path, 'test no hardware loop_config.hdf5') test_out = os.path.join(test_path, 'test no hardware loop_%s.hdf5' % filename_sfx) fitting_out = os.path.join(test_path, 'fit_parameters_%s' % filename_sfx) fits_out = Labber.createLogFile_ForData(fitting_out, [{ 'name': 'Power', 'unit': 'dBm' }, { 'name': 'Frequency', 'unit': 'Hz' }, { 'name': 'Frequency Error', 'unit': 'Hz' }, { 'name': 'FWHM', 'unit': 'Hz' }, { 'name': 'FWHM Error', 'unit': 'Hz' }]) # define measurement objects test = ScriptTools.MeasurementObject(test_meas, test_out) test.setMasterChannel(readout_power_var) pows = np.linspace(8, 10, 2) # go through list of points for idx, pr in enumerate(pows): print('\nFreq point number: %d (out of %d points).' % ((idx + 1), pows.size)) print('Current Power: %.2f dBm.' % pr) ### TEST ### # set power test.updateValue(readout_power_var, pr) # find qubit print('Test in progress...') t_test = time.clock() (freqs, _) = test.performMeasurement() print('Test measurement time: %.1f s.' % (time.clock() - t_test)) # fit spectrum test_in = Labber.LogFile(test_out) # last_entry = test_in.getEntry(-1) # refls = last_entry[ATS_var] refls = test_in.getData(ATS_var)[0] print('Fitting to Lorentzian...') try: fit = fitting.lorentzian_fit(freqs, refls) (freq, freq_err) = fit[0] (FWHM, FWHM_err) = fit[1] print('Cavity frequency: %.4f +/- %.4f GHz.' % (1.e-9 * freq, 1.e-9 * freq_err)) print('Cavity FWHM: %.4f +/- %.4f GHz.' % (1.e-9 * FWHM, 1.e-9 * FWHM_err)) except: print_exception() continue # save fit data fits_out.addEntry({ 'Power': np.array([pr]), 'Frequency': np.array([freq]), 'Frequency Error': np.array([freq_err]), 'FWHM': np.array([FWHM]), 'FWHM Error': np.array([FWHM_err]) })