diff --git a/src/qibocal/protocols/characterization/ramsey.py b/src/qibocal/protocols/characterization/ramsey.py index 55a726ccd..46e7fcca4 100644 --- a/src/qibocal/protocols/characterization/ramsey.py +++ b/src/qibocal/protocols/characterization/ramsey.py @@ -39,6 +39,9 @@ class RamseyParameters(Parameters): n_osc: Optional[int] = 0 """Number of oscillations to induce detuning (optional). If 0 standard Ramsey experiment is performed.""" + unrolling: bool = False + """If ``True`` it uses sequence unrolling to deploy multiple sequences in a single instrument call. + Defaults to ``False``.""" @dataclass @@ -95,25 +98,6 @@ def _acquisition( """Data acquisition for Ramsey Experiment (detuned).""" # create a sequence of pulses for the experiment # RX90 - t - RX90 - MZ - ro_pulses = {} - RX90_pulses1 = {} - RX90_pulses2 = {} - freqs = {} - sequence = PulseSequence() - for qubit in qubits: - RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) - RX90_pulses2[qubit] = platform.create_RX90_pulse( - qubit, - start=RX90_pulses1[qubit].finish, - ) - ro_pulses[qubit] = platform.create_qubit_readout_pulse( - qubit, start=RX90_pulses2[qubit].finish - ) - freqs[qubit] = qubits[qubit].drive_frequency - sequence.add(RX90_pulses1[qubit]) - sequence.add(RX90_pulses2[qubit]) - sequence.add(ro_pulses[qubit]) - # define the parameter to sweep and its range: waits = np.arange( # wait time between RX90 pulses @@ -122,14 +106,40 @@ def _acquisition( params.delay_between_pulses_step, ) - data = RamseyData( - n_osc=params.n_osc, - t_max=params.delay_between_pulses_end, - detuning_sign=+1, - qubit_freqs=freqs, + options = ExecutionParameters( + nshots=params.nshots, + relaxation_time=params.relaxation_time, + acquisition_type=AcquisitionType.DISCRIMINATION, + averaging_mode=AveragingMode.SINGLESHOT, ) if params.n_osc == 0: + ro_pulses = {} + RX90_pulses1 = {} + RX90_pulses2 = {} + freqs = {} + sequence = PulseSequence() + for qubit in qubits: + RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) + RX90_pulses2[qubit] = platform.create_RX90_pulse( + qubit, + start=RX90_pulses1[qubit].finish, + ) + ro_pulses[qubit] = platform.create_qubit_readout_pulse( + qubit, start=RX90_pulses2[qubit].finish + ) + freqs[qubit] = qubits[qubit].drive_frequency + sequence.add(RX90_pulses1[qubit]) + sequence.add(RX90_pulses2[qubit]) + sequence.add(ro_pulses[qubit]) + + data = RamseyData( + n_osc=params.n_osc, + t_max=params.delay_between_pulses_end, + detuning_sign=+1, + qubit_freqs=freqs, + ) + sweeper = Sweeper( Parameter.start, waits, @@ -140,12 +150,7 @@ def _acquisition( # execute the sweep results = platform.sweep( sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.DISCRIMINATION, - averaging_mode=AveragingMode.SINGLESHOT, - ), + options, sweeper, ) for qubit in qubits: @@ -161,31 +166,67 @@ def _acquisition( errors=errors, ), ) - else: + if params.n_osc != 0: + sequences, all_ro_pulses = [], [] for wait in waits: + ro_pulses = {} + RX90_pulses1 = {} + RX90_pulses2 = {} + freqs = {} + sequence = PulseSequence() for qubit in qubits: + RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) + RX90_pulses2[qubit] = platform.create_RX90_pulse( + qubit, + start=RX90_pulses1[qubit].finish, + ) + ro_pulses[qubit] = platform.create_qubit_readout_pulse( + qubit, start=RX90_pulses2[qubit].finish + ) + RX90_pulses2[qubit].start = RX90_pulses1[qubit].finish + wait ro_pulses[qubit].start = RX90_pulses2[qubit].finish - if params.n_osc != 0: - RX90_pulses2[qubit].relative_phase = ( - RX90_pulses2[qubit].start - * (-2 * np.pi) - * (params.n_osc) - / params.delay_between_pulses_end - ) - - results = platform.execute_pulse_sequence( - sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.DISCRIMINATION, - averaging_mode=(AveragingMode.SINGLESHOT), - ), - ) + RX90_pulses2[qubit].relative_phase = ( + RX90_pulses2[qubit].start + * (-2 * np.pi) + * (params.n_osc) + / params.delay_between_pulses_end + ) + + freqs[qubit] = qubits[qubit].drive_frequency + sequence.add(RX90_pulses1[qubit]) + sequence.add(RX90_pulses2[qubit]) + sequence.add(ro_pulses[qubit]) + + sequences.append(sequence) + all_ro_pulses.append(ro_pulses) + + data = RamseyData( + n_osc=params.n_osc, + t_max=params.delay_between_pulses_end, + detuning_sign=+1, + qubit_freqs=freqs, + ) + + if params.unrolling: + results = platform.execute_pulse_sequences(sequences, options) + + elif not params.unrolling: + results = [ + platform.execute_pulse_sequence(sequence, options) + for sequence in sequences + ] + + # We dont need ig as everty serial is different + for ig, (wait, ro_pulses) in enumerate(zip(waits, all_ro_pulses)): for qubit in qubits: - prob = results[qubit].probability() + serial = ro_pulses[qubit].serial + if params.unrolling: + result = results[serial][0] + else: + result = results[ig][serial] + prob = result.probability() error = np.sqrt(prob * (1 - prob) / params.nshots) data.register_qubit( RamseyType, @@ -196,6 +237,7 @@ def _acquisition( errors=np.array([error]), ), ) + return data diff --git a/src/qibocal/protocols/characterization/ramsey_signal.py b/src/qibocal/protocols/characterization/ramsey_signal.py index 6ee4af47a..8e990ba5f 100644 --- a/src/qibocal/protocols/characterization/ramsey_signal.py +++ b/src/qibocal/protocols/characterization/ramsey_signal.py @@ -79,25 +79,6 @@ def _acquisition( """Data acquisition for Ramsey Experiment (detuned).""" # create a sequence of pulses for the experiment # RX90 - t - RX90 - MZ - ro_pulses = {} - RX90_pulses1 = {} - RX90_pulses2 = {} - freqs = {} - sequence = PulseSequence() - for qubit in qubits: - RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) - RX90_pulses2[qubit] = platform.create_RX90_pulse( - qubit, - start=RX90_pulses1[qubit].finish, - ) - ro_pulses[qubit] = platform.create_qubit_readout_pulse( - qubit, start=RX90_pulses2[qubit].finish - ) - freqs[qubit] = qubits[qubit].drive_frequency - sequence.add(RX90_pulses1[qubit]) - sequence.add(RX90_pulses2[qubit]) - sequence.add(ro_pulses[qubit]) - # define the parameter to sweep and its range: waits = np.arange( # wait time between RX90 pulses @@ -106,14 +87,33 @@ def _acquisition( params.delay_between_pulses_step, ) - data = RamseySignalData( - n_osc=params.n_osc, - t_max=params.delay_between_pulses_end, - detuning_sign=+1, - qubit_freqs=freqs, + options = ExecutionParameters( + nshots=params.nshots, + relaxation_time=params.relaxation_time, + acquisition_type=AcquisitionType.INTEGRATION, + averaging_mode=AveragingMode.CYCLIC, ) if params.n_osc == 0: + ro_pulses = {} + RX90_pulses1 = {} + RX90_pulses2 = {} + freqs = {} + sequence = PulseSequence() + for qubit in qubits: + RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) + RX90_pulses2[qubit] = platform.create_RX90_pulse( + qubit, + start=RX90_pulses1[qubit].finish, + ) + ro_pulses[qubit] = platform.create_qubit_readout_pulse( + qubit, start=RX90_pulses2[qubit].finish + ) + freqs[qubit] = qubits[qubit].drive_frequency + sequence.add(RX90_pulses1[qubit]) + sequence.add(RX90_pulses2[qubit]) + sequence.add(ro_pulses[qubit]) + sweeper = Sweeper( Parameter.start, waits, @@ -121,15 +121,16 @@ def _acquisition( type=SweeperType.ABSOLUTE, ) + data = RamseySignalData( + n_osc=params.n_osc, + t_max=params.delay_between_pulses_end, + detuning_sign=+1, + qubit_freqs=freqs, + ) # execute the sweep results = platform.sweep( sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=AveragingMode.CYCLIC, - ), + options, sweeper, ) for qubit in qubits: @@ -141,36 +142,72 @@ def _acquisition( signal=result.magnitude, ) - else: + if params.n_osc != 0: + sequences, all_ro_pulses = [], [] for wait in waits: + ro_pulses = {} + RX90_pulses1 = {} + RX90_pulses2 = {} + freqs = {} + sequence = PulseSequence() for qubit in qubits: + RX90_pulses1[qubit] = platform.create_RX90_pulse(qubit, start=0) + RX90_pulses2[qubit] = platform.create_RX90_pulse( + qubit, + start=RX90_pulses1[qubit].finish, + ) + ro_pulses[qubit] = platform.create_qubit_readout_pulse( + qubit, start=RX90_pulses2[qubit].finish + ) + RX90_pulses2[qubit].start = RX90_pulses1[qubit].finish + wait ro_pulses[qubit].start = RX90_pulses2[qubit].finish - if params.n_osc != 0: - RX90_pulses2[qubit].relative_phase = ( - RX90_pulses2[qubit].start - * (-2 * np.pi) - * (params.n_osc) - / params.delay_between_pulses_end - ) - - results = platform.execute_pulse_sequence( - sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=(AveragingMode.CYCLIC), - ), - ) + RX90_pulses2[qubit].relative_phase = ( + RX90_pulses2[qubit].start + * (-2 * np.pi) + * (params.n_osc) + / params.delay_between_pulses_end + ) + + freqs[qubit] = qubits[qubit].drive_frequency + sequence.add(RX90_pulses1[qubit]) + sequence.add(RX90_pulses2[qubit]) + sequence.add(ro_pulses[qubit]) + + sequences.append(sequence) + all_ro_pulses.append(ro_pulses) + + data = RamseySignalData( + n_osc=params.n_osc, + t_max=params.delay_between_pulses_end, + detuning_sign=+1, + qubit_freqs=freqs, + ) + + if params.unrolling: + results = platform.execute_pulse_sequences(sequences, options) + + elif not params.unrolling: + results = [ + platform.execute_pulse_sequence(sequence, options) + for sequence in sequences + ] + + # We dont need ig as everty serial is different + for ig, (wait, ro_pulses) in enumerate(zip(waits, all_ro_pulses)): for qubit in qubits: - result = results[ro_pulses[qubit].serial] + serial = ro_pulses[qubit].serial + if params.unrolling: + result = results[serial][0] + else: + result = results[ig][serial] data.register_qubit( qubit, wait=wait, signal=result.magnitude, ) + return data diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index 874eb5dc5..f0c680139 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -356,38 +356,50 @@ actions: delay_between_pulses_step: 100 nshots: 10 - - id: ramsey_detuned + - id: ramsey_signal priority: 0 - operation: ramsey + operation: ramsey_signal parameters: delay_between_pulses_start: 0 delay_between_pulses_end: 50 delay_between_pulses_step: 1 - n_osc: 2 nshots: 10 - - id: ramsey_signal + - id: ramsey_signal_detuned priority: 0 operation: ramsey_signal parameters: + unrolling: False delay_between_pulses_start: 0 delay_between_pulses_end: 50 delay_between_pulses_step: 1 n_osc: 2 nshots: 10 - - id: ramsey_signal_detuned + - id: ramsey_signal_detuned_unrolled priority: 0 operation: ramsey_signal parameters: + unrolling: True delay_between_pulses_start: 0 delay_between_pulses_end: 50 delay_between_pulses_step: 1 + n_osc: 10 nshots: 10 - - id: ramsey detuned sequences + - id: ramsey priority: 0 - operation: ramsey_sequences + operation: ramsey + parameters: + delay_between_pulses_start: 0 + delay_between_pulses_end: 20 + delay_between_pulses_step: 1 + n_osc: 0 + nshots: 1024 + + - id: ramsey_detuned + priority: 0 + operation: ramsey parameters: delay_between_pulses_start: 0 delay_between_pulses_end: 50 @@ -395,15 +407,26 @@ actions: n_osc: 2 nshots: 10 - - id: ramsey + - id: ramsey_detuned_sequences + priority: 0 + operation: ramsey_sequences + parameters: + delay_between_pulses_start: 0 + delay_between_pulses_end: 50 + delay_between_pulses_step: 1 + nshots: 10 + n_osc: 2 + + - id: ramsey_unrolled_detuned priority: 0 operation: ramsey parameters: + unrolling: True delay_between_pulses_start: 0 - delay_between_pulses_end: 20 + delay_between_pulses_end: 50 delay_between_pulses_step: 1 - n_osc: 0 - nshots: 1024 + nshots: 10 + n_osc: 10 - id: single shot classification priority: 0