示例#1
0
 def performOpen(self, options={}):
     """Perform the operation of opening the instrument connection."""
     # init variables
     self.sequence = None
     self.sequence_to_waveforms = SequenceToWaveforms()
     self.waveforms = {}
     # always create a sequence at startup
     name = self.getValue('Sequence')
     self.sendValueToOther('Sequence', name)
示例#2
0
class Driver(LabberDriver):
    """This class implements a multi-qubit pulse generator."""

    def performOpen(self, options={}):
        """Perform the operation of opening the instrument connection."""
        # init variables
        self.sequence = None
        self.sequence_to_waveforms = SequenceToWaveforms()
        self.waveforms = {}
        # always create a sequence at startup
        name = self.getValue('Sequence')
        self.sendValueToOther('Sequence', name)

    def performSetValue(self, quant, value, sweepRate=0.0, options={}):
        """Perform the Set Value instrument operation."""
        # only do something here if changing the sequence type
        if quant.name == 'Sequence':
            # create new sequence if sequence type changed
            new_type = SEQUENCES[value]

            if not isinstance(self.sequence, new_type):
                # create a new sequence object
                if value == 'Custom':
                    # for custom python files
                    path = self.getValue('Custom Python file')
                    (path, modName) = os.path.split(path)
                    sys.path.append(path)
                    modName = modName.split('.py')[0]  # strip suffix
                    mod = importlib.import_module(modName)
                    # the custom sequence class has to be named
                    # 'CustomSequence'
                    if not isinstance(self.sequence, mod.CustomSequence):
                        self.sequence = mod.CustomSequence()
                else:
                    # standard built-in sequence
                    self.sequence = new_type()

        elif (quant.name == 'Custom Python file' and
              self.getValue('Sequence') == 'Custom'):
            # for custom python files
            path = self.getValue('Custom Python file')
            (path, modName) = os.path.split(path)
            modName = modName.split('.py')[0]  # strip suffix
            sys.path.append(path)
            mod = importlib.import_module(modName)
            # the custom sequence class has to be named 'CustomSequence'
            if not isinstance(self.sequence, mod.CustomSequence):
                self.sequence = mod.CustomSequence()
        return value

    def performGetValue(self, quant, options={}):
        """Perform the Get Value instrument operation."""
        # ignore if no sequence
        if self.sequence is None:
            return quant.getValue()

        # check type of quantity
        if (quant.name.startswith('Voltage, QB') or
                quant.name.startswith('Single-shot, QB')):
            # perform demodulation, check if config is updated
            if self.isConfigUpdated():
                # update sequence object with current driver configuation
                config = self.instrCfg.getValuesDict()
                self.sequence.set_parameters(config)
                self.sequence_to_waveforms.set_parameters(config)
            # get qubit index and waveforms
            n = int(quant.name.split(', QB')[1]) - 1
            demod_iq = self.getValue('Demodulation - IQ')
            if demod_iq:
                signal_i = self.getValue('Demodulation - Input I')
                signal_q = self.getValue('Demodulation - Input Q')
            else:
                signal = self.getValue('Demodulation - Input')
            ref = self.getValue('Demodulation - Reference')
            # perform demodulation
            if demod_iq:
                value = self.sequence_to_waveforms.readout.demodulate_iq(
                    n, signal_i, signal_q, ref)
            else:
                value = self.sequence_to_waveforms.readout.demodulate(
                    n, signal, ref)
            # average values if not single-shot
            if not quant.name.startswith('Single-shot, QB'):
                value = np.mean(value)

        elif quant.isVector():
            # traces, check if waveform needs to be re-calculated
            if self.isConfigUpdated():
                # update sequence object with current driver configuation
                config = self.instrCfg.getValuesDict()
                self.sequence.set_parameters(config)
                self.sequence_to_waveforms.set_parameters(config)

                # check if calculating multiple sequences, for randomization
                if config.get('Output multiple sequences', False):
                    # create multiple randomizations, store in memory
                    n_call = int(config.get('Number of multiple sequences', 1))
                    calls = []
                    for n in range(n_call):
                        config['Randomize'] += 1
                        calls.append(
                            copy.deepcopy(
                                self.sequence_to_waveforms.get_waveforms(
                                    self.sequence.get_sequence(config))))

                    # after all calls are done, convert output to matrix form
                    self.waveforms = dict()
                    n_qubit = self.sequence.n_qubit
                    # Align RB waveforms to end
                    align_RB_to_end = config.get('Align RB waveforms to end', False)
                    # start with xy, z and gate waveforms, list of data
                    for key in ['xy', 'z', 'gate']:
                        # get size of longest waveform
                        self.waveforms[key] = []
                        for n in range(n_qubit):
                            length = max([len(call[key][n]) for call in calls])
                            # build matrix
                            datatype = calls[0][key][n].dtype
                            data = np.zeros((n_call, length), dtype=datatype)
                            for m, call in enumerate(calls):
                                if align_RB_to_end:
                                    data[m][-len(call[key][n]):] = call[key][n]
                                else:
                                    data[m][:len(call[key][n])] = call[key][n]
                            self.waveforms[key].append(data)

                    # same for readout waveforms
                    for key in ['readout_trig', 'readout_iq']:
                        length = max([len(call[key]) for call in calls])
                        datatype = calls[0][key].dtype
                        data = np.zeros((n_call, length), dtype=datatype)
                        for m, call in enumerate(calls):
                            if align_RB_to_end:
                                data[m][-len(call[key]):] = call[key]
                            else:
                                data[m][:len(call[key])] = call[key]
                        self.waveforms[key] = data

                else:
                    # normal operation, calcluate waveforms
                    self.waveforms = self.sequence_to_waveforms.get_waveforms(
                        self.sequence.get_sequence(config))
            # get correct data from waveforms stored in memory
            value = self.getWaveformFromMemory(quant)
        else:
            # for all other cases, do nothing
            value = quant.getValue()
        return value

    def getWaveformFromMemory(self, quant):
        """Return data from already calculated waveforms."""
        # check which data to return
        if quant.name[-1] in ('1', '2', '3', '4', '5', '6', '7', '8', '9'):
            # get name and number of qubit waveform asked for
            name = quant.name[:-1]
            n = int(quant.name[-1]) - 1
            # get correct vector
            if name == 'Trace - I':
                if self.getValue('Swap IQ'):
                    value = self.waveforms['xy'][n].imag
                else:
                    value = self.waveforms['xy'][n].real
            elif name == 'Trace - Q':
                if self.getValue('Swap IQ'):
                    value = self.waveforms['xy'][n].real
                else:
                    value = self.waveforms['xy'][n].imag
            elif name == 'Trace - Z':
                value = self.waveforms['z'][n]
            elif name == 'Trace - G':
                value = self.waveforms['gate'][n]

        elif quant.name == 'Trace - Readout trig':
            value = self.waveforms['readout_trig']
        elif quant.name == 'Trace - Readout I':
            value = self.waveforms['readout_iq'].real
        elif quant.name == 'Trace - Readout Q':
            value = self.waveforms['readout_iq'].imag

        # return data as dict with sampling information
        dt = 1 / self.sequence_to_waveforms.sample_rate
        value = quant.getTraceDict(value, dt=dt)
        return value
class Driver(LabberDriver):
    """This class implements a multi-qubit pulse generator."""
    def performOpen(self, options={}):
        """Perform the operation of opening the instrument connection."""
        # init variables
        self.sequence = None
        self.sequence_to_waveforms = SequenceToWaveforms()
        self.waveforms = {}
        # always create a sequence at startup
        name = self.getValue('Sequence')
        self.sendValueToOther('Sequence', name)

    def performSetValue(self, quant, value, sweepRate=0.0, options={}):
        """Perform the Set Value instrument operation."""
        # only do something here if changing the sequence type
        if quant.name == 'Sequence':
            # create new sequence if sequence type changed
            new_type = SEQUENCES[value]

            if not isinstance(self.sequence, new_type):
                # create a new sequence object
                if value == 'Custom':
                    # for custom python files
                    path = self.getValue('Custom Python file')
                    (path, modName) = os.path.split(path)
                    sys.path.append(path)
                    modName = modName.split('.py')[0]  # strip suffix
                    mod = importlib.import_module(modName)
                    # the custom sequence class has to be named
                    # 'CustomSequence'
                    if not isinstance(self.sequence, mod.CustomSequence):
                        self.sequence = mod.CustomSequence()
                else:
                    # standard built-in sequence
                    self.sequence = new_type()

        elif (quant.name == 'Custom Python file'
              and self.getValue('Sequence') == 'Custom'):
            # for custom python files
            path = self.getValue('Custom Python file')
            (path, modName) = os.path.split(path)
            modName = modName.split('.py')[0]  # strip suffix
            sys.path.append(path)
            mod = importlib.import_module(modName)
            # the custom sequence class has to be named 'CustomSequence'
            if not isinstance(self.sequence, mod.CustomSequence):
                self.sequence = mod.CustomSequence()
        return value

    def performGetValue(self, quant, options={}):
        """Perform the Get Value instrument operation."""
        # ignore if no sequence
        if self.sequence is None:
            return quant.getValue()

        # check type of quantity
        if (quant.name.startswith('Voltage, QB')
                or quant.name.startswith('Single-shot, QB')):
            # perform demodulation, check if config is updated
            if self.isConfigUpdated():
                # update sequence object with current driver configuation
                config = self.instrCfg.getValuesDict()
                self.sequence.set_parameters(config)
                self.sequence_to_waveforms.set_parameters(config)
            # get qubit index and waveforms
            n = int(quant.name.split(', QB')[1]) - 1
            demod_iq = self.getValue('Demodulation - IQ')
            if demod_iq:
                signal_i = self.getValue('Demodulation - Input I')
                signal_q = self.getValue('Demodulation - Input Q')
            else:
                signal = self.getValue('Demodulation - Input')
            ref = self.getValue('Demodulation - Reference')
            # perform demodulation
            if demod_iq:
                value = self.sequence_to_waveforms.readout.demodulate_iq(
                    n, signal_i, signal_q, ref)
            else:
                value = self.sequence_to_waveforms.readout.demodulate(
                    n, signal, ref)
            # average values if not single-shot
            if not quant.name.startswith('Single-shot, QB'):
                value = np.mean(value)

        elif quant.isVector():
            # traces, check if waveform needs to be re-calculated
            if self.isConfigUpdated():
                # update sequence object with current driver configuation
                config = self.instrCfg.getValuesDict()
                self.sequence.set_parameters(config)
                self.sequence_to_waveforms.set_parameters(config)
                # calcluate waveforms
                self.waveforms = self.sequence_to_waveforms.get_waveforms(
                    self.sequence.get_sequence(config))
            # get correct data from waveforms stored in memory
            value = self.getWaveformFromMemory(quant)
        else:
            # for all other cases, do nothing
            value = quant.getValue()
        return value

    def getWaveformFromMemory(self, quant):
        """Return data from already calculated waveforms."""
        # check which data to return
        if quant.name[-1] in ('1', '2', '3', '4', '5', '6', '7', '8', '9'):
            # get name and number of qubit waveform asked for
            name = quant.name[:-1]
            n = int(quant.name[-1]) - 1
            # get correct vector
            if name == 'Trace - I':
                if self.getValue('Swap IQ'):
                    value = self.waveforms['xy'][n].imag
                else:
                    value = self.waveforms['xy'][n].real
            elif name == 'Trace - Q':
                if self.getValue('Swap IQ'):
                    value = self.waveforms['xy'][n].real
                else:
                    value = self.waveforms['xy'][n].imag
            elif name == 'Trace - Z':
                value = self.waveforms['z'][n]
            elif name == 'Trace - G':
                value = self.waveforms['gate'][n]

        elif quant.name == 'Trace - Readout trig':
            value = self.waveforms['readout_trig']
        elif quant.name == 'Trace - Readout I':
            value = self.waveforms['readout_iq'].real
        elif quant.name == 'Trace - Readout Q':
            value = self.waveforms['readout_iq'].imag

        # return data as dict with sampling information
        dt = 1 / self.sequence_to_waveforms.sample_rate
        value = quant.getTraceDict(value, dt=dt)
        return value