Skip to content

Commit

Permalink
Merge pull request #728 from qiboteam/tof_qblox
Browse files Browse the repository at this point in the history
ToF routine for qblox
  • Loading branch information
PiergiorgioButtarini authored Feb 1, 2024
2 parents e11f5c8 + 9e3d1d7 commit 13bdcb4
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 40 deletions.
30 changes: 12 additions & 18 deletions src/qibolab/instruments/qblox/acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,17 @@ class DemodulatedAcquisition:
It is advisable to have a power level at least higher than 5mV.
"""

scope: dict
"""Data returned by scope qblox acquisition."""
bins: dict
"""Binned acquisition data returned by qblox."""
duration: int
"""Duration of the readout pulse."""

@property
def raw(self):
return self.scope["acquisition"]["scope"]

@property
def integration(self):
return self.bins["integration"]
Expand All @@ -115,29 +121,17 @@ def shots_q(self):
return np.array(self.integration["path1"]) / self.duration

@property
def averaged_i(self):
"""I-component after demodulating and integrating every shot waveform
and then averaging over shots."""
return np.mean(self.shots_i)
def raw_i(self):
"""Average of the raw i waveforms for every readout pulse."""
return np.array(self.raw["path0"]["data"][0 : self.duration])

@property
def averaged_q(self):
"""Q-component after demodulating and integrating every shot waveform
and then averaging over shots."""
return np.mean(self.shots_q)
def raw_q(self):
"""Average of the raw q waveforms for every readout pulse."""
return np.array(self.raw["path1"]["data"][0 : self.duration])

@property
def classified(self):
"""List with the results of demodulating, integrating and classifying
every shot."""
return np.array(self.bins["threshold"])

@property
def data(self):
"""Acquisition data to be returned to the platform.
Ignores the data available in acquisition results and returns
only i and q voltages.
"""
# TODO: to be updated once the functionality of ExecutionResults is extended
return (self.shots_i, self.shots_q, self.classified)
15 changes: 3 additions & 12 deletions src/qibolab/instruments/qblox/cluster_qrm_rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,14 +977,14 @@ def acquire(self):
for port in self._output_ports_keys:
for sequencer in self._sequencers[port]:
# Store scope acquisition data on 'scope_acquisition' acquisition of the default sequencer
# TODO: Maybe this store_scope can be done only if needed to optimize the process!
if sequencer.number == self.DEFAULT_SEQUENCERS[port]:
self.device.store_scope_acquisition(
sequencer.number, "scope_acquisition"
)
scope = self.device.get_acquisitions(sequencer.number)[
"scope_acquisition"
]

if not hardware_demod_enabled: # Software Demodulation
if len(sequencer.pulses.ro_pulses) == 1:
pulse = sequencer.pulses.ro_pulses[0]
Expand All @@ -1002,20 +1002,11 @@ def acquire(self):
for pulse in sequencer.pulses.ro_pulses:
bins = results[pulse.serial]["acquisition"]["bins"]
acquisitions[pulse.qubit] = acquisitions[pulse.serial] = (
DemodulatedAcquisition(bins, duration)
)

# Provide Scope Data for verification (assuming memory reseet is being done)
if len(sequencer.pulses.ro_pulses) == 1:
pulse = sequencer.pulses.ro_pulses[0]
frequency = self.get_if(pulse)
acquisitions[pulse.serial].averaged = AveragedAcquisition(
scope, duration, frequency
DemodulatedAcquisition(scope, bins, duration)
)

# grab only the data required by the platform
# TODO: to be updated once the functionality of ExecutionResults is extended
return {key: acquisition.data for key, acquisition in acquisitions.items()}
return {key: acquisition for key, acquisition in acquisitions.items()}

def disconnect(self):
"""Stops all sequencers, disconnect all the outputs from the AWG paths
Expand Down
19 changes: 9 additions & 10 deletions src/qibolab/instruments/qblox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,24 @@ def _execute_pulse_sequence(
for name, module in self.modules.items():
if isinstance(module, QrmRf) and not module_pulses[name].ro_pulses.is_empty:
results = module.acquire()
existing_keys = set(acquisition_results.keys()) & set(results.keys())
for key, value in results.items():
if key in existing_keys:
acquisition_results[key].update(value)
else:
acquisition_results[key] = value

acquisition_results[key] = value
# TODO: move to QRM_RF.acquire()
shape = tuple(len(sweeper.values) for sweeper in reversed(sweepers))
shots_shape = (nshots,) + shape
for ro_pulse in sequence.ro_pulses:
if options.acquisition_type is AcquisitionType.DISCRIMINATION:
_res = acquisition_results[ro_pulse.serial][2]
_res = acquisition_results[ro_pulse.serial].classified
_res = np.reshape(_res, shots_shape)
if options.averaging_mode is not AveragingMode.SINGLESHOT:
_res = np.mean(_res, axis=0)
else:
ires = acquisition_results[ro_pulse.serial][0]
qres = acquisition_results[ro_pulse.serial][1]
elif options.acquisition_type is AcquisitionType.RAW:
i_raw = acquisition_results[ro_pulse.serial].raw_i
q_raw = acquisition_results[ro_pulse.serial].raw_q
_res = i_raw + 1j * q_raw
elif options.acquisition_type is AcquisitionType.INTEGRATION:
ires = acquisition_results[ro_pulse.serial].shots_i
qres = acquisition_results[ro_pulse.serial].shots_q
_res = ires + 1j * qres
if options.averaging_mode is AveragingMode.SINGLESHOT:
_res = np.reshape(_res, shots_shape)
Expand Down

0 comments on commit 13bdcb4

Please sign in to comment.