diff --git a/doc/source/protocols/resonator_spectroscopy.rst b/doc/source/protocols/resonator_spectroscopy.rst index aadf8b342..de545791f 100644 --- a/doc/source/protocols/resonator_spectroscopy.rst +++ b/doc/source/protocols/resonator_spectroscopy.rst @@ -29,7 +29,7 @@ The bare resonator frequency can be found setting a large value for the amplitud platform: - qubits: [0] + targets: [0] actions: @@ -44,6 +44,17 @@ The bare resonator frequency can be found setting a large value for the amplitud nshots: 1024 relaxation_time: 100000 +.. note:: + The resonator spectroscopy experiment will be performed by computing + the average on hardware. If the user wants to retrieve all the shots + and perform the average afterwards it can be done by specifying the + entry `hardware_average: false` in the experiment parameters. In this + case the fitting procedure will take into account errors and error bands + will be included in the plot. + + .. image:: resonator_spectroscopy_error_bars.png + + .. image:: resonator_spectroscopy_high.png Lowering the amplitude we can see a shift in the peak, e.g.: @@ -52,7 +63,7 @@ Lowering the amplitude we can see a shift in the peak, e.g.: platform: - qubits: [0] + targets: [0] actions: @@ -130,8 +141,7 @@ and also here: single_qubit: 0: bare_resonator_frequency: - readout_frequency: 5_227_920_060 - drive_frequency: + readout_frequency: .. rubric:: References diff --git a/doc/source/protocols/resonator_spectroscopy_error_bars.png b/doc/source/protocols/resonator_spectroscopy_error_bars.png new file mode 100644 index 000000000..984fc90ff Binary files /dev/null and b/doc/source/protocols/resonator_spectroscopy_error_bars.png differ diff --git a/poetry.lock b/poetry.lock index 166f0288f..0c4414722 100644 --- a/poetry.lock +++ b/poetry.lock @@ -115,13 +115,13 @@ lxml = ["lxml"] [[package]] name = "blinker" -version = "1.8.1" +version = "1.8.2" description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.8" files = [ - {file = "blinker-1.8.1-py3-none-any.whl", hash = "sha256:5f1cdeff423b77c31b89de0565cd03e5275a03028f44b2b15f912632a58cced6"}, - {file = "blinker-1.8.1.tar.gz", hash = "sha256:da44ec748222dcd0105ef975eed946da197d5bdf8bafb6aa92f5bc89da63fa25"}, + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, ] [[package]] @@ -2312,7 +2312,7 @@ zh = ["laboneq (==2.25.0)"] type = "git" url = "https://github.com/qiboteam/qibolab.git" reference = "HEAD" -resolved_reference = "41fcafde38801179cbd5a39b72bfbb00b52e4c07" +resolved_reference = "b93ee1b029df36a9b4df48c04ce9459764957b93" [[package]] name = "recommonmark" @@ -2472,19 +2472,19 @@ stats = ["scipy (>=1.3)", "statsmodels (>=0.10)"] [[package]] name = "setuptools" -version = "69.5.1" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, - {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2802,17 +2802,18 @@ widechars = ["wcwidth"] [[package]] name = "tenacity" -version = "8.2.3" +version = "8.3.0" description = "Retry code until it succeeds" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, - {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, + {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, + {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, ] [package.extras] -doc = ["reno", "sphinx", "tornado (>=4.5)"] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "threadpoolctl" @@ -2838,13 +2839,13 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.4" +version = "0.12.5" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, - {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, + {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, + {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, ] [[package]] @@ -3056,4 +3057,4 @@ viz = ["pydot"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "6655c1ee3820666edaed7cca4e7662a58d89669cc9a0d81ddf4ea93839c9aec0" +content-hash = "e4882dee58cdba6d57ac17a5b91884d2eec65d7321734ecc2bb09ea1ecb48561" diff --git a/pyproject.toml b/pyproject.toml index 0728815ac..1e3447a5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ [tool.poetry.dependencies] python = ">=3.9,<3.12" qibolab = { git = "https://github.com/qiboteam/qibolab.git"} -qibo = "^0.2.7" +qibo ="^0.2.6" numpy = "^1.26.4" scipy = "^1.10.1" pandas = "^1.4.3" @@ -30,7 +30,7 @@ dash = "^2.6.0" skops = "^0.6.0" scikit-learn = "^1.2.1" # Explicit dependency required to cope for dash: https://github.com/plotly/dash/issues/2557 -setuptools = "^69.0.0" +setuptools = "^67.8.0" matplotlib = { version = "^3.7.0", optional = true } seaborn = { version = "^0.12.2", optional = true } pydot = { version = "^1.4.2", optional = true } diff --git a/src/qibocal/auto/operation.py b/src/qibocal/auto/operation.py index 319491039..d39c381fb 100644 --- a/src/qibocal/auto/operation.py +++ b/src/qibocal/auto/operation.py @@ -9,6 +9,7 @@ import numpy as np import numpy.typing as npt +from qibolab import AcquisitionType, AveragingMode, ExecutionParameters from qibolab.platform import Platform from qibolab.qubits import Qubit, QubitId, QubitPair, QubitPairId @@ -71,6 +72,10 @@ class Parameters: """Number of executions on hardware""" relaxation_time: float """Wait time for the qubit to decohere back to the `gnd` state""" + hardware_average: bool = False + """By default hardware average will be performed.""" + classify: bool = False + """By default qubit state classification will not be performed.""" @classmethod def load(cls, input_parameters): @@ -96,6 +101,24 @@ def load(cls, input_parameters): setattr(instantiated_class, parameter, value) return instantiated_class + @property + def execution_parameters(self): + """Default execution parameters.""" + averaging_mode = ( + AveragingMode.CYCLIC if self.hardware_average else AveragingMode.SINGLESHOT + ) + acquisition_type = ( + AcquisitionType.DISCRIMINATION + if self.classify + else AcquisitionType.INTEGRATION + ) + return ExecutionParameters( + nshots=self.nshots, + relaxation_time=self.relaxation_time, + acquisition_type=acquisition_type, + averaging_mode=averaging_mode, + ) + class AbstractData: """Abstract data class.""" @@ -197,9 +220,10 @@ def register_qubit(self, dtype, data_keys, data_dict): the values are the related arrays. """ # to be able to handle the non-sweeper case - ar = np.empty(np.shape(data_dict[list(data_dict.keys())[0]]), dtype=dtype) + ar = np.empty(np.shape(data_dict[list(data_dict)[0]]), dtype=dtype) for key, value in data_dict.items(): ar[key] = value + if data_keys in self.data: self.data[data_keys] = np.rec.array( np.concatenate((self.data[data_keys], ar)) diff --git a/src/qibocal/protocols/dispersive_shift.py b/src/qibocal/protocols/dispersive_shift.py index 5aa07b5de..a1c9be06d 100644 --- a/src/qibocal/protocols/dispersive_shift.py +++ b/src/qibocal/protocols/dispersive_shift.py @@ -138,19 +138,14 @@ def _acquisition( results_1 = platform.sweep( sequence_1, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=AveragingMode.CYCLIC, - ), + params.execution_parameters, sweeper, ) # retrieve the results for every qubit for qubit in targets: for i, results in enumerate([results_0, results_1]): - result = results[ro_pulses[qubit].serial] + result = results[ro_pulses[qubit].serial].average # store the results data.register_qubit( DispersiveShiftType, diff --git a/src/qibocal/protocols/dispersive_shift_qutrit.py b/src/qibocal/protocols/dispersive_shift_qutrit.py index b1bdbfbb1..79545826c 100644 --- a/src/qibocal/protocols/dispersive_shift_qutrit.py +++ b/src/qibocal/protocols/dispersive_shift_qutrit.py @@ -130,7 +130,7 @@ def _acquisition( ) for qubit in targets: - result = results[qubit] + result = results[qubit].average # store the results data.register_qubit( ResSpecType, diff --git a/src/qibocal/protocols/qubit_spectroscopy.py b/src/qibocal/protocols/qubit_spectroscopy.py index 766583257..ae60f93f7 100644 --- a/src/qibocal/protocols/qubit_spectroscopy.py +++ b/src/qibocal/protocols/qubit_spectroscopy.py @@ -2,7 +2,6 @@ from typing import Optional import numpy as np -from qibolab import AcquisitionType, AveragingMode, ExecutionParameters from qibolab.platform import Platform from qibolab.pulses import PulseSequence from qibolab.qubits import QubitId @@ -27,6 +26,8 @@ class QubitSpectroscopyParameters(Parameters): """Drive pulse duration [ns]. Same for all qubits.""" drive_amplitude: Optional[float] = None """Drive pulse amplitude (optional). Same for all qubits.""" + hardware_average: bool = True + """By default hardware average will be performed.""" @dataclass @@ -96,12 +97,7 @@ def _acquisition( results = platform.sweep( sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=AveragingMode.SINGLESHOT, - ), + params.execution_parameters, sweeper, ) @@ -113,11 +109,11 @@ def _acquisition( ResSpecType, (qubit), dict( - signal=np.abs(result.average.voltage), - phase=np.mean(result.phase, axis=0), + signal=result.average.magnitude, + phase=result.average.phase, freq=delta_frequency_range + qd_pulses[qubit].frequency, error_signal=result.average.std, - error_phase=np.std(result.phase, axis=0, ddof=1), + error_phase=result.phase_std, ), ) return data diff --git a/src/qibocal/protocols/qubit_spectroscopy_ef.py b/src/qibocal/protocols/qubit_spectroscopy_ef.py index 989c07017..8be2b1633 100644 --- a/src/qibocal/protocols/qubit_spectroscopy_ef.py +++ b/src/qibocal/protocols/qubit_spectroscopy_ef.py @@ -1,7 +1,6 @@ from dataclasses import asdict, dataclass, field import numpy as np -from qibolab import AcquisitionType, AveragingMode, ExecutionParameters from qibolab.platform import Platform from qibolab.pulses import PulseSequence from qibolab.qubits import QubitId @@ -124,12 +123,7 @@ def _acquisition( results = platform.sweep( sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=AveragingMode.SINGLESHOT, - ), + params.execution_parameters, sweeper, ) @@ -141,11 +135,11 @@ def _acquisition( ResSpecType, (qubit), dict( - signal=np.abs(result.average.voltage), - phase=np.mean(result.phase, axis=0), + signal=result.average.magnitude, + phase=result.average.phase, freq=delta_frequency_range + qd_pulses[qubit].frequency, error_signal=result.average.std, - error_phase=np.std(result.phase, axis=0, ddof=1), + error_phase=result.phase_std, ), ) return data @@ -156,25 +150,44 @@ def _plot( ): """Plotting function for QubitSpectroscopy.""" figures, report = spectroscopy_plot(data, target, fit) + show_error_bars = not np.isnan(data[target].error_signal).any() if fit is not None: - report = table_html( - table_dict( - target, - [ - "Frequency 1->2 [Hz]", - "Amplitude [a.u.]", - "Anharmonicity [Hz]", - "Chi2", - ], - [ - (fit.frequency[target], fit.error_fit_pars[target][1]), - (fit.amplitude[target], fit.error_fit_pars[target][0]), - (fit.anharmonicity[target], fit.error_fit_pars[target][2]), - fit.chi2_reduced[target], - ], - display_error=True, + if show_error_bars: + report = table_html( + table_dict( + target, + [ + "Frequency 1->2 [Hz]", + "Amplitude [a.u.]", + "Anharmonicity [Hz]", + "Chi2", + ], + [ + (fit.frequency[target], fit.error_fit_pars[target][1]), + (fit.amplitude[target], fit.error_fit_pars[target][0]), + (fit.anharmonicity[target], fit.error_fit_pars[target][2]), + fit.chi2_reduced[target], + ], + display_error=True, + ) + ) + else: + report = table_html( + table_dict( + target, + [ + "Frequency 1->2 [Hz]", + "Amplitude [a.u.]", + "Anharmonicity [Hz]", + ], + [ + fit.frequency[target], + fit.amplitude[target], + fit.anharmonicity[target], + ], + display_error=False, + ) ) - ) return figures, report diff --git a/src/qibocal/protocols/resonator_spectroscopy.py b/src/qibocal/protocols/resonator_spectroscopy.py index 674a3ebf8..e728873e1 100644 --- a/src/qibocal/protocols/resonator_spectroscopy.py +++ b/src/qibocal/protocols/resonator_spectroscopy.py @@ -3,7 +3,6 @@ import numpy as np import numpy.typing as npt -from qibolab import AcquisitionType, AveragingMode, ExecutionParameters from qibolab.platform import Platform from qibolab.pulses import PulseSequence from qibolab.qubits import QubitId @@ -49,6 +48,8 @@ class ResonatorSpectroscopyParameters(Parameters): attenuation: Optional[int] = None """Readout attenuation (optional). If defined, same attenuation will be used in all qubits. Otherwise the default attenuation defined on the platform runcard will be used""" + hardware_average: bool = True + """By default hardware average will be performed.""" def __post_init__(self): if isinstance(self.power_level, str): @@ -166,12 +167,7 @@ def _acquisition( results = platform.sweep( sequence, - ExecutionParameters( - nshots=params.nshots, - relaxation_time=params.relaxation_time, - acquisition_type=AcquisitionType.INTEGRATION, - averaging_mode=AveragingMode.SINGLESHOT, - ), + params.execution_parameters, sweeper, ) @@ -183,14 +179,13 @@ def _acquisition( ResSpecType, (qubit), dict( - signal=np.abs(result.average.voltage), - phase=np.mean(result.phase, axis=0), + signal=result.average.magnitude, + phase=result.average.phase, freq=delta_frequency_range + ro_pulses[qubit].frequency, error_signal=result.average.std, - error_phase=np.std(result.phase, axis=0, ddof=1), + error_phase=result.phase_std, ), ) - # finally, save the remaining data return data diff --git a/src/qibocal/protocols/utils.py b/src/qibocal/protocols/utils.py index 018b6e184..0584e4c21 100644 --- a/src/qibocal/protocols/utils.py +++ b/src/qibocal/protocols/utils.py @@ -124,7 +124,7 @@ def lorentzian_fit(data, resonator_type=None, fit=None): guess_sigma = abs(frequencies[np.argmax(voltages)] - guess_center) guess_amp = (np.min(voltages) - guess_offset) * guess_sigma * np.pi - model_parameters = [ + initial_parameters = [ guess_amp, guess_center, guess_sigma, @@ -133,22 +133,24 @@ def lorentzian_fit(data, resonator_type=None, fit=None): # fit the model with the data and guessed parameters try: if hasattr(data, "error_signal"): - fit_parameters, perr = curve_fit( - lorentzian, - frequencies, - voltages, - p0=model_parameters, - sigma=data.error_signal, - ) - perr = np.sqrt(np.diag(perr)).tolist() - else: - fit_parameters, perr = curve_fit( - lorentzian, - frequencies, - voltages, - p0=model_parameters, - ) - perr = [0] * 4 + if not np.isnan(data.error_signal).any(): + fit_parameters, perr = curve_fit( + lorentzian, + frequencies, + voltages, + p0=initial_parameters, + sigma=data.error_signal, + ) + perr = np.sqrt(np.diag(perr)).tolist() + model_parameters = list(fit_parameters) + return model_parameters[1] * GHZ_TO_HZ, list(model_parameters), perr + fit_parameters, perr = curve_fit( + lorentzian, + frequencies, + voltages, + p0=initial_parameters, + ) + perr = [0] * 4 model_parameters = list(fit_parameters) return model_parameters[1] * GHZ_TO_HZ, model_parameters, perr except RuntimeError as e: @@ -167,8 +169,7 @@ def spectroscopy_plot(data, qubit, fit: Results = None): fitting_report = "" frequencies = qubit_data.freq * HZ_TO_GHZ signal = qubit_data.signal - errors_signal = qubit_data.error_signal - errors_phase = qubit_data.error_phase + phase = qubit_data.phase fig.add_trace( go.Scatter( @@ -182,19 +183,7 @@ def spectroscopy_plot(data, qubit, fit: Results = None): row=1, col=1, ) - fig.add_trace( - go.Scatter( - x=np.concatenate((frequencies, frequencies[::-1])), - y=np.concatenate((signal + errors_signal, (signal - errors_signal)[::-1])), - fill="toself", - fillcolor=COLORBAND, - line=dict(color=COLORBAND_LINE), - showlegend=True, - name="Signal Errors", - ), - row=1, - col=1, - ) + fig.add_trace( go.Scatter( x=frequencies, @@ -207,19 +196,41 @@ def spectroscopy_plot(data, qubit, fit: Results = None): row=1, col=2, ) - fig.add_trace( - go.Scatter( - x=np.concatenate((frequencies, frequencies[::-1])), - y=np.concatenate((phase + errors_phase, (phase - errors_phase)[::-1])), - fill="toself", - fillcolor=COLORBAND, - line=dict(color=COLORBAND_LINE), - showlegend=True, - name="Phase Errors", - ), - row=1, - col=2, - ) + + show_error_bars = not np.isnan(qubit_data.error_signal).any() + if show_error_bars: + errors_signal = qubit_data.error_signal + errors_phase = qubit_data.error_phase + fig.add_trace( + go.Scatter( + x=np.concatenate((frequencies, frequencies[::-1])), + y=np.concatenate( + (signal + errors_signal, (signal - errors_signal)[::-1]) + ), + fill="toself", + fillcolor=COLORBAND, + line=dict(color=COLORBAND_LINE), + showlegend=True, + name="Signal Errors", + ), + row=1, + col=1, + ) + + fig.add_trace( + go.Scatter( + x=np.concatenate((frequencies, frequencies[::-1])), + y=np.concatenate((phase + errors_phase, (phase - errors_phase)[::-1])), + fill="toself", + fillcolor=COLORBAND, + line=dict(color=COLORBAND_LINE), + showlegend=True, + name="Phase Errors", + ), + row=1, + col=2, + ) + freqrange = np.linspace( min(frequencies), max(frequencies), @@ -249,40 +260,49 @@ def spectroscopy_plot(data, qubit, fit: Results = None): label = "qubit frequency[Hz]" freq = fit.frequency - if data.amplitudes[qubit] is not None: - fitting_report = table_html( - table_dict( - qubit, - [label, "amplitude", "chi2 reduced"], - [ + if data.attenuations: + if data.attenuations[qubit] is not None: + if show_error_bars: + labels = [label, "amplitude", "attenuation", "chi2 reduced"] + values = [ ( freq[qubit], fit.error_fit_pars[qubit][1], ), (data.amplitudes[qubit], 0), + (data.attenuations[qubit], 0), fit.chi2_reduced[qubit], - ], - display_error=True, + ] + else: + labels = [label, "amplitude", "attenuation"] + values = [ + freq[qubit], + data.amplitudes[qubit], + data.attenuations[qubit], + ] + if data.amplitudes[qubit] is not None: + if show_error_bars: + labels = [label, "amplitude", "chi2 reduced"] + values = [ + ( + freq[qubit], + fit.error_fit_pars[qubit][1], + ), + (data.amplitudes[qubit], 0), + fit.chi2_reduced[qubit], + ] + else: + labels = [label, "amplitude"] + values = [freq[qubit], data.amplitudes[qubit]] + + fitting_report = table_html( + table_dict( + qubit, + labels, + values, + display_error=show_error_bars, ) ) - if data.attenuations: - if data.attenuations[qubit] is not None: - fitting_report = table_html( - table_dict( - qubit, - [label, "amplitude", "attenuation", "chi2 reduced"], - [ - ( - freq[qubit], - fit.error_fit_pars[qubit][1], - ), - (data.amplitudes[qubit], 0), - (data.attenuations[qubit], 0), - fit.chi2_reduced[qubit], - ], - display_error=True, - ) - ) fig.update_layout( showlegend=True, diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index 65a238439..92704909e 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -10,7 +10,7 @@ actions: nshots: 1024 readout_amplitude: 0.5 - - id: resonator high power high amplitude + - id: resonator high power high amplitude average operation: resonator_spectroscopy parameters: freq_width: 10_000_000 @@ -19,6 +19,16 @@ actions: power_level: high nshots: 10 + - id: resonator high power high amplitude single shot + operation: resonator_spectroscopy + parameters: + freq_width: 10_000_000 + freq_step: 100_000 + amplitude: 0.4 + power_level: high + nshots: 10 + hardware_average: false + - id: resonator high power low attenuation operation: resonator_spectroscopy @@ -71,7 +81,16 @@ actions: power_level: low nshots: 10 - - id: qubit spectroscopy + - id: qubit spectroscopy average + operation: qubit_spectroscopy + parameters: + drive_amplitude: 0.001 + drive_duration: 1000 + freq_width: 2_000_000 + freq_step: 500_000 + nshots: 10 + + - id: qubit spectroscopy singleshot operation: qubit_spectroscopy parameters: drive_amplitude: 0.001 @@ -79,8 +98,20 @@ actions: freq_width: 2_000_000 freq_step: 500_000 nshots: 10 + hardware_average: false + + - id: qubit spectroscopy ef average + operation: qubit_spectroscopy_ef + #FIXME: add RX12 for qubit 4 + targets: [0, 1, 2, 3] + parameters: + drive_amplitude: 0.001 + drive_duration: 1000 + freq_width: 2_000_000 + freq_step: 500_000 + nshots: 10 - - id: qubit spectroscopy ef + - id: qubit spectroscopy ef single shot operation: qubit_spectroscopy_ef #FIXME: add RX12 for qubit 4 targets: [0, 1, 2, 3] @@ -90,6 +121,7 @@ actions: freq_width: 2_000_000 freq_step: 500_000 nshots: 10 + hardware_average: false - id: resonator flux dependence bias