From 441385e92672890087f6445dbd8ea1928144a420 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 31 Dec 2022 11:01:00 +0100 Subject: [PATCH 01/17] Add types to test common --- qcodes/tests/common.py | 59 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/qcodes/tests/common.py b/qcodes/tests/common.py index ec32ff4005b..63d0bb5b56a 100644 --- a/qcodes/tests/common.py +++ b/qcodes/tests/common.py @@ -1,9 +1,12 @@ +from __future__ import annotations + import copy import cProfile import os import tempfile from contextlib import contextmanager from functools import wraps +from pathlib import Path from time import sleep from typing import ( TYPE_CHECKING, @@ -13,11 +16,14 @@ Generator, Hashable, Optional, + Sequence, Tuple, Type, + TypeVar, ) import pytest +from typing_extensions import ParamSpec import qcodes from qcodes.configuration import Config, DotDict @@ -28,7 +34,9 @@ from pytest import ExceptionInfo -def strip_qc(d, keys=('instrument', '__class__')): +def strip_qc( + d: dict[str, Any], keys: Sequence[str] = ("instrument", "__class__") +) -> dict[str, Any]: # depending on how you run the tests, __module__ can either # have qcodes on the front or not. Just strip it off. for key in keys: @@ -36,12 +44,14 @@ def strip_qc(d, keys=('instrument', '__class__')): d[key] = d[key].replace('qcodes.tests.', 'tests.') return d +T = TypeVar("T") +P = ParamSpec("P") def retry_until_does_not_throw( - exception_class_to_expect: Type[Exception] = AssertionError, - tries: int = 5, - delay: float = 0.1 -) -> Callable[..., Any]: + exception_class_to_expect: type[Exception] = AssertionError, + tries: int = 5, + delay: float = 0.1, +) -> Callable[[Callable[P, T]], Callable[P, T]]: """ Call the decorated function given number of times with given delay between the calls until it does not throw an exception of a given class. @@ -73,10 +83,11 @@ def assert_x_is_true(): ... A callable that runs the decorated function until it does not throw a given exception """ - def retry_until_passes_decorator(func: Callable[..., Any]): + + def retry_until_passes_decorator(func: Callable[P, T]) -> Callable[P, T]: @wraps(func) - def func_retry(*args, **kwargs): + def func_retry(*args: P.args, **kwargs: P.kwargs) -> T: tries_left = tries - 1 while tries_left > 0: try: @@ -94,7 +105,7 @@ def func_retry(*args, **kwargs): return retry_until_passes_decorator -def profile(func): +def profile(func: Callable[P, T]) -> Callable[P, T]: """ Decorator that profiles the wrapped function with cProfile. @@ -106,7 +117,8 @@ def profile(func): where 'p' is an instance of the 'Stats' class), and print the data (for example, 'p.print_stats()'). """ - def wrapper(*args, **kwargs): + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: profile_filename = func.__name__ + '.prof' profiler = cProfile.Profile() result = profiler.runcall(func, *args, **kwargs) @@ -115,7 +127,7 @@ def wrapper(*args, **kwargs): return wrapper -def error_caused_by(excinfo: 'ExceptionInfo[Any]', cause: str) -> bool: +def error_caused_by(excinfo: ExceptionInfo[Any], cause: str) -> bool: """ Helper function to figure out whether an exception was caused by another exception with the message provided. @@ -145,7 +157,7 @@ def error_caused_by(excinfo: 'ExceptionInfo[Any]', cause: str) -> bool: return False -def skip_if_no_fixtures(dbname): +def skip_if_no_fixtures(dbname: str | Path) -> None: if not os.path.exists(dbname): pytest.skip( "No db-file fixtures found. " @@ -158,22 +170,22 @@ class DumyPar(Metadatable): """Docstring for DumyPar. """ - def __init__(self, name): + def __init__(self, name: str): super().__init__() self.name = name self.full_name = name - def __str__(self): + def __str__(self) -> str: return self.full_name - def set(self, value): + def set(self, value: float) -> float: value = value * 2 return value @deprecate(reason="Unused internally", alternative="default_config fixture") @contextmanager -def default_config(user_config: Optional[str] = None): +def default_config(user_config: str | None = None) -> Generator[None, None, None]: """ Context manager to temporarily establish default config settings. This is achieved by overwriting the config paths of the user-, @@ -207,8 +219,7 @@ def default_config(user_config: Optional[str] = None): Config.cwd_file_name = '' Config.schema_cwd_file_name = '' - default_config_obj: Optional[DotDict] = copy.\ - deepcopy(qcodes.config.current_config) + default_config_obj: DotDict | None = copy.deepcopy(qcodes.config.current_config) qcodes.config = Config() try: @@ -231,9 +242,7 @@ def reset_config_on_exit() -> Generator[None, None, None]: Context manager to clean any modification of the in memory config on exit """ - default_config_obj: Optional[DotDict] = copy.deepcopy( - qcodes.config.current_config - ) + default_config_obj: DotDict | None = copy.deepcopy(qcodes.config.current_config) try: yield @@ -242,12 +251,12 @@ def reset_config_on_exit() -> Generator[None, None, None]: def compare_dictionaries( - dict_1: Dict[Hashable, Any], - dict_2: Dict[Hashable, Any], - dict_1_name: Optional[str] = "d1", - dict_2_name: Optional[str] = "d2", + dict_1: dict[Hashable, Any], + dict_2: dict[Hashable, Any], + dict_1_name: str | None = "d1", + dict_2_name: str | None = "d2", path: str = "", -) -> Tuple[bool, str]: +) -> tuple[bool, str]: """ Compare two dictionaries recursively to find non matching elements. From 743d4e9f29dfea453163f31f9b3d528774b924b7 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 31 Dec 2022 11:11:58 +0100 Subject: [PATCH 02/17] Add types to test.conftest --- qcodes/tests/conftest.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/qcodes/tests/conftest.py b/qcodes/tests/conftest.py index 05b8c9c9694..794f5ed8a36 100644 --- a/qcodes/tests/conftest.py +++ b/qcodes/tests/conftest.py @@ -4,7 +4,7 @@ import gc import os import sys -import tempfile +from pathlib import Path from typing import TYPE_CHECKING, Generator import pytest @@ -13,9 +13,10 @@ import qcodes as qc from qcodes.configuration import Config from qcodes.dataset import initialise_database, new_data_set +from qcodes.dataset.data_set import DataSet from qcodes.dataset.descriptions.dependencies import InterDependencies_ from qcodes.dataset.descriptions.param_spec import ParamSpecBase -from qcodes.dataset.experiment_container import new_experiment +from qcodes.dataset.experiment_container import Experiment, new_experiment settings.register_profile("ci", deadline=1000) @@ -24,11 +25,11 @@ if TYPE_CHECKING: from qcodes.configuration import DotDict -def pytest_configure(config): +def pytest_configure(config: pytest.Config) -> None: config.addinivalue_line("markers", "win32: tests that only run under windows") -def pytest_runtest_setup(item): +def pytest_runtest_setup(item: pytest.Item) -> None: ALL = set("darwin linux win32".split()) supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers()) if supported_platforms and sys.platform not in supported_platforms: @@ -36,7 +37,7 @@ def pytest_runtest_setup(item): @pytest.fixture(scope="session", autouse=True) -def disable_telemetry(): +def disable_telemetry() -> Generator[None, None, None]: """ We do not want the tests to send up telemetric information, so we disable that with this fixture. @@ -52,7 +53,7 @@ def disable_telemetry(): @pytest.fixture(scope="function") -def default_config(tmp_path) -> Generator[None, None, None]: +def default_config(tmp_path: Path) -> Generator[None, None, None]: """ Fixture to temporarily establish default config settings. This is achieved by overwriting the config paths of the user-, @@ -110,7 +111,7 @@ def reset_config_on_exit() -> Generator[None, None, None]: @pytest.fixture(scope="session", autouse=True) -def disable_config_subscriber(): +def disable_config_subscriber() -> Generator[None, None, None]: """ We do not want the tests to send generate subscription events unless specifically enabled in the test. So disable any default subscriber defined. @@ -126,7 +127,7 @@ def disable_config_subscriber(): @pytest.fixture(scope="function", name="empty_temp_db") -def _make_empty_temp_db(tmp_path): +def _make_empty_temp_db(tmp_path: Path) -> Generator[None, None, None]: global n_experiments n_experiments = 0 # create a temp database for testing @@ -147,8 +148,9 @@ def _make_empty_temp_db(tmp_path): gc.collect() +@pytest.mark.usefixtures("empty_temp_db") @pytest.fixture(scope="function", name="experiment") -def _make_experiment(empty_temp_db): +def _make_experiment() -> Generator[Experiment, None, None]: e = new_experiment("test-experiment", sample_name="test-sample") try: yield e @@ -157,7 +159,7 @@ def _make_experiment(empty_temp_db): @pytest.fixture(scope="function", name="dataset") -def _make_dataset(experiment): +def _make_dataset(experiment: Experiment) -> Generator[DataSet, None, None]: dataset = new_data_set("test-dataset") try: yield dataset @@ -167,7 +169,9 @@ def _make_dataset(experiment): @pytest.fixture(name="standalone_parameters_dataset") -def _make_standalone_parameters_dataset(dataset): +def _make_standalone_parameters_dataset( + dataset: DataSet, +) -> Generator[DataSet, None, None]: n_params = 3 n_rows = 10 ** 3 params_indep = [ From 4f6b0559242b3b933c21e38384060b414dc1573a Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sat, 31 Dec 2022 11:12:59 +0100 Subject: [PATCH 03/17] Add types to test.validators.conftest --- qcodes/tests/validators/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qcodes/tests/validators/conftest.py b/qcodes/tests/validators/conftest.py index 2a382242b32..e890ad4d390 100644 --- a/qcodes/tests/validators/conftest.py +++ b/qcodes/tests/validators/conftest.py @@ -1,8 +1,8 @@ class AClass: - def method_a(self): + def method_a(self) -> None: raise RuntimeError('function should not get called') -def a_func(): +def a_func() -> None: pass From 4956d4beccb0ad30394cfdc7bb0865fb8fcaf44f Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 1 Jan 2023 19:15:41 +0100 Subject: [PATCH 04/17] Fix don't use mark in fixture --- qcodes/tests/conftest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qcodes/tests/conftest.py b/qcodes/tests/conftest.py index 794f5ed8a36..d00a0d6bc52 100644 --- a/qcodes/tests/conftest.py +++ b/qcodes/tests/conftest.py @@ -148,9 +148,11 @@ def _make_empty_temp_db(tmp_path: Path) -> Generator[None, None, None]: gc.collect() -@pytest.mark.usefixtures("empty_temp_db") +# note that you cannot use mark.usefixtures in a fixture +# so empty_temp_db needs to be passed to this fixture +# even if unused https://github.com/pytest-dev/pytest/issues/3664 @pytest.fixture(scope="function", name="experiment") -def _make_experiment() -> Generator[Experiment, None, None]: +def _make_experiment(empty_temp_db: None) -> Generator[Experiment, None, None]: e = new_experiment("test-experiment", sample_name="test-sample") try: yield e From 47efb6050dfa7b2d28fd14940d8cd886349f2bc4 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 1 Jan 2023 19:17:30 +0100 Subject: [PATCH 05/17] Wip add types to instrument mocks --- qcodes/tests/instrument_mocks.py | 205 +++++++++++++++++++------------ 1 file changed, 126 insertions(+), 79 deletions(-) diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py index 4dcc5126b92..12759485191 100644 --- a/qcodes/tests/instrument_mocks.py +++ b/qcodes/tests/instrument_mocks.py @@ -1,7 +1,7 @@ import logging import time from functools import partial -from typing import Any, Dict, List, Optional, Sequence, Union +from typing import Any, Dict, Generator, List, Optional, Sequence, Union import numpy as np @@ -11,6 +11,7 @@ MultiParameter, Parameter, ParameterWithSetpoints, + ParamRawDataType, ) from qcodes.validators import Arrays, ComplexNumbers, Numbers, OnOff from qcodes.validators import Sequence as ValidatorSequence @@ -20,7 +21,7 @@ class DummyBase(Instrument): - def get_idn(self): + def get_idn(self) -> dict[str, str | None]: return { "vendor": "QCoDeS", "model": str(self.__class__), @@ -43,7 +44,7 @@ class MockParabola(DummyBase): testing of numerical optimizations. """ - def __init__(self, name, **kw): + def __init__(self, name: str, **kw: Any): super().__init__(name, **kw) # Instrument parameters @@ -64,11 +65,11 @@ def __init__(self, name, **kw): self.add_parameter('skewed_parabola', unit='a.u.', get_cmd=self._measure_skewed_parabola) - def _measure_parabola(self): + def _measure_parabola(self) -> float: return (self.x.get()**2 + self.y.get()**2 + self.z.get()**2 + self.noise.get()*np.random.rand(1)) - def _measure_skewed_parabola(self): + def _measure_skewed_parabola(self) -> float: """ Adds an -x term to add a corelation between the parameters. """ @@ -88,7 +89,7 @@ class MockMetaParabola(InstrumentBase): snapshottable in a station. """ - def __init__(self, name, mock_parabola_inst, **kw): + def __init__(self, name: str, mock_parabola_inst: MockParabola, **kw: Any): """ Create a new MockMetaParabola, connected to an existing MockParabola instance. """ @@ -107,20 +108,22 @@ def __init__(self, name, mock_parabola_inst, **kw): self.add_parameter('skewed_parabola', unit='a.u.', get_cmd=self._get_skew_parabola) - def _get_parabola(self): + def _get_parabola(self) -> float: val = self.mock_parabola_inst.parabola.get() return val*self.gain.get() - def _get_skew_parabola(self): + def _get_skew_parabola(self) -> float: val = self.mock_parabola_inst.skewed_parabola.get() return val*self.gain.get() class DummyInstrument(DummyBase): - - def __init__(self, name: str = 'dummy', - gates: Sequence[str] = ('dac1', 'dac2', 'dac3'), **kwargs): - + def __init__( + self, + name: str = "dummy", + gates: Sequence[str] = ("dac1", "dac2", "dac3"), + **kwargs: Any, + ): """ Create a dummy instrument that can be used for testing @@ -146,7 +149,7 @@ def __init__(self, name: str = 'dummy', class DummyFailingInstrument(DummyBase): - def __init__(self, name: str = "dummy", fail: bool = True, **kwargs): + def __init__(self, name: str = "dummy", fail: bool = True, **kwargs: Any): """ Create a dummy instrument that fails on initialization @@ -196,16 +199,17 @@ def __init__(self, name: str = "dummy", **kwargs: Any): class DmmExponentialParameter(Parameter): - def __init__(self, name, **kwargs): + def __init__(self, name: str, **kwargs: Any): super().__init__(name, **kwargs) self._ed = self._exponential_decay(5, 0.2) next(self._ed) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: """ This method is automatically wrapped to provide a ``get`` method on the parameter instance. """ + assert isinstance(self.root_instrument, DummyInstrumentWithMeasurement) dac = self.root_instrument._setter_instr val = self._ed.send(dac.ch1.cache.get()) next(self._ed) @@ -217,14 +221,13 @@ def get_raw(self): return val @staticmethod - def _exponential_decay(a: float, b: float): + def _exponential_decay(a: float, b: float) -> Generator[float, float, None]: """ Yields a*exp(-b*x) where x is put in """ - x = 0 + x = 0.0 while True: - x = yield - yield a * np.exp(-b * x) + 0.02 * a * np.random.randn() + x = yield a * np.exp(-b * x) + 0.02 * a * np.random.randn() class DmmGaussParameter(Parameter): @@ -237,14 +240,15 @@ def __init__(self, name: str, **kwargs: Any): self._gauss = self._gauss_model() next(self._gauss) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: """ This method is automatically wrapped to provide a ``get`` method on the parameter instance. """ + assert isinstance(self.root_instrument, DummyInstrumentWithMeasurement) dac = self.root_instrument._setter_instr val = self._gauss.send((dac.ch1.cache.get(), dac.ch2.cache.get())) - next(self._gauss) + # next(self._gauss) if self.root_instrument is not None: mylogger = self.root_instrument.log else: @@ -252,25 +256,26 @@ def get_raw(self): mylogger.debug("Getting raw value of parameter: %s as %s", self.full_name, val) return val - def _gauss_model(self): + def _gauss_model(self) -> Generator[float, tuple[float, float], None]: """ Returns a generator sampling a gaussian. The gaussian is normalised such that its maximal value is simply 1 """ + + def gauss_2d(x: float, y: float) -> np.floating: + return np.exp( + -((self.x0 - x) ** 2 + (self.y0 - y) ** 2) / 2 / self.sigma**2 + ) * np.exp(2 * self.sigma**2) + + x = 0.0 + y = 0.0 while True: - (x, y) = yield - model = np.exp(-((self.x0-x)**2+(self.y0-y)**2)/2/self.sigma**2)*np.exp(2*self.sigma**2) - noise = np.random.randn()*self.noise - yield model + noise + noise = np.random.randn() * self.noise + (x, y) = yield float(gauss_2d(x, y) + noise) class DummyInstrumentWithMeasurement(DummyBase): - - def __init__( - self, - name: str, - setter_instr: DummyInstrument, - **kwargs): + def __init__(self, name: str, setter_instr: DummyInstrument, **kwargs: Any): super().__init__(name=name, **kwargs) self._setter_instr = setter_instr self.add_parameter('v1', @@ -294,7 +299,7 @@ class DummyChannel(InstrumentChannel): A single dummy channel implementation """ - def __init__(self, parent, name, channel, **kwargs): + def __init__(self, parent: Instrument, name: str, channel: str, **kwargs: Any): super().__init__(parent, name, **kwargs) self._channel = channel @@ -446,13 +451,15 @@ class DummyChannelInstrument(Instrument): Dummy instrument with channels """ - def __init__(self, name, channel_names=None, **kwargs): + def __init__( + self, name: str, channel_names: Sequence[str] | None = None, **kwargs: Any + ): super().__init__(name, **kwargs) channels = ChannelList(self, "TempSensors", DummyChannel, snapshotable=False) if channel_names is None: - channel_ids = ("A", "B", "C", "D", "E", "F") + channel_ids: Sequence[str] = ("A", "B", "C", "D", "E", "F") channel_names = tuple(f"Chan{chan_name}" for chan_name in channel_ids) else: channel_ids = channel_names @@ -478,13 +485,14 @@ class MultiGetter(MultiParameter): MultiGetter(one=1, onetwo=(1, 2)) """ - def __init__(self, **kwargs): + + def __init__(self, **kwargs: Any): names = tuple(sorted(kwargs.keys())) self._return = tuple(kwargs[k] for k in names) shapes = tuple(np.shape(v) for v in self._return) super().__init__(name='multigetter', names=names, shapes=shapes) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: return self._return @@ -494,7 +502,12 @@ class MultiSetPointParam(MultiParameter): and so on are copied correctly to the individual arrays in the datarray. """ - def __init__(self, instrument=None, name="multi_setpoint_param", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "multi_setpoint_param", + **kwargs: Any, + ): shapes = ((5,), (5,)) names = ('multi_setpoint_param_this', 'multi_setpoint_param_that') labels = ('this label', 'that label') @@ -521,7 +534,7 @@ def __init__(self, instrument=None, name="multi_setpoint_param", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: items = (np.zeros(5), np.ones(5)) return items @@ -532,7 +545,12 @@ class Multi2DSetPointParam(MultiParameter): and so on are copied correctly to the individual arrays in the datarray. """ - def __init__(self, instrument=None, name="multi_2d_setpoint_param", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "multi_2d_setpoint_param", + **kwargs: Any, + ): shapes = ((5, 3), (5, 3)) names = ('this', 'that') labels = ('this label', 'that label') @@ -573,7 +591,7 @@ def __init__(self, instrument=None, name="multi_2d_setpoint_param", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: items = (np.zeros((5, 3)), np.ones((5, 3))) return items @@ -585,7 +603,12 @@ class Multi2DSetPointParam2Sizes(MultiParameter): shapes. """ - def __init__(self, instrument=None, name="multi_2d_setpoint_param", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "multi_2d_setpoint_param", + **kwargs: Any, + ): shapes = ((5, 3), (2, 7)) names = ('this_5_3', 'this_2_7') labels = ('this label', 'that label') @@ -629,7 +652,7 @@ def __init__(self, instrument=None, name="multi_2d_setpoint_param", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: items = (np.zeros((5, 3)), np.ones((2, 7))) return items @@ -640,7 +663,12 @@ class MultiScalarParam(MultiParameter): Parameter with no setpoints etc. """ - def __init__(self, instrument=None, name="multiscalarparameter", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "multiscalarparameter", + **kwargs: Any, + ): shapes = ((), ()) names = ('thisparam', 'thatparam') labels = ('thisparam label', 'thatparam label') @@ -657,7 +685,7 @@ def __init__(self, instrument=None, name="multiscalarparameter", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: items = (0, 1) return items @@ -668,7 +696,12 @@ class ArraySetPointParam(ArrayParameter): and so on are copied correctly to the individual arrays in the datarray. """ - def __init__(self, instrument=None, name="array_setpoint_param", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "array_setpoint_param", + **kwargs: Any, + ): shape = (5,) label = 'this label' unit = 'this unit' @@ -690,7 +723,7 @@ def __init__(self, instrument=None, name="array_setpoint_param", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: item = np.ones(5) + 1 return item @@ -700,7 +733,12 @@ class ComplexArraySetPointParam(ArrayParameter): Arrayparameter that returns complex numbers """ - def __init__(self, instrument=None, name="testparameter", **kwargs): + def __init__( + self, + instrument: InstrumentBase | None = None, + name: str = "testparameter", + **kwargs: Any, + ): shape = (5,) label = 'this label' unit = 'this unit' @@ -722,7 +760,7 @@ def __init__(self, instrument=None, name="testparameter", **kwargs): **kwargs, ) - def get_raw(self): + def get_raw(self) -> ParamRawDataType: item = np.arange(5) - 1j*np.arange(5) return item @@ -732,13 +770,21 @@ class GeneratedSetPoints(Parameter): A parameter that generates a setpoint array from start, stop and num points parameters. """ - def __init__(self, startparam, stopparam, numpointsparam, *args, **kwargs): + + def __init__( + self, + startparam: Parameter, + stopparam: Parameter, + numpointsparam: Parameter, + *args: Any, + **kwargs: Any, + ): super().__init__(*args, **kwargs) self._startparam = startparam self._stopparam = stopparam self._numpointsparam = numpointsparam - def get_raw(self): + def get_raw(self) -> ParamRawDataType: return np.linspace(self._startparam(), self._stopparam(), self._numpointsparam()) @@ -749,7 +795,8 @@ class DummyParameterWithSetpoints1D(ParameterWithSetpoints): `dummy_n_points` parameter in the instrument. """ - def get_raw(self): + def get_raw(self) -> ParamRawDataType: + assert isinstance(self.instrument, DummyChannel) npoints = self.instrument.dummy_n_points() return np.random.rand(npoints) @@ -760,7 +807,8 @@ class DummyParameterWithSetpoints2D(ParameterWithSetpoints): `dummy_n_points` and `dummy_n_points_2` parameters in the instrument. """ - def get_raw(self): + def get_raw(self) -> ParamRawDataType: + assert isinstance(self.instrument, DummyChannel) npoints = self.instrument.dummy_n_points() npoints_2 = self.instrument.dummy_n_points_2() return np.random.rand(npoints, npoints_2) @@ -773,12 +821,15 @@ class DummyParameterWithSetpointsComplex(ParameterWithSetpoints): `dummy_n_points` parameter in the instrument. Returns Complex values """ - def get_raw(self): + def get_raw(self) -> ParamRawDataType: + assert isinstance(self.instrument, DummyChannel) npoints = self.instrument.dummy_n_points() return np.random.rand(npoints) + 1j*np.random.rand(npoints) -def setpoint_generator(*sp_bases): +def setpoint_generator( + *sp_bases: Sequence[float], +) -> tuple[np.ndarray | Sequence[float], ...]: """ Helper function to generate setpoints in the format that ArrayParameter (and MultiParameter) expects @@ -789,7 +840,7 @@ def setpoint_generator(*sp_bases): Returns: """ - setpoints = [] + setpoints: List[np.ndarray | Sequence[float]] = [] for i, sp_base in enumerate(sp_bases): if i == 0: setpoints.append(sp_base) @@ -835,7 +886,7 @@ def __init__(self, name: str, params: Sequence[str] = ('v1', 'v2', 'v3'), set_cmd=None, get_cmd=partial(self._getter, p_name)) - def _getter(self, name: str): + def _getter(self, name: str) -> ParamRawDataType: val = self.parameters[name].cache.get(get_if_invalid=False) self._get_calls[name] += 1 return val @@ -853,10 +904,11 @@ def snapshot_base(self, update: Optional[bool] = True, class MockField(DummyBase): def __init__( - self, - name: str, - vals: Numbers = Numbers(min_value=-1., max_value=1.), - **kwargs): + self, + name: str, + vals: Numbers = Numbers(min_value=-1.0, max_value=1.0), + **kwargs: Any, + ): """Mock instrument for emulating a magnetic field axis Args: @@ -881,7 +933,7 @@ def __init__( self._fr = self._field_ramp() next(self._fr) - def get_field(self): + def get_field(self) -> float: """ This method is automatically wrapped to provide a ``get`` method on the parameter instance. @@ -893,7 +945,7 @@ def get_field(self): self._field = val return self._field - def set_field(self, value, block: bool = True): + def set_field(self, value: float, block: bool = True) -> None | float: if self._field == value: return value @@ -908,8 +960,10 @@ def set_field(self, value, block: bool = True): time.sleep(wait_time) self._field = value return value + else: + return None - def _field_ramp_fcn(self, _time: float): + def _field_ramp_fcn(self, _time: float) -> float: if self._wait_time is None: return self._field elif _time <= 0.0: @@ -919,24 +973,17 @@ def _field_ramp_fcn(self, _time: float): dfield = self.ramp_rate() * _time / 60.0 return self._start_field + self._sign * dfield - def _field_ramp(self): + def _field_ramp(self) -> Generator[float, float, None]: """ Yields field for a given point in time """ + time = 0.0 while True: - _time = yield - if _time is None: - _time = 0.0 - - yield float(self._field_ramp_fcn(_time)) + time = yield float(self._field_ramp_fcn(time)) class MockLockin(DummyBase): - - def __init__( - self, - name: str, - **kwargs): + def __init__(self, name: str, **kwargs: Any): super().__init__(name=name, **kwargs) self.add_parameter("X", parameter_class=Parameter, @@ -975,7 +1022,7 @@ class MockDACChannel(InstrumentChannel): A single dummy channel implementation """ - def __init__(self, parent, name, num): + def __init__(self, parent: InstrumentBase, name: str, num: str): super().__init__(parent, name) self._num = num @@ -1007,12 +1054,12 @@ def __init__(self, parent, name, num): vals=OnOff(), get_cmd=None, set_cmd=None) - def channel_number(self): + def channel_number(self) -> str: return self._num class MockDAC(DummyBase): - def __init__(self, name: str = "mdac", num_channels: int = 10, **kwargs): + def __init__(self, name: str = "mdac", num_channels: int = 10, **kwargs: Any): """ Create a dummy instrument that can be used for testing @@ -1041,7 +1088,7 @@ def __init__( parent: InstrumentBase, name: str, channel: Union[str, InstrumentChannel], - current_valid_range: Optional[List[float]] = None, + current_valid_range: Optional[Sequence[float]] = None, ) -> None: """ A custom instrument channel emulating an existing channel. From 2107345a189b18dc69cb5a3f749f4175ab900353 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 1 Jan 2023 19:18:27 +0100 Subject: [PATCH 06/17] Wip types for parameter conftest --- qcodes/tests/parameter/conftest.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qcodes/tests/parameter/conftest.py b/qcodes/tests/parameter/conftest.py index e5d1a9f01af..84b431b1c50 100644 --- a/qcodes/tests/parameter/conftest.py +++ b/qcodes/tests/parameter/conftest.py @@ -1,5 +1,5 @@ from collections import namedtuple -from typing import Any, Optional +from typing import Any, Generator, Optional import pytest @@ -12,37 +12,37 @@ @pytest.fixture(params=(True, False, NOT_PASSED)) -def snapshot_get(request): +def snapshot_get(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(params=(True, False, NOT_PASSED)) -def snapshot_value(request): +def snapshot_value(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(params=(None, False, NOT_PASSED)) -def get_cmd(request): +def get_cmd(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(params=(True, False, NOT_PASSED)) -def get_if_invalid(request): +def get_if_invalid(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(params=(True, False, None, NOT_PASSED)) -def update(request): +def update(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(params=(True, False)) -def cache_is_valid(request): +def cache_is_valid(request: pytest.FixtureRequest) -> Any: return request.param @pytest.fixture(name="dummy_instrument") -def _make_dummy_instrument(): +def _make_dummy_instrument() -> Generator[DummyChannelInstrument, None, None]: instr = DummyChannelInstrument("dummy") yield instr instr.close() @@ -66,9 +66,9 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._get_count = 0 - def get_raw(self): + def get_raw(self) -> Any: self._get_count += 1 - return self.cache._raw_value + return self.cache.raw_value class SettableParam(Parameter): From a0aed8fd86d2247f7a086c1f7e10d26bc11af924 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 1 Jan 2023 19:18:57 +0100 Subject: [PATCH 07/17] Add types for validator string tests --- qcodes/tests/validators/test_string.py | 38 ++++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/qcodes/tests/validators/test_string.py b/qcodes/tests/validators/test_string.py index 698184c4fbb..c69dbcfeb82 100644 --- a/qcodes/tests/validators/test_string.py +++ b/qcodes/tests/validators/test_string.py @@ -17,20 +17,20 @@ True, False, None, AClass, AClass(), a_func] -def test_unlimited(): +def test_unlimited() -> None: s = Strings() for v in strings: s.validate(v) - for v in not_strings: + for vv in not_strings: with pytest.raises(TypeError): - s.validate(v) + s.validate(vv) # type: ignore[arg-type] assert repr(s) == '' -def test_min(): +def test_min() -> None: for min_len in [0, 1, 5, 10, 100]: s = Strings(min_length=min_len) for v in strings: @@ -40,14 +40,15 @@ def test_min(): with pytest.raises(ValueError): s.validate(v) - for v in not_strings: + for vv in not_strings: with pytest.raises(TypeError): - s.validate(v) + s.validate(vv) # type: ignore[arg-type] + s = Strings(min_length=100) assert repr(s) == '=100>' -def test_max(): +def test_max() -> None: for max_len in [1, 5, 10, 100]: s = Strings(max_length=max_len) for v in strings: @@ -57,14 +58,15 @@ def test_max(): with pytest.raises(ValueError): s.validate(v) - for v in not_strings: + s = Strings(max_length=100) + for vv in not_strings: with pytest.raises(TypeError): - s.validate(v) + s.validate(vv) # type: ignore[arg-type] assert repr(s) == '' -def test_range(): +def test_range() -> None: s = Strings(1, 10) for v in strings: @@ -74,9 +76,9 @@ def test_range(): with pytest.raises(ValueError): s.validate(v) - for v in not_strings: + for vv in not_strings: with pytest.raises(TypeError): - s.validate(v) + s.validate(vv) # type: ignore[arg-type] assert repr(s) == '' @@ -84,9 +86,9 @@ def test_range(): assert repr(Strings(10, 10)) == '' -def test_failed_strings(): +def test_failed_strings() -> None: with pytest.raises(TypeError): - Strings(1, 2, 3) + Strings(1, 2, 3) # type: ignore[call-arg] with pytest.raises(TypeError): Strings(10, 9) @@ -95,17 +97,17 @@ def test_failed_strings(): Strings(max_length=0) with pytest.raises(TypeError): - Strings(min_length=1e12) + Strings(min_length=1e12) # type: ignore[arg-type] for length in [-1, 3.5, '2', None]: with pytest.raises(TypeError): - Strings(max_length=length) + Strings(max_length=length) # type: ignore[arg-type] with pytest.raises(TypeError): - Strings(min_length=length) + Strings(min_length=length) # type: ignore[arg-type] -def test_valid_values(): +def test_valid_values() -> None: val = Strings() for vval in val.valid_values: val.validate(vval) From a5290bf383def2347a283ae061869dd3616fdaf8 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 15:16:52 +0100 Subject: [PATCH 08/17] remove now uneeded next --- qcodes/tests/instrument_mocks.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py index 12759485191..894ef535943 100644 --- a/qcodes/tests/instrument_mocks.py +++ b/qcodes/tests/instrument_mocks.py @@ -212,7 +212,6 @@ def get_raw(self) -> ParamRawDataType: assert isinstance(self.root_instrument, DummyInstrumentWithMeasurement) dac = self.root_instrument._setter_instr val = self._ed.send(dac.ch1.cache.get()) - next(self._ed) if self.root_instrument is not None: mylogger = self.root_instrument.log else: @@ -248,7 +247,6 @@ def get_raw(self) -> ParamRawDataType: assert isinstance(self.root_instrument, DummyInstrumentWithMeasurement) dac = self.root_instrument._setter_instr val = self._gauss.send((dac.ch1.cache.get(), dac.ch2.cache.get())) - # next(self._gauss) if self.root_instrument is not None: mylogger = self.root_instrument.log else: @@ -941,7 +939,6 @@ def get_field(self) -> float: if self._ramp_start_time: _time_since_start = time.time() - self._ramp_start_time val = self._fr.send(_time_since_start) - next(self._fr) self._field = val return self._field From 9861ffb696966e0ce34118d81bc277dac03101d2 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 15:35:56 +0100 Subject: [PATCH 09/17] fix typecheck in MyParam --- qcodes/tests/dataset/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qcodes/tests/dataset/conftest.py b/qcodes/tests/dataset/conftest.py index 89ef61fad52..5d2bcb6fd2e 100644 --- a/qcodes/tests/dataset/conftest.py +++ b/qcodes/tests/dataset/conftest.py @@ -483,11 +483,13 @@ def complex_num_instrument(): class MyParam(Parameter): def get_raw(self): + assert self.instrument is not None return self.instrument.setpoint() + 1j*self.instrument.setpoint() class RealPartParam(Parameter): def get_raw(self): + assert self.instrument is not None return self.instrument.complex_setpoint().real dummyinst = DummyInstrument('dummy_channel_inst', gates=()) From 16bee50d4f5d28661545f4a2df5a32a82bc45609 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 15:36:23 +0100 Subject: [PATCH 10/17] Allow setupoint generator to take numpy arrays --- qcodes/tests/instrument_mocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py index 894ef535943..d4aa3bca97c 100644 --- a/qcodes/tests/instrument_mocks.py +++ b/qcodes/tests/instrument_mocks.py @@ -826,7 +826,7 @@ def get_raw(self) -> ParamRawDataType: def setpoint_generator( - *sp_bases: Sequence[float], + *sp_bases: Sequence[float] | np.ndarray, ) -> tuple[np.ndarray | Sequence[float], ...]: """ Helper function to generate setpoints in the format that ArrayParameter From 688b7da734e4f72e0904b86aad342ee5798ce9d5 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 15:41:03 +0100 Subject: [PATCH 11/17] Fix dateset/confttest to typecheck --- qcodes/tests/dataset/conftest.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/qcodes/tests/dataset/conftest.py b/qcodes/tests/dataset/conftest.py index 5d2bcb6fd2e..7af4c8c7e43 100644 --- a/qcodes/tests/dataset/conftest.py +++ b/qcodes/tests/dataset/conftest.py @@ -9,6 +9,7 @@ import pytest import qcodes as qc +from qcodes.dataset.data_set import DataSet from qcodes.dataset.descriptions.dependencies import InterDependencies_ from qcodes.dataset.descriptions.param_spec import ParamSpec, ParamSpecBase from qcodes.dataset.measurements import Measurement @@ -203,6 +204,7 @@ def array_dataset(experiment, request): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -235,6 +237,7 @@ def array_dataset_with_nulls(experiment, request): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -251,6 +254,7 @@ def multi_dataset(experiment, request): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -267,6 +271,7 @@ def different_setpoint_dataset(experiment, request): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -287,6 +292,7 @@ def array_in_scalar_dataset(experiment): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -308,6 +314,7 @@ def varlen_array_in_scalar_dataset(experiment): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -334,6 +341,7 @@ def array_in_scalar_dataset_unrolled(experiment): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -355,6 +363,7 @@ def array_in_str_dataset(experiment, request): try: yield datasaver.dataset finally: + assert isinstance(datasaver.dataset, DataSet) datasaver.dataset.conn.close() @@ -690,6 +699,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def get_raw(self): + assert isinstance(self.vals, Arrays) shape = self.vals.shape return np.random.rand(*shape) From b144f417faedffe82a2c8f3aa98a278b3b970a35 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 15:48:46 +0100 Subject: [PATCH 12/17] Add __future__ annotations --- qcodes/tests/dataset/conftest.py | 2 ++ qcodes/tests/instrument_mocks.py | 20 ++++++++++++-------- qcodes/tests/parameter/conftest.py | 4 +++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/qcodes/tests/dataset/conftest.py b/qcodes/tests/dataset/conftest.py index 7af4c8c7e43..40ca97e287b 100644 --- a/qcodes/tests/dataset/conftest.py +++ b/qcodes/tests/dataset/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import gc import os import shutil diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py index d4aa3bca97c..63f055fded5 100644 --- a/qcodes/tests/instrument_mocks.py +++ b/qcodes/tests/instrument_mocks.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import time from functools import partial @@ -838,7 +840,7 @@ def setpoint_generator( Returns: """ - setpoints: List[np.ndarray | Sequence[float]] = [] + setpoints: list[np.ndarray | Sequence[float]] = [] for i, sp_base in enumerate(sp_bases): if i == 0: setpoints.append(sp_base) @@ -889,9 +891,11 @@ def _getter(self, name: str) -> ParamRawDataType: self._get_calls[name] += 1 return val - def snapshot_base(self, update: Optional[bool] = True, - params_to_skip_update: Optional[Sequence[str]] = None - ) -> Dict[Any, Any]: + def snapshot_base( + self, + update: bool | None = True, + params_to_skip_update: Sequence[str] | None = None, + ) -> dict[Any, Any]: if params_to_skip_update is None: params_to_skip_update = self._params_to_skip snap = super().snapshot_base( @@ -926,8 +930,8 @@ def __init__( initial_value=0.1, unit='T/min', get_cmd=None, set_cmd=None) - self._ramp_start_time: Optional[float] = None - self._wait_time: Optional[float] = None + self._ramp_start_time: float | None = None + self._wait_time: float | None = None self._fr = self._field_ramp() next(self._fr) @@ -1084,8 +1088,8 @@ def __init__( self, parent: InstrumentBase, name: str, - channel: Union[str, InstrumentChannel], - current_valid_range: Optional[Sequence[float]] = None, + channel: str | InstrumentChannel, + current_valid_range: Sequence[float] | None = None, ) -> None: """ A custom instrument channel emulating an existing channel. diff --git a/qcodes/tests/parameter/conftest.py b/qcodes/tests/parameter/conftest.py index 84b431b1c50..ddc7ea60072 100644 --- a/qcodes/tests/parameter/conftest.py +++ b/qcodes/tests/parameter/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import namedtuple from typing import Any, Generator, Optional @@ -159,7 +161,7 @@ def __init__(self, name: str, param: Parameter, **kwargs): super().__init__(name=name, **kwargs) @property - def underlying_instrument(self) -> Optional[InstrumentBase]: + def underlying_instrument(self) -> InstrumentBase | None: return self._param.instrument def get_raw(self): From d812300bddbf8958b641cfa46c955dff8adf91f6 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Wed, 18 Jan 2023 15:51:08 +0100 Subject: [PATCH 13/17] remove qdevil drivers from api docs --- docs/Makefile | 1 + docs/make.bat | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/Makefile b/docs/Makefile index 7fd6c1c255d..3abc7139762 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -41,6 +41,7 @@ genapi: ../qcodes/instrument_drivers/oxford \ ../qcodes/instrument_drivers/Lakeshore \ ../qcodes/instrument_drivers/QDev/* \ + ../qcodes/instrument_drivers/QDevil/* \ ../qcodes/instrument_drivers/QuantumDesign/* \ ../qcodes/instrument_drivers/rigol/* \ ../qcodes/instrument_drivers/rohde_schwarz/* \ diff --git a/docs/make.bat b/docs/make.bat index 659bb54cae4..686877aeae1 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -52,6 +52,7 @@ sphinx-apidoc -o _auto -d 10 ..\qcodes ^ ..\qcodes\instrument_drivers\oxford ^ ..\qcodes\instrument_drivers\QuantumDesign\* ^ ..\qcodes\instrument_drivers\QDev\* ^ + ..\qcodes\instrument_drivers\QDevil\* ^ ..\qcodes\instrument_drivers\rigol\* ^ ..\qcodes\instrument_drivers\rohde_schwarz\* ^ ..\qcodes\instrument_drivers\stahl\* ^ From cbc30de1ebba3595f4793500065a41b3aed51b9d Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Wed, 18 Jan 2023 15:51:29 +0100 Subject: [PATCH 14/17] deprecate QDevil QDac 1 driver --- qcodes/instrument_drivers/QDevil/QDevil_QDAC.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qcodes/instrument_drivers/QDevil/QDevil_QDAC.py b/qcodes/instrument_drivers/QDevil/QDevil_QDAC.py index 1dffe4877d1..c606590a5b4 100644 --- a/qcodes/instrument_drivers/QDevil/QDevil_QDAC.py +++ b/qcodes/instrument_drivers/QDevil/QDevil_QDAC.py @@ -17,6 +17,7 @@ from qcodes import validators as vals from qcodes.instrument import ChannelList, InstrumentChannel, VisaInstrument from qcodes.parameters import MultiChannelInstrumentParameter, ParamRawDataType +from qcodes.utils import deprecate LOG = logging.getLogger(__name__) @@ -188,6 +189,7 @@ def get_raw(self) -> Tuple[ParamRawDataType, ...]: return output +@deprecate(alternative="QDevil QDAC 1 driver in qcodes_contrib_drivers.") class QDac(VisaInstrument): """ Channelised driver for the QDevil QDAC voltage source. From 6c1ff03cc64e1b76917dcfd544c87214ccffa514 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Wed, 18 Jan 2023 15:52:17 +0100 Subject: [PATCH 15/17] remove QDevil notebook --- .../QCodes example with QDevil_QDAC.ipynb | 591 ------------------ 1 file changed, 591 deletions(-) delete mode 100644 docs/examples/driver_examples/QCodes example with QDevil_QDAC.ipynb diff --git a/docs/examples/driver_examples/QCodes example with QDevil_QDAC.ipynb b/docs/examples/driver_examples/QCodes example with QDevil_QDAC.ipynb deleted file mode 100644 index 87e637aafba..00000000000 --- a/docs/examples/driver_examples/QCodes example with QDevil_QDAC.ipynb +++ /dev/null @@ -1,591 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# QCoDeS Example with QDevil_QDAC" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from time import sleep\n", - "\n", - "import numpy as np\n", - "\n", - "import qcodes as qc\n", - "import qcodes.instrument_drivers.QDevil.QDevil_QDAC as QDac\n", - "from qcodes.instrument_drivers.QDevil.QDevil_QDAC import Mode" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Initialisation\n", - "When initialised, the driver will read in the state of the QDAC to the extend spossible. This means that initialisation does not change any outputs, implying that any ongoing ramping is continuing undisturbed. The initialisation is, however, **not** able to figure out if any **slopes** have been assigned to channels, see later. So these will have to be set again by the user. \n", - "\n", - "During the initialisation all channels are queried in order to update the parmeter cache. However, as the current query is very slow due to the long current sensor integration time, it is optional to update currents. They are only read at startup if the **update_currents** flag is set to True. \n", - "\n", - "NOTE: After switching the QDAC off and back on the driver has to be re-initialised, OR the reset() command has to be executed." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Connect to the instrument\n", - "# By default the initialisation skips reading the current sensors on all channels\n", - "# as this takes some 0.2-0.5 secs per channel due to the sensor settling time. \n", - "# You can force reading the current sensors at startup by specifiying \"update_currents=True\" in the call.\n", - "\n", - "qdac = QDac.QDac(name='qdac', address='ASRL2::INSTR', update_currents=False)\n", - "print(\"Number of channels: \",qdac.num_chans)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic QDAC Usage\n", - "\n", - "The QDevil_QDAC driver supports controlling each individual BNC output channel. Each output channel \"qdac.ch##.\" has seven attributes:\n", - " * v: DC voltage\n", - " * i: Current out (read-only)\n", - " * mode: the combined voltage output and current sensor range: Mode.vhigh_ihigh, Mode.vhigh_ilow, Mode.vlow_ilow\n", - " * slope: Maximum ramp rate for an output channel when changing teh DC voltage,v.\n", - " * sync: Sync output assigned to a channel \n", - " * sync_delay: Sync pulse delay \n", - " * sync_duration: Sync pulse duration\n", - " \n", - "The slope is the (maximal) slope in V/s that the channel will allow its voltage to change by. By default, all channels have a slope of \"Inf\". The slope can be changed dynamically, but no more than 8 channels can be ramped simultaneously.\n", - "\n", - "In addition this driver supports:\n", - " * Reset the QDAC to start up conditions. Allows continuing operation after the QDAC has been \n", - " powered off/on without restarting teh driver\n", - " * Simultaneous ramping of up to 8 channels\n", - " * 2D ramping of two groups of channels (slow and fast channels, up to 8 in total)\n", - " * Override of protection against mode change for non-zero output voltages\n", - " * Reading the internal temperature sensors \n", - " * Pretty printing the state of all channels, of assigned sync outputs and of assigned slopes " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Setting voltages and reading currents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Setting the output voltage of a channel using \"set\"\n", - "qdac.ch01.v.set(1)\n", - "# Reading the output voltage of a channel using \"get\"\n", - "print(f'Channel 1 voltage: {qdac.ch01.v.get()} {qdac.ch01.v.unit}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Setting the output voltage of a channel using short-hand notation, which is used hereafter\n", - "qdac.ch01.v(-1)\n", - "# Reading the output voltage of a channel using short hand notion \"qdac.ch01.v()\", which is used hereafter\n", - "print(f'Channel 1 voltage: {qdac.ch01.v()} {qdac.ch01.v.unit}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Reading the current output of a channel \n", - "print(qdac.ch01.i(), qdac.ch01.i.unit)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Smooth ramping between voltages" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# For smooth voltage changes the maximal voltage change (in V/s) may be set for each channel\n", - "qdac.ch01.slope(1)\n", - "qdac.ch02.slope(2)\n", - "# An overview may be printed (all other channels have 'Inf' slope)\n", - "qdac.print_slopes()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Now setting channel 1 and 2 voltages will cause slow ramping to 0V (1 V/s and 2 V/s, respectively)\n", - "# Note that ch02 is already at 0 V, so the ramping function will complain bacause a ramp time\n", - "# less than 2 ms is not possible.\n", - "qdac.ch01.v(0)\n", - "qdac.ch02.v(0)\n", - "sleep(1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Note that only 8 (or fewer) channels can be slow ramped at a time\n", - "# To disable slow ramping of a channel, set its slope to 'Inf':\n", - "qdac.ch01.slope('Inf')\n", - "qdac.print_slopes()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Addressing multiple channels\n", - "Multiple channels can be addressed simultaneously via the 'channels' list, by use of slicing.\n", - "Note that numbering goes from 0 to N-1, where N is the number of channels. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This will query voltages of all channels of a 24 channel QDAC \n", - "# Note that index 0 refer to channel 01, and so on \n", - "print(qdac.channels[0:8].v())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Similarly, we may set them. The outputs will not change simultaneously but witin some milliseconds.\n", - "qdac.channels[0:8].v(-0.9)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Output a SYNC pulse\n", - "The QDAC can output a puls one one of the SYNC outputs when a channel is ramped, either using the \"slope\" functionality, see above, or when using one of the ramping functions below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# To each channel one may assign a SYNC output\n", - "# SYNC output 1 will fire a 10 ms 5 V pulse when ch02 initiates a ramp\n", - "# ch will ramp when setting a voltage while a slope is assinged, or when using \"ramp_voltages\"\n", - "qdac.ch02.sync(1) \n", - "# note that a pulse is still fired even if no visible ramp is performed\n", - "# e.g if ramping from 1 V to 1 V\n", - "\n", - "# The sync pulse settings can be modified\n", - "qdac.ch02.sync_delay(0) # The sync pulse delay (s)\n", - "qdac.ch02.sync_duration(25e-3) # The sync pulse duration (secs). Default is 10 ms.\n", - "\n", - "# Print an overview of assigned SYNC ports\n", - "qdac.print_syncs()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Plug in an oscilloscope to CH02 and SYNC1 and observe the ramping and the sync pulse\n", - "qdac.ch02.slope(1)\n", - "qdac.ch02.v(-0.5)\n", - "sleep(3)\n", - "qdac.ch02.v(1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# syncs are unassigned by assigning sync 0\n", - "qdac.ch02.sync(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Ramp one or more channels simultaneously \n", - "Setting several channels simutaneously is only possible using \"ramp_voltages\". Note that " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Here we ramp channels 1, 2, 3, and 7 from there current values to zero, in 0.2 seconds\n", - "duration = qdac.ramp_voltages([1,2,3,7],[],[0,0,0,0],0.2)\n", - "sleep(duration+0.05)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# As it takes tens of milliseconds to read the channels' current voltage, it is faster \n", - "# if their previous voltages are known:\n", - "duration = qdac.ramp_voltages([1,2,3,7],[0,0,0,0],[1,2,3,4],0.2)\n", - "sleep(duration+0.05)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Ramp a single channel step by step and record and plot the current sensor reading" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Perform a 1D scan of the QDAC ch01 and record the current on\n", - "# the same channel also using the QDAC. \n", - "# Replace the QDAC current measurement by a DMM to do a typical physical measurement\n", - "\n", - "from time import ctime\n", - "\n", - "from qcodes.dataset import Measurement, plot_by_id\n", - "\n", - "STATION = qc.station.Station(qdac)\n", - "qc.new_experiment(\"QDAC\", \"TestIV\"+ctime())\n", - "meas = Measurement()\n", - "meas.register_parameter(qdac.ch01.v) # register the independent parameter\n", - "meas.register_parameter(qdac.ch01.i, setpoints=(qdac.ch01.v,)) # now register the dependent one\n", - "meas.write_period = 2\n", - "with meas.run() as datasaver:\n", - " for set_v in np.linspace(-1, 1, 10):\n", - " qdac.ch01.v(set_v)\n", - " sleep(0.1)\n", - " get_i = qdac.ch01.i()\n", - " datasaver.add_result((qdac.ch01.v, set_v),\n", - " (qdac.ch01.i, get_i))\n", - " print(set_v, get_i)\n", - " dataset = datasaver.dataset\n", - "myplot = plot_by_id(dataset.run_id)\n", - "qc.dataset.plotting.plt.show() # Sometimes it is necessasry to out-comment this line in Jupyter...." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2D scan \n", - "It is possible to ramp two groups of channels simultaneously. This is useful for a 2D data acquisition setup\n", - "Note! The slope definitions are not used during the 2D scan." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# set outputs to zero\n", - "qdac.ch01.v(0)\n", - "qdac.ch02.v(0)\n", - "qdac.ch03.v(0)\n", - "\n", - "# enable sync on one of the fast channels (sync signal is output at every start of a staircase ramp.)\n", - "# for example for triggering a digitizer\n", - "qdac.ch02.sync(1)\n", - "# enable a 10ms sync delay which allows for stabilizing of the device\n", - "qdac.ch02.sync_delay(0.01)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Note! The slope definitions are not used during the 2D scan\n", - "duration = qdac.ramp_voltages_2d( slow_chans=[1], slow_vstart=[0], slow_vend=[1],\n", - " fast_chans=[2,3], fast_vstart=[0,0], fast_vend=[1,-1],\n", - " slow_steps = 10, fast_steps = 10,\n", - " step_length=0.02)\n", - "# wait for the ramp to finish\n", - "sleep(duration+0.1)" - ] - }, - { - "attachments": { - "image.png": { - "image/png": "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AiIgAiIgAiIgAvFGgGa+g824OzHokmIwYsQIvPzay6itrQXtycdToI8DBjpti2RISExAYkoKWhoaI553JOpJuflH/wbxFugBmu0d6TaPdo5qc7V5tN+jkayffud6tkfyformvPRs99azne3J51dHITk5GXN+mYPJ+0zuKJlxrkuKgZXrSSedhNmzZ1tf4+JzwIABRgeRHnkjGbIH9ceWJx+Gnx55FTWr10Uy64jklZGRgbKyMsNBG70Tx1MoLS1FU1OTz9NtvMiemZmJQYMGGW3e2NgYL2IbclLuhoYGrF27Nq7kzs7OBp9xixYtMu75eBJ+8ODBxmDXunXR9/ztyXbIyclB//79jTaPt4E+vtM4irp+/fqeRBx1eefl5WHgwIGYM2dO1NWtpytER7R0oLphw4aeLqrX8s9Iz8CokaOQAHPg2qngfffbF7vsuovTqZC4bikGS5Yswdy5c0My9XIEZ0k4crxs2bKIipnbUIWcjeX4bcF8VC1fE9G8I5FZVlaWIfe8efNQV1cXiSxjJg/KS8VgxYr48lzLTiLlZpuzkxxPgfKy3VetWhVPYiM3N9eQm20eb8og7/Xq6mpEetAn2m+g/Px81NTUGO/yeFMMKC87ifE2AFBQUGA80+Ot/8bfIvtvVArKy8uj/afpun5ZmVlIT0nvMH04ym/Hcw8dFqOTIiACIiACIiACIiACIiACXiEgxcArLSk5REAEREAEREAEREAERKAbBKQYdAOeLhUBERABERABERABERABrxCQYuCVlpQcIiACIiACIiACIiACItANAlIMugFPl4qACIiACIiACIiACIiAVwh0yyqRVyBIDhEQARGIZwI0X5iamor09HTDHnZhYaHho4bWamipR0EEREAERCA+CEgxiI92lpQiIAIi0C4B+imhSWI6waGjHJqqpVk/mnOUYtAuNp0QAREQAc8RkGLguSaVQCIgAiIQHgHLXwP9GNDR1+LFi+POj0F4xJRaBERABLxJQHsMvNmukkoEREAEREAEREAEREAEwiIgxSAsXEosAiIgAiIgAiIgAiIgAt4kIMXAm+0qqURABERABERABERABEQgLAJSDMLCpcQiIAIiIAIiIAIiIAIi4E0CUgy82a6SSgREQAREQAREQAREQATCIiDFICxcSiwCIiACIiACIiACIiAC3iQgxcCb7SqpREAEREAEREAEREAERCAsAvJjEBYuJRYBERAB7xGg5+O0tDTjLykpCfR83NLSYjg3k4Mz77W3JBIBEYheAhMnTsQWW2zhq+Abb7yBtWvX+r739IEUg54mrPxFQAREIMoJWJ6PqRQkJCT4PB83NjbK83GUt52qJwIi4B0C48aNw6n77op9tx2Dymbgm0pgzZo1+Prrr7F69epeEVSKQa9gViEiIAIiEL0E5Pk4ettGNRMBEYgfAhdddBH2/OkNFN1xC8qrgVO/BZ5/4QVkZmbi+eefBwdveFxTU4Pm5uYeAaM9Bj2CVZmKgAiIgAiIgAiIgAiIgHsCl112GfZ65APcsNj5muHDh+Oll17CyJEjnRNEIFaKQQQgKgsREAEREAEREAEREAER6A4BLhdauKEKaxucc0lNTcWQIUNABWLChAnOiboZq6VE3QSoy0VABERABERABERABNonsO++QGoq8M477afRmUACRUVFmDLlcPz3v//FnDlzAk7uuuuuxv4vLi36buZ3Aee6+0WKQXcJ6noREAEREAEREAERiFMCAwcCY8d2LPzZZwOZmUBDOyPhHV8dubODBtWgsrIBFRWRy7MnctostwT5W++Ev54yAddd/zcUFy8ElavBg/2lHXzwSBQUjMRjj36Hmkp/fHePpBh0l6CuFwEREAEREAEREIE4JTB5MvDEE+6EZ1o3gftqKyuB7Gwg2UVPlWk5I5GW1lnuyztLEPb52lqgtdVUfMK+2OGC1tZ0bCrfCxvXHYSysj/i4Ydbfanq6oBFi4DExGoUFj6CE054FeN3zMLJJ5p18CXsxoH2GHQDni4VAREQAREQAREQARGILIHffgO4hH72bHf5nnIK8MIL7tJGOtWNNwLXXx+5XMvLT0f9tM1Q+vil7fb2Bw68DDk5H0auUFtOLvQwW2odioAIiIAIeI5A//79QV8GKSkphjm8wYMHGw7ONm3ahI0bN3pOXgkkAiIQWQJLlwKXXw40NUUm302bgLlzgUsuAQoLO8/zk0+ABQuAt97qOO2AAQOMtfmVnGLoJJx2GpCSAjzwQMcJv/0WaGkxy7en3HtvYP/9TS5/+xvAOn7YSV9+6tSpKC4+EBgMNGUWAivMHF966UVjr0Fz8zJUV1+IrKwZSEqqMk421LerP9ir4/pYioFrVEooAiIgAt4kQEdmlnMzStjQ0GAoBj1lJ9ubFCWVCMQvAXbkX34ZqK+PLINp09znt24d8F0n+3BHjcrBhg1NKC/vXDHgfgguY3rpJXd1WLgwMB2///yzOZNRXAzMmAF8+WVgmuBvKSlrMGDA+/7o6ebhRx9VY9YsHnNzxHv+8wCyMoGttgyI6tYXKQbdwqeLRUAERCD2CWzYsMEQIjc313CeQ0+bVBYUREAERCBeCbz2Wvck/+YbgH8M997rLq+nn37aXcIeTKU9Bj0IV1mLgAiIgAiIgAiIgAiIQKwQkGIQKy2leoqACIiACIiACIiACIhADxLQUqIehKusRUAEREAEREAE4oPANdcAY8ZEXtbPPgNeeQW46SbTJGd7JUyfDnD5yz/+0XG61NRqZGYuRmd2BZjf66+b+XETbnth2LD2zig+FglIMYjFVlOdRUAEREAEREAEoorAnnsCe+wR+SptthnAzvfvf29ayWmvBKYbMaLzdAC9jHXuaWzkSH9+nfkS+PHH9mql+FgjIMUg1lpM9RUBERABERABEYhKAjSxuXhx51XbfHOzk++2Qz1unGnusrOct9qq83Q0S5yeng6a7Bw/Hli9GliyxJ+zFUcrP8zvP//xn2vviE63aLJTIfYJSDGI/TaUBCIgAiIgAiIgAlFA4MEHgdtv77witGtPE5ZnnNF52kinKCjIRllZGWbNmoW33wbeeANgva3gFGed06f3CUgx8H4bS0IREAEREAEREIEoIkDlISmp7ys0ZQpQXR1YD6e4wBT65mUCUgy83LqSTQREQARcEKDn48zMTCQnJ/s8H7e2thpej+X52AVAJRGBMAmsXx/mBT2UfOXK0Iyd4kJTKcarBKQYeLVlJZcIiIAIuCRAZ2b19fWgMpCRkeHzfNzU1OQyByUTAREQARHoSwJVVVVw8lbPZ3o4QYpBOLSUVgREQAQ8SMDu+TgrKwvyfOzBRu4lkUpKgFGjgC+/BLbZBigsBFatAn74ofMKDBgAbL21mW7GDICj6oyjtR3mt+22QHk5wI2uVthxR6BfP/NbTU1ousxMYJddgO+/B4qKTOs+1rUDB9bi++8bjCU9Vrk89+uvgRuIWcbatUB9PUBLPaxLc7OZC+tnxVn56lMEepNAS0sLamtrsWnTJsNjfVFREfg3Z84coxpUFhoaO7dCZdVZioFFQp8iIAIiIAIiIALdIkBznbS3v88+5ibc3Xc3beGfdlrn2R58MPDII2a6I44AaL//kEOAK67w5zdtGnDvvf687rgDmDTJ/L5ggZmOcR9+CNx3n2luk7b9TzwR2G8/4Oyz/dcCK3D11QCXzjz0kD/+qquAf/7T//3OO4H33zet91xyiVmGtS7/sMMAK64jW//+3HQkApEl0NjUiNU0LdUWdtxpRxx40IE4/5zzjZiKigrwz22QYuCWlNKJgAiIgAiIgAh0SmDwYNPEZf/+ZtJ99wU4A9BZyMryp7j/fqCuDmBcfr5pgpP50XzmySf703HE3gpDhgCffgow3dixwCmnmCZBmccDDwBOKyouuAAIXjHHuFNPtXI1Zy223NKcJWBd6PirtdU8b9WPcZwtefll/3U6EoFYJJAYi5VWnUVABERABERABKKTAJf7/OUvwLx5Zv1mzQJuucU0z0lHXdZfejrA0fnKSjOOPgDOOQfgkiB2+NnZfuops3NfVgYwfUGB/3rmwziGL74ALrzQLOPGG83ZhmXLTK+9XALE/OjFl6P/K1YAJ5zA2YMBuOiiXJx5JnD00f4/5rV0KXDxxeYf0zKO5kU5KzB0KPDYY8Ds2WYclxldeSXAGQsFEehLAgcefCAOOvggDBg4AFf89QrjM9z6aMYgXGJKLwIiIAIiIAIi0C4BLrN5800gNdVcf88ONJficI2/1ZHnxdxD8OKLgek++MBMl5YGvPsusGmTOXPQbmFtJ7iHgcuHuKeBygRnKHJz/XFWflxRwU7/Sy8BgwdnoaKi2dg/YM+/thbIyQkc/Wec3RkZy/j2WzOOihDl4H6GX36x56RjEehdAiNHjsTIzUYahU6cNBEvPPdC2BWQYhA2Ml0gAiIgAiIgAiLQGYFHHw1Mcd11gd+tb8Hprr3WOmN+utm4bF1hXWsfvbfirDScwegovPNO6FnGBccvXBgY9/DDodcpRgR6i8DmW2yOouKigOK22GILbNywMSCusy/dUgySkpIMm9edFeKl8wkJCYY4lD2SwcovWpkmJpqrzqK1fpFsi+C8KDv/rDYKPu/V75a88djm/J3HY5tTZsrONqeli3gK8dzmbGf6sIhESExsRUJCi3EPRfg1GYnqBeQR721uPeMDoMTBF6892612PPPsMzFq9KiAFjzznDMdTZgGJAr60q0nwZAhQwzzSEF5evqr9fDMzs6OqJwpJQWgzlE2dCiasvIjmnckMuMDlH9Dhw41bJ1HIs9YyYNtTvvuOZxbjqNgPTyHDx8el21Os515eXlx1OLwKUMjRoyIyzanve987i6No2D9zrkEgc+57oaBAyuQkrIWI0cOR2VldG9jTElJQXp6OvpZ9k67K3yMXM82Zxg9enSM1Dhy1WSbp6WloZBrzjwSmpuasWn9pohJ0y3FoLy8HKu7fvkAACAASURBVCu4iyeOAm3D8uG5bt26iEqdldSMglbaSl6D2pWRzTsSFeUPacCAAVi7dq3h/CgSecZKHsXFxYbGvT5aXFX2Ejh2kih7PNq0pydgOv2y7Pv3EvI+L4bej/nCXLVqVdijTH1e+W5WoKSkxHDyFm+enqkAFxQUYOXKlRGZJdqwoRF0jLdq1Ups2mTOsHezaXrscr7TLPvvPVZIFGbMgU32ZeKt/8amGDhwIKqrq8My3xmFTRhQpcSERKQmpeLxRx+H06D1/N/mY9/J+wZc09GXbikG9LJGhwrxFHJzcw3FINJytxaYdtqqKqtQFYVM+fJgqKysRB1tyMVR4KgxX3SRbvNoR0inKHx50P5xQ4N75yjRLpeb+rGjxPs83tqcgx6Unb9zKkbxFKgQRbLNjz3W3HjbGwzpx+jjj00zntwAG05IT69HTk4jyss3obW1+8vHaE6Uq9D43IjCV1kAGj7f4lExsGYM4u35xsbnoI/X2pyrGgrzCjHr+042zwTc/e1/6ZZi0H62OiMCIiACIiAC8UuAtvYPOMCUnxZt6C133DjT4k6kqdARGFe3cpMtLfGEFzjQE9nBnvnzw6uBUouACEQPASkG0dMWqokIiIAIiICHCNAeP/9oT5928ulka6+9Ii8gnW/ddhvAiT2azgwnWBtwOUMYqbBhg98BWKTyVD4iIAK9Q0CKQe9wVikiIAIiIAJxRuC++wD+0bPuxo2m8y4n77t9iSU3N8dYXrFw4cKI7SuhvHRapiACIhB7BKQYxF6bqcYiIAIiIAIxQIBr7Bcv9ld0zRr/cbQc5ecnoqkpxahnBCcNokU81UMERCBMAtFtSyxMYZRcBERABERABERABERABESgawSkGHSNm64SAREQAREQAREQAREQAU8R0FIiTzWnhBEBERCB8AnQcyY3odo/abqU3o+76wGZvpQKCug8zawXN8haZizpPy41NbC+PJeSQk+85jp1Xsv16oyjKU6awuTmVvobpEVVbu4NLoM5dpTOnp9Ver9+zUhPp7yh13KJTbC1n/p6muQ0r3aSI1guqxx9ioAIiEA0E5BiEM2to7qJgAiIQC8QKC0tNRzjWF5wLc/HdGJJp4bdCcXFwFtv0X64mctHHwGnnWYe33EHsM8+gbmfcgqw7bbA2LHAlVea1156qRl3/vnAypXAIYcAt9wCfP89cNddQEmJma6oyJ+Xle7WW4GZM4G77zbTvf02cNFFwPbbA+ed50+fnLzc8FFDJYDXHnwwcPvtwIwZwNy5wEMP+dPy6P33gdNPN+PuuQfYY4/A85SXvgUUREAERCCWCEgxiKXWUl1FQAREoAcI0JM7HVLR2zWdPlmej7vrzHDHHYHrrgPo9Co93az4gQcCr7xiHk+YAAwYECjQ3/5mzjBwFL601FQQrLiyMoCKxpNPAtttB+y8s9khp6UfKhJpaf68rHRUAHbaCdhzT4DpxowBbrgB6NcPYH7+0OQ7tK7dYQeAMnCGITCtqThYcuy6q6l0+DLQgQiIgAjEKAEpBjHacKq2CIiACESKQA3X44C2583lQ5HyfDxwIDBpkmm/v6oqtLY//RQaFxzDEXun8O23gbHdTVdQkI+GhkZUV1f7MuZMgxU+/NA6Cv1sT47PPw9NqxgREAERiGYCUgyiuXVUNxEQARGIcQIcbb/5ZnN5TjSLMmJEP0MpWL3arxhEc31VNxEQARHoCQKyStQTVJWnCIiACIiACIiACIiACMQYASkGMdZgqq4IiIAIiIAIiIAIiIAI9AQBKQY9QVV5ioAIiIAIiIAIiIAIiECMEZBiEGMNpuqKgAjELoGRI4GpU0Nt4tsl4mbdP/zBHhP54912A449tuv5jhoF0HQofQkoiIAIiIAIeIeANh97py0liQiIQJQSoMlM2tqn6csLLwTKy80/p+oedxywxRZ+J2BOabobd/zxwOjRfgddVn6ZmU0oKqrCiBEtoD3/9gLNhJ5zjinD+vXtpQJo7lNBBERABEQgdghIMYidtlJNRUAEYpTAX/4CTJ4M0BImPf/S6VZn4YknOkvR/fPBZSQk1CIpaQWamjrQCtqKpeJAB2CdhVWrTE/CnaXTeREQAREQgb4nIMWg79tANRABEYgDAo8+6k4h6EsU2dlZGDiwFAsXLkBTk9/hV3fqRAWCMyQKIiACIiAC0U9AikH0t5FqKAIi4AECFRXA0qXRLUhubiISEpKxbFkCGhuju66qnQiIgAiIQOQJaPNx5JkqRxEQAREQAREQAREQARGIOQJSDGKuyVRhERABERABERABERABEYg8ASkGkWeqHEVABERABERABERABEQg5ghIMYi5JlOFRUAEREAEREAEREAERCDyBLT5OPJMlaMIiIADgW23Ba65xuFEFEZlZq5BS0sL6uoiU7mddgJ++ikyeSkXERABERABEegpAlIMeoqs8hUBEQggUFxs2vJ/5BFgw4aAU1H3JT8/1TDXWVUVmarNmgVMnx6ZvJSLCIiACIiACPQUASkGPUVW+YqACIQQqK0F7rwTWLAg5FRURQwblo+6ujqsWhUhzSCqpAutTGZmJpKTk8HPxMREZGdno7m5GfX19cZf6BWKEQEREAER8CIBKQZebFXJJAIiIAJhECgqKkJOTg4SEhKQlJSE0tJS4+o1a9Zg7dq1YeSkpCIgAiIgArFMQIpBLLee6i4CIiACESCwfPly30wBlYIFC0zPx5w1UBABERABEYgfAlIM4qetJakIiIAIOBKgAmD9tba2GvsrGuX62JGVIkVABETAywRkrtTLrSvZREAEREAEREAEREAERMAlAc0YuASlZCIQKQLbbQe0LeGOVJY9kk96ejNKSioxciRHkLtfBM2VKoiACIiACIiACEQvASkG0ds2qplHCVxyCXDYYUBlpXsBExKAoiLzmqQkIC0NWL/e/fVuUlplMH8z1KK1dTHKywG3S83z88207cm2Zo37vKxa6FMEREAEREAERKB3CEgx6B3OKkUEAgg89RRw/fUBUR1+yc4G3n0XuOUWc7Zh772B3/++w0vCPpmba5YxdKj/UnbwDz8cWLzYH9fR0QMPAEuWAH//u3OqlhZARm6c2ShWBERABERABPqaQIBikJvbjF13q8T/vsjBpo2+YcO+rqPKFwHPEWCHe/ly92IlJwNTpgC//gqkp5sd+HCud1MSR/NPOw3IyjJTp6dnoKCgP376aTk2bXK3lujaa4GamvBkc1M3pREBERABERABEeh5Aj7FoKi4CWO2qsHwEfWYOYM9AykGPY9fJYiAOwJc4//xx/608+f7jyN1RCM006b5c8vOTsKwYTmorXVvo2DGDP/1OoodAvn5+UhLSzP+6MeguLjYsFJUXV2Nqki5f44dHKqpCIiACMQtAZ9ikJHRgn79ZLM6bu8ECS4CIhC3BKgUWN6P6eQsPT0dNFva0NAQt0wkuAiIgAjEIwGfYrB0SaoxMnj0sevikYNkFgEREIG4JbB69WpD9tzcXAwePBhLly6F/BjE7e0gwUVABOKYgPs1AnEMSaKLgAiIgAiIgAiIgAiIgNcJ+GYMvC6o5IsuAmPGAP/4R3TVqb3aZGSsNZZV1NW1lyK8+O23B559NrxrlFoEREAEREAEREAEepqAFIOeJqz8HQn06wcccADw0EMw7OTvvDNAZeHxx/3JGbfllsATT4TG0dzn6acDn30GzJ5tnqflHntcWRlwyinmuVde8adLSTHTTZ9uWuDZf3+AG28ffBBY57CSLi8vFc3NLaiq6lgzOPJIgPs0P/jAX1+no5kzgf/+1+mM4kRABERABERABESg7wh0qhikprZi4KAGrFqRivr6hL6rqUr2HAFa2vnnP4GffwYOPRSYOBG45hq/mHQCtuuuznH0AUDl4oUXgE8+Ma+h0y973NixplMwnr3nHn86mvssKACefx6gQy7ur6yvB266CVi2zF++dVRWloempiasWNGxRzIqBXQ69thj1pX6FAEREAEREAEREIHYIeBTDJKTW0HLRAzp6S3IympBY1MC6NvgwIM34p0387FieSqamqQcxE7zxk5N33wT4J89vPEGwD97sMeddZb9jNm5t8f99JPpYTgwFcAlQfZ0r78enKJr32+9tWvX6SoREAEREAEREAERiAYCPsWA/gsm7V6JhARgn8kVaGkG5s5Nx7xfM4x6Mu6Lz3Iwd056NNRbdRABERABERABERABERABEYggAZ9isHJlCj7+KDcg66qqJENRYCRnEbbdvhppqeasQkBCfREBERABERABERABERABEYhpAoZiMHRYPfqXNIYIwrjMzBafclBY2ITNx9QiObHWSFtYWIgBAwaEXOfliIyMDMNCTaTlTi8sBBKAwqJCZDdHnxXZFO7YBdfsFxnr7bvbxv36NSAhYQOKingP+fTT7mbbI9ezzVtaWuLuXk9NTUViYqLPC26PwI3STOngKzk5Oe7anI7OLM/HvOfjKfB+p3M3/sVTsNq8f//+xrstnmRnm+fk5Bj3fDzJzecbQ6T7MbHAkH0Ztjmf754JrUBrU2vExDHIZOe0oKi4yTFTbj62h/T0VmRnmWn33TcNo0ebS43sabx9bClQkZW7JiMN8xOA/SenI70+snlHrj24+ZYKgqkkdCffESPMly9fShkZqd3JqsevZUeJHWQqCPEUKDcDXyLx1klke/PFEW9tTpntno/j8X6P1zan3PR2HU+Bv3N2FOOtza2BvniTm/c225wKoZdCS3ML6po6tpoYjryGYvDT7AzwzylQYaA3ZA6i0CrR/HnpqKrMMZJedNEKbNy40DimdReGNWtM049ZWaYpSH63AuPs6fidYeNG87N/f6BtYNowH8lrGVddbf7xHL8z3srfvNL5v5WOZ2tqgOJifzrm6VSuP4X/fGYmsHatWbZVP3u64GOWm50N8DpavOG1DLSEw+euU11mLKzH3z4DLr10OfolrTF4W6x47YYNCIljPOWw5+eUzinOqJDDv+D8HJIYdUlMBPLynM52HkfrPbW1Jovly5djoXkLdX5hH6UoKytrs0q0oo9q0DfFZmdnY9iwYYYX3AbeyHEUKHddXR1WrVoVR1ID8ez5eMSIEaiuroblBTpeGj4/Px8DBw7E4sWL0dzcHC9iG3KOHDkSFRUVWGu9pONE+oKCAvC9tjDaX7490B6jRo3Chg0bUF5e3gO5902WHNApzCuMWOFhrVmZOSML337T1ptvq8KNNwJ/+5u/PiedBOy4I3DDDcCcOcD48eZ3K85KeeKJAG3Lv/qq//wvv1hnAR7zGn4yLx4zb3asTzjBvM6fOvTISvfaa8DLL5vX2lMxjnnutBPw66/2M/5jmsSkEy5at6FN/blz/efaO6IJzuOPByxLNz/+6JePcS++CJx8cuDVNLl5ii3uuutM05n2VNdeC9x8sz3GPDaubbPVzxindIy75ZbQa51iaMLz1FOdzvjjaFLUbX7+q/xHzz0HTJni/64jERABERABERABERCBvifgepEVLRItnJ+Ghgb/+ssLLzQ79+yEW53rL78ENm0y7ct/9RWwcqVfSHZiqSwwWOc4E2ENyp1zjn8UmnkwnnGLF5vHHGWmvfuvvwZWrzbt0PtzDzxinax0PF661LzWSmXlyfJputJp9PuHH8xR+i++AFasAM48Exg5ssiYbl23bh04an7HHcCIEcA77wD33w9wWe4335izBM88Y470W/LRTj4HZDjbwc+pU2GMli9aBKyrAoY2A+edB8z+HOAqDioVVpg1y4yznHlZ8bx2+XK/bE7pvv8e4HI6ytNZ4AACZSVne+CSH44qLV++At9802Dkx7K6ElgG74ujjgKWLOlKDrpGBERABERABERABEQg0gQ6VQxqqhMx4+tsYwlRdXXgBMPnn5uddlYquIPH753FBXdy6cU2ONjjqCy8/baZgp1cNx1de5q33grO3ZyBsJcRmsIvI9MtWmSuw6QjLCoVAwdyA4+pDFA5sIJT/ayO9KBB5sg+FSUqOAy5w4DWFoDeeKuWm3Hs9AcHpzimCZbNKZ1TXHD+1vfg/LKykjFyZC7mzl1l+AFgunDys/K1f777rv2bjkVABERABERABERABPqSQOeKQQ0Vg8DlQ31Z4WgqmzMRDz4Yfo04ws9lSgoiIAIiIAIiIAIiIAIiEC0EAqcAoqVWqocIiIAIiIAIiIAIiIAIiECvEpBi0Ku4VZgIiIAIiIAIiIAIiIAIRCeBTpcSRWe1VSsREAEREIFIESgpKUFmZqbhu4Gm72jKkL4rNm7caJj2i1Q5ykcEREAERCC6CUgxiO72Ue1EQAREoMcJ1NfXG2XQ+hgd2tXW1ho27RsbLYeOPV4FFSACIiACIhAFBKQYREEjqAoiIAIi0JcEODPAQAdndGxHh09SCvqyRVS2CIiACPQNAe0x6BvuKlUEREAEREAEREAEREAEooqAFIOoag5VRgREQAREQAREQAREQAT6hoAUg77hrlJFQAREQAREQAREQAREIKoISDGIquZQZURABERABERABERABESgbwhIMegb7ipVBERABERABERABERABKKKgBSDqGoOVUYEREAEREAEREAEREAE+oaAFIO+4a5SRUAEREAEREAEREAERCCqCMiPQVQ1hyojAiIgAr1PgJ6Ps7KyAjwft7a2Gl6PN2zY0PsVUokiIAIiIAJ9QkCKQZ9gV6EiIAIiED0E7J6P6f24pqYGLS0taGhoiJ5KqiYiIAIiIAI9TkCKQY8jVgEiIAIiEN0Egj0fl5eXy/NxdDeZaicCIiACPUJAewx6BKsyFQEREAEREAEREAEREIHYIiDFILbaS7UVAREQAREQAREQAREQgR4hIMWgR7AqUxEQAREQAREQAREQARGILQJSDGKrvVRbERABERABERABERABEegRAlIMegSrMhUBERABERABERABERCB2CIgq0Sx1V6qrQiIgAhEnEBycjISExMNPwYJCQlISUkBP5ubm42/iBeoDEVABERABKKSgBSDqGwWVUoEREAEeo9AaWkpcnJyDGUgKSkJI0aMAB2crV27FmvWrOm9iqgkERABERCBPiUgxaBP8atwERABEeh7AlQA6OE4MzMTxcXFWL58OZqamuTgrO+bRjUQAREQgV4lIMWgV3GrMBEQARGIPgK1tbVGpbh8iB6Pq6qq5OAs+ppJNRIBERCBHiegzcc9jlgFiIAIiIAIiIAIiIAIiED0E5BiEP1tpBqKgAiIgAiIgAiIgAiIQI8TkGLQ44hVgAiIgAiIgAiIgAiIgAhEPwEpBtHfRqqhCIiACIiACIiACIiACPQ4ASkGPY5YBYiACIiACIiACIiACIhA9BOQYhD9baQaioAIiIAIiIAIiIAIiECPE5C50h5HrAJEQAREILoJyPNxdLePaicCIiACvUVAikFvkVY5IiACIhClBCzPx4mJieCfPB9HaUOpWiIgAiLQwwSkGPQwYGUvAiIgAtFOINjz8bJly9Dc3CzPx9HecKqfCIiACESYgBSDCANVdiIgAiIQawSCPR9XV1fL83GsNaLqKwIiIAIRIKDNxxGAqCxEQAREQAREQAREQAREINYJSDGI9RZU/UVABERABERABERABEQgAgSkGEQAorIQAREQAREQAREQAREQgVgnIMUg1ltQ9RcBERABERABERABERCBCBCQYhABiMpCBERABERABERABERABGKdQLesEmVnZyMvLy/WGYRV/9TUVLS2tkZc7qzsbKMe2Tk5SMqrD6tOvZE4PT3dKCYnJwdpaWm9UWTUlME2T0pK6nKb1w8dirrRo33yZM6ejZRVq3zfo/UgIyMDCQkJyM3N7ZKFmtaUFFTtvDNaMjJ8IiY0NiL7q6+QWFvri4vGg5SUFKNaXXm+1WyzDRr790dyeTmyvvvOyIdxidXVSP/tt2gU11enzMxMw48B27ypqckX7+agqbgYtVtuabQvPxuLi5Gydi0yv//ezeV9noZO3vic60qb2yvfmp6Oyp13RuZPPxn3gP1cNB5bbU65aaLWbagbNQr1w4b5kmfNnImmfv2M33vmDz/44qP5gG3O51w4bd6SlYWqnXZC1vffG/d4S1oa0hcsMOJamd/cuUhdvDiaxQbbnCEcuS2BGktLUTN2rPE1+5tvkLRxo3UqJj75Lg+3ze2C1W6xBZCYiLSlS43fORk0lJaiYfBgJFVWGs8/tLYalzQMGoSGIUOMuKrx45G6YgV4rnbMGON89tdfG9ciIQGpS5ca70t7fvZyM375JfDar75CUkWFUW7j4CHADPNdY7+mq8fdUgyKiopAxzjxFPggYYh05zilqID3BoqLi9CUkBp1SNlB5F9xcbGhGLmuYG4uUFjonJw/nuXLgcZG5/NREss2pzJoKUeuqpWYCPC3kZKC9UccgbopU3yXFdx8M3LfeANYv94XF40HlrOr/v37h9fmHCzo1w/N2dlYeNddaBkwwCde4qZN6H/MMUhdtswXF40HbHP+xvkCcR2Skow2X3bNNWicMAHpM2ag9OqrjcuX/eUvSJs1C8V33+06u75IaLV5SUlJeG2en4+q/ffHynPPRcl552HleeehcaedkPbVVyi96iqAL8QwOp19ITvbnIMAVqfJVR34PuDvnG3fFqgQVd91F/rddhuyP/oIiPKOE9ucnSW2eThhzRlnoN72XCu88kpUb7cdGktKUHr99Wabt7SEk2Wvp2WbcxAgKyvLddkNw4ej+umnUXjttajcZRc0FRSg+JlnjDZvzchA7k03od+//uU6v75IyDZnCLv/VliITUccgZoLLzSuL7rkEmT8/LMpQkOD2eZtnWIzMvr+s715v3Ng23VITTV/5wkJWHXWWeCgV8Gbb6LyrrtQdNFF2LTffmg46CCkLFiAgeefj4S2+37j/vtjw8EHo/T887Ho9tuR9+GHSGhuRu155xlFF11wATZNnozWxEQUvP02qu6+G0VTpxpxzM8e8u6918jXurb4gguQPm8eNh5wANbusSewz2RDcbBf09XjhJLCElO1CSOHcVuPwwfTPsCECRMwY8aMMK6M/aSDBg0yXpgr+KKLYMgdVoqtzzsO3932b1QvXxPBnCOTFV+Ww4cPx/z581FXV+c+0zPOAP7+d+f0zGfvvYFff3U+HyWxgwcPNkbSVq5c6b5GfOhMmwZsthla09LQ0jbjwgwSa2qQcOedADtMURz44BwyZIjR5g186LsNfOixQ5yQYCgHHF3xhfXrkbTLLsCCBb6oaDwoKytDfX09Vq9e7b56RUXAxx+jZdQo48WR0NRkzBIwg5bMTCTccgsSorzNOSPIZxx/543hKOyXXYbWK680RouTqqqMT46eGgzmzzd/5+GwdE89YimHDRsG+m+gszfXYfBgo80DBj8SE4373vidX3stcPvtrrPri4QcNaZSwDYP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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qdac.print_syncs()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Set outputs back to zero\n", - "# First remove sync output so that we do not trigger an acquisition\n", - "qdac.ch02.sync(0)\n", - "qdac.ch01.v.set(0)\n", - "qdac.ch02.v.set(0)\n", - "qdac.ch03.v.set(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The \"mode\" parameter: controlling voltage and current ranges: \n", - "The \"mode\" parameter is controlling the output voltage range (by an attenuator) and the current sensor range. Only certain combinations of the two are allowed, which is why they are conrolled by a single parameter. The mode parameter is allowed values are:\n", - "\n", - "Mode.vhigh_ihigh : high voltage output range / high current sensing range\n", - "\n", - "Mode.vhigh_ilow : high voltage output range / low current sensing range\n", - "\n", - "Mode.vlow_ilow : low voltage output range / low current sensing range" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# The \"QDac.Mode\" enum class is used for setting and reading the mode. \n", - "\n", - "# This will set the voltage output range to low, and the current sensor range to low\n", - "qdac.ch01.mode(Mode.vlow_ilow)\n", - "print(qdac.ch01.mode.cache().get_label())\n", - "\n", - "# This will return ch01 to the default mode: high voltage range, high current sensing range\n", - "qdac.ch01.mode(Mode.vhigh_ihigh)\n", - "print(qdac.ch01.mode.cache().get_label())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### When \"mode\" change results in change of voltage range\n", - "\n", - "When changing \"mode\" so that the voltage range is changed the attenuator is switched immidiately. The driver will re-adjust the output voltage in order to keep it constant, but a spike will always occur if the voltage is non-zero. If the set voltage is outside the range of the low range and the transition is from high to low range, the output will be clipped. \n", - "\n", - "To avoid spikes, the driver by default **does not allow changing the voltage range (mode)** when the output is non-zero. To over-ride this protection, set qdac.mode_force(True)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Here is a small example showing demonstrating the behavior - if posible hook up an oscilloscope on ch01\n", - "#\n", - "qdac.ch01.slope('Inf') # Make sure that we are not fooled by a slow changing ch01 \n", - "qdac.ch01.mode(Mode.vhigh_ihigh) # Attenuation OFF (the default), high voltage range\n", - "qdac.ch01.v(1.5) # Set the voltage to outside the low voltage range (but inside present range)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qdac.mode_force(True) # Enable changing voltage range eventhough the output is non-zero\n", - "qdac.ch01.mode(Mode.vlow_ilow) # Attenuation ON, low voltage range - signal is clipped, and a dip occurred\n", - "print(qdac.ch01.v()) # Returns approximately 1.1V as the output is clipped to the low range limit" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qdac.ch01.mode(Mode.vhigh_ihigh) # Attenuation off, high voltage range\n", - "print(qdac.ch01.v()) # Returns approximately 1.1V, unchanged - but a spike occured" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Return to protected mode\n", - "qdac.mode_force(False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Now provoke an error\n", - "print(qdac.ch01.v())\n", - "print(qdac.ch01.mode.cache().get_label()) # Pretty printing the mode parameter\n", - "try:\n", - " qdac.ch01.mode(Mode.vlow_ilow)\n", - "except ValueError as ve:\n", - " print(\"ERROR: \", ve)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Overview of channels\n", - "\n", - "The driver provides a method for pretty-printing the state of all channels\n", - "\n", - "The pretty-print method may or may not **update** the values for the currents, depending on the value of the `update_currents` flag. Each current reading takes some 200-500 ms, so updating all current values takes about 14-24 seconds depending on the number of channels." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qdac.print_overview(update_currents=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Temperature sensors\n", - "Physically, the QDac consists of either three or six boards each hosting eight channels. For diagnostics purposes temperature sensors are placed at three locations on each board,. Read-only parameters for these sensors are provided, named tempX_Y where X is the board number (0-2, or 0-5) and Y the sensor number (0-2)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(qdac.temp0_0.get(), qdac.temp0_0.unit)\n", - "print(qdac.temp2_1.get(), qdac.temp0_0.unit)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Resetting the driver and the QDAC\n", - "To get to a well defined state, the QDAC should be powered off and then on before starting this driver.\n", - "\n", - "Alternatively the reset command can be executed. The reset command can also be used to recover an off/on situation of the QDAC without having to restart the driver." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qdac.reset(update_currents=False)\n", - "# Then print the overview gain\n", - "qdac.print_overview(update_currents=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Shut down the VISA connection\n", - "qdac.close()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "'Python Interactive'", - "language": "python", - "name": "30e14b23-afba-469e-97a2-7642068d43d1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - }, - "nbsphinx": { - "execute": "never" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 6d2bf033e3781eff9a16523ea5a3a79e67c619bb Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Mon, 23 Jan 2023 09:49:31 +0100 Subject: [PATCH 16/17] Add changelog for 4932 --- docs/changes/newsfragments/4932.breaking | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/changes/newsfragments/4932.breaking diff --git a/docs/changes/newsfragments/4932.breaking b/docs/changes/newsfragments/4932.breaking new file mode 100644 index 00000000000..63d0aec194a --- /dev/null +++ b/docs/changes/newsfragments/4932.breaking @@ -0,0 +1,2 @@ +The QDevil QDAC 1 driver has been migrated to qcodes_contrib_drivers and is included from version +0.18.0. The driver in QCoDeS is deprecated and will be removed in a future release. From fd0642b141009686e62eabaf65b5448e3a009e22 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Sun, 22 Jan 2023 20:27:47 +0100 Subject: [PATCH 17/17] remove unused imports --- qcodes/tests/instrument_mocks.py | 2 +- qcodes/tests/parameter/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py index 63f055fded5..00e253f5c19 100644 --- a/qcodes/tests/instrument_mocks.py +++ b/qcodes/tests/instrument_mocks.py @@ -3,7 +3,7 @@ import logging import time from functools import partial -from typing import Any, Dict, Generator, List, Optional, Sequence, Union +from typing import Any, Generator, Sequence, Union import numpy as np diff --git a/qcodes/tests/parameter/conftest.py b/qcodes/tests/parameter/conftest.py index ddc7ea60072..ea8e0f803e8 100644 --- a/qcodes/tests/parameter/conftest.py +++ b/qcodes/tests/parameter/conftest.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections import namedtuple -from typing import Any, Generator, Optional +from typing import Any, Generator import pytest