def add_manual_sweep(self, label, prompt, values, channel=None): param = FloatParameter() # Create the parameter param.name = label def method(value): print(f'Manually set {label} to {value}, then press enter.') input() param.assign_method(method) self.add_sweep(param, values) # Create the requested sweep on this parameter
def add_instrument_sweep(self, instrument_name, attribute, values, channel=None): param = FloatParameter() # Create the parameter param.name = f"{instrument_name} {attribute} {channel}" instr = self._instruments[instrument_name] def method(value, channel=channel, instr=instr, prop=attribute): if channel: getattr(instr, "set_" + prop)(channel, value) else: getattr(instr, "set_" + prop)(value) param.assign_method(method) self.add_sweep(param, values) # Create the requested sweep on this parameter
def load_parameter_sweeps(experiment): # Load the active sweeps from the sweep ordering for name in experiment.sweep_settings['sweepOrder']: par = experiment.sweep_settings['sweepDict'][name] # Treat segment sweeps separately since they are DataAxes rather than SweepAxes if par['x__class__'] != 'SegmentNum': # Here we create a parameter for experiment and associate it with the # relevant method in the instrument # Add a parameter to the experiment corresponding to the thing we want to sweep param = FloatParameter() param.name = name setattr(experiment, name, param) experiment._parameters[name] = param # Get the instrument instr = experiment._instruments[par['instr']] method_name = 'set_' + par['x__class__'].lower() points = np.linspace(par['start'], par['stop'], par['numPoints']) if hasattr(instr, method_name): param.assign_method(getattr(instr, method_name)) # Couple the parameter to the instrument experiment.add_sweep(param, points) # Create the requested sweep on this parameter else: raise ValueError("The instrument {} has no method set_{}".format(name, par['x__class__'].lower()))
def add_qubit_sweep(self, qubit, measure_or_control, attribute, values): """ Add a *ParameterSweep* to the experiment. Users specify a qubit property that auspex will try to link back to the relevant instrument. For example:: exp = QubitExpFactory.create(PulsedSpec(q1)) self.add_qubit_sweep(q1, "measure", "frequency", np.linspace(6e9, 6.5e9, 500)) self.run_sweeps() """ param = FloatParameter() # Create the parameter param.name = f"{qubit.label} {measure_or_control} {attribute}" if measure_or_control not in ["measure", "control"]: raise ValueError( f"Cannot add sweep for something other than measure or control properties of {qubit}" ) if measure_or_control == "measure": logger.debug(f"Sweeping {qubit} measurement") thing = list( filter(lambda m: m.label == "M-" + qubit.label, self.measurements)) if len(thing) > 1: raise ValueError( f"Found more than one measurement for {qubit}") thing = thing[0] elif measure_or_control == "control": logger.debug(f"Sweeping {qubit} control") thing = qubit if thing.phys_chan.generator and attribute == "frequency": # Mixed up to final frequency name = thing.phys_chan.generator.label instr = list( filter(lambda x: x.name == name, self._instruments.values()))[0] method = None else: # Direct synthesis name, chan = thing.phys_chan.label.split("-")[0:2] instr = self._instruments[ name] #list(filter(lambda x: x.name == name, self._instruments.values()))[0] #special casing for APS2 channel amplitude sweeps... is there a better way to do this? if isinstance( instr, auspex.instruments.APS2) and attribute == "amplitude": chan = [1, 2] def method(value, channel=chan, instr=instr, prop=attribute, thing=thing): # e.g. keysight.set_amplitude("ch1", 0.5) try: getattr(instr, "set_" + prop)(chan, value, thing) except: getattr(instr, "set_" + prop)(chan, value) param.set_pair = (thing.phys_chan.label, attribute) if method: # Custom method param.assign_method(method) else: # Get method by name if hasattr(instr, "set_" + attribute): param.assign_method(getattr( instr, "set_" + attribute)) # Couple the parameter to the instrument param.add_post_push_hook(lambda: time.sleep(0.05)) else: raise ValueError("The instrument {} has no method {}".format( name, "set_" + attribute)) param.set_pair = (instr.name, attribute) self.add_sweep(param, values) # Create the requested sweep on this parameter
def load_parameter_sweeps(experiment, manual_sweep_params=None): """Create parameter sweeps (non-segment sweeps) from the settings. Users can provide either a space-separated pair of *instr_name method_name* (i.e. *Holzworth1 power*) or specify a qubit property that auspex will try to link back to the relevant instrument. (i.e. *q1 measure frequency* or *q2 control amplitude 1*). Auspex will create a *SweepAxis* for each parameter sweep, and add this axis to all output connectors. If a channel number (1 or 2) is specified, it only sets that channel in the pair""" if manual_sweep_params: sweeps = manual_sweep_params order = [list(sweeps.keys())[0]] else: sweeps = experiment.settings['sweeps'] order = experiment.settings['sweepOrder'] channels = experiment.settings['qubits'] if 'edges' in experiment.settings: channels.update(experiment.settings['edges']) for name in order: par = sweeps[name] # Treat segment sweeps separately since they are DataAxes rather than SweepAxes if par['type'] != 'Segment': # Here we create a parameter for experiment and associate it with the # relevant method of the relevant experiment. # Add a parameter to the experiment corresponding to the thing we want to sweep if "unit" in par: param = FloatParameter(unit=par["unit"]) else: param = FloatParameter() param.name = name setattr(experiment, name, param) experiment._parameters[name] = param # We might need to return a custom function rather than just a method_name method = None # Figure our what we are sweeping target_info = par["target"].split() if target_info[0] in channels: # We are sweeping a qubit, so we must lookup the instrument target = par["target"].split() if target_info[0] in experiment.qubits: name, meas_or_control, prop = target[:3] isqubit = True else: name, prop = target[:2] isqubit = False if len(target) > 2 + isqubit: ch_ind = target[2 + isqubit] channel_params = channels[name][ meas_or_control] if isqubit else channels[name] method_name = "set_{}".format(prop.lower()) # If sweeping frequency, we should allow for either mixed up signals or direct synthesis. # Sweeping amplitude is always through the AWG channels. if 'generator' in channel_params and prop.lower( ) == "frequency": name = channel_params['generator'] instr = experiment._instruments[name] else: # Construct a function that sets a per-channel property name, chan = channel_params['AWG'].split() if len(target) > 3: chan = chan[int(ch_ind) - 1] instr = experiment._instruments[name] def method(value, channel=chan, instr=instr, prop=prop.lower()): # e.g. keysight.set_amplitude("ch1", 0.5) getattr(instr, "set_" + prop)(chan, value) elif target_info[0] in experiment._instruments: # We are sweeping an instrument directly # Get the instrument being swept, and find the relevant method name, prop = par["target"].split() instr = experiment._instruments[name] method_name = 'set_' + prop.lower() # If there's a "points" property, use those directly. Otherwise, we # use numPoints or the step interval. if "points" in par: points = par["points"] elif "numPoints" in par: points = np.linspace(par['start'], par['stop'], par['numPoints']) elif "step" in par: points = np.arange(par['start'], par['stop'], par['step']) if method: # Custom method param.assign_method(method) else: # Get method by name if hasattr(instr, method_name): param.assign_method( getattr(instr, method_name) ) # Couple the parameter to the instrument else: raise ValueError( "The instrument {} has no method {}".format( name, method_name)) param.instr_tree = [instr.name, prop] #TODO: extend tree to endpoint experiment.add_sweep( param, points) # Create the requested sweep on this parameter