Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add curve header parameters to Lakeshore model 336, make group parameter take callable get_cmd #6520

Merged
40 changes: 40 additions & 0 deletions src/qcodes/instrument/sims/lakeshore_model336.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ devices:
setter:
q: "range A,\"{}\""

sensor_curve_number_A:
default: 42
getter:
q: "INCRV? A"
r: "{}"

curve_data_query_for_curve_42:
getter:
q: "CRVHDR? 42"
r: "DT-042,01110042,2,342.0,1"


temperature_B:
default: 100.0
Expand Down Expand Up @@ -96,7 +107,16 @@ devices:
setter:
q: "range A,\"{}\""

sensor_curve_number_B:
default: 41
getter:
q: "INCRV? B"
r: "{}"

curve_data_query_for_curve_41:
getter:
q: "CRVHDR? 41"
r: "DT-041,01110041,2,341.0,1"

temperature_C:
default: 100.0
Expand Down Expand Up @@ -140,7 +160,16 @@ devices:
setter:
q: "range A,\"{}\""

sensor_curve_number_C:
default: 40
getter:
q: "INCRV? C"
r: "{}"

curve_data_query_for_curve_40:
getter:
q: "CRVHDR? 40"
r: "DT-040,01110040,2,340.0,1"

temperature_D:
default: 100.0
Expand Down Expand Up @@ -184,6 +213,17 @@ devices:
setter:
q: "range A,\"{}\""

sensor_curve_number_D:
default: 39
getter:
q: "INCRV? D"
r: "{}"

curve_data_query_for_curve_39:
getter:
q: "CRVHDR? 39"
r: "DT-039,01110039,2,339.0,1"


resources:
GPIB::2::INSTR:
Expand Down
74 changes: 73 additions & 1 deletion src/qcodes/instrument_drivers/Lakeshore/Lakeshore_model_336.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING, ClassVar

import qcodes.validators as vals
from qcodes.parameters import Group, GroupParameter
from qcodes.parameters import Group, GroupParameter, Parameter

from .lakeshore_base import (
LakeshoreBase,
Expand Down Expand Up @@ -203,6 +203,78 @@ def __init__(
get_cmd=f"INTYPE? {self._channel}",
)

# Parameters related to temperature calibration curve (CRVHDR)
self.curve_number: Parameter = self.add_parameter(
"curve_number",
get_cmd=f"INCRV? {self._channel}",
set_cmd=False,
get_parser=int,
label="Temperature calibration curve number",
)
"""
Temperature calibration curve number that is selected now
"""
self.curve_name: GroupParameter = self.add_parameter(
"curve_name",
label="Temperature calibration curve name",
parameter_class=GroupParameter,
)
"""
Temperature calibration curve name
for the current curve as selected by ``curve_number``
"""
self.curve_sn: GroupParameter = self.add_parameter(
"curve_sn",
label="Temperature calibration curve SN",
parameter_class=GroupParameter,
)
"""
Temperature calibration curve SN
for the current curve as selected by ``curve_number``
"""
self.curve_format: GroupParameter = self.add_parameter(
"curve_format",
label="Temperature calibration curve format",
get_parser=int,
val_mapping={"mV/K": 1, "V/K": 2, "Ohms/K": 3, "log Ohms/K": 4},
parameter_class=GroupParameter,
)
"""
Temperature calibration curve format
for the current curve as selected by ``curve_number``
"""
self.curve_limit: GroupParameter = self.add_parameter(
"curve_limit",
get_parser=float,
label="Temperature calibration curve limit value",
parameter_class=GroupParameter,
)
"""
Temperature calibration curve limit value
for the current curve as selected by ``curve_number``
"""
self.curve_coefficient: GroupParameter = self.add_parameter(
"curve_coefficient",
get_parser=int,
label="Temperature calibration curve coefficient",
val_mapping={"negative": 1, "positive": 2},
parameter_class=GroupParameter,
)
"""
Temperature calibration curve coefficient
for the current curve as selected by ``curve_number``
"""
self.curve_parameters_group = Group(
[
self.curve_name,
self.curve_sn,
self.curve_format,
self.curve_limit,
self.curve_coefficient,
],
get_cmd=lambda: f"CRVHDR? {self.curve_number()}",
)


class LakeshoreModel336(LakeshoreBase):
"""
Expand Down
12 changes: 9 additions & 3 deletions src/qcodes/parameters/group_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ def __init__(self, name, address, **kwargs):
set_cmd: Format string of the command that is used for setting the
values of the parameters; for example, ``CMD {a}, {b}``.
get_cmd: String of the command that is used for getting the values
of the parameters; for example, ``CMD?``.
of the parameters; for example, ``CMD?``. Can also be a callable
that returns a command string, this is useful for the cases where
the command string is dynamic; for example,
``lambda: f"CMD {get_id_that_specifies_the_command()} ?"``.
separator: A separator that is used when parsing the output of the
``get_cmd`` in order to obtain the values of the parameters; it
is ignored in case a custom ``get_parser`` is used.
Expand All @@ -168,7 +171,7 @@ def __init__(
self,
parameters: Sequence[GroupParameter],
set_cmd: str | None = None,
get_cmd: str | None = None,
get_cmd: str | Callable[[], str] | None = None,
get_parser: Callable[[str], Mapping[str, Any]] | None = None,
separator: str = ",",
single_instrument: bool = True,
Expand Down Expand Up @@ -309,7 +312,10 @@ def update(self) -> None:
f"parameters - {parameter_names} since it "
f"has no `get_cmd` defined."
)
ret = self.get_parser(self.instrument.ask(self._get_cmd))
get_command = (
self._get_cmd if isinstance(self._get_cmd, str) else self._get_cmd()
)
ret = self.get_parser(self.instrument.ask(get_command))
for name, p in list(self.parameters.items()):
p.cache._set_from_raw_value(ret[name])

Expand Down
2 changes: 1 addition & 1 deletion tests/drivers/test_lakeshore.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def ask_raw(self, cmd) -> Any:
self.visa_log.debug(f"Response: {response}")
return response
else:
super().ask_raw(cmd) # type: ignore[misc]
return super().ask_raw(cmd) # type: ignore[misc]


def query(name: str) -> Callable[[Callable[P, T]], Callable[P, T]]:
Expand Down
17 changes: 15 additions & 2 deletions tests/drivers/test_lakeshore_336.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ def __init__(self, *args, **kwargs) -> None:
auto_range_enabled=0, # 'off',
range=0,
compensation_enabled=0, # False,
units=1,
) # 'kelvin')
units=1, # 'kelvin'
)
for i in self.channel_name_command.keys()
}

Expand Down Expand Up @@ -259,6 +259,19 @@ def test_setpoint(lakeshore_336) -> None:
assert h.setpoint() == setpoint


def test_curve_parameters(lakeshore_336) -> None:
# The curve numbers are assigned in the simulation pyvisa sim
# YAML file for each sensor/channel, and properties of the
# curves also include curve number in them to help testing
for ch, curve_number in zip(lakeshore_336.channels, (42, 41, 40, 39)):
assert ch.curve_number() == curve_number
assert ch.curve_name().endswith(str(curve_number))
assert ch.curve_sn().endswith(str(curve_number))
assert ch.curve_format() == "V/K"
assert str(int(ch.curve_limit())).endswith(str(curve_number))
assert ch.curve_coefficient() == "negative"


def test_select_range_limits(lakeshore_336) -> None:
h = lakeshore_336.output_1
ranges = [1, 2, 3]
Expand Down
28 changes: 25 additions & 3 deletions tests/parameter/test_group_parameter.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import re
from datetime import datetime
from typing import Any
from typing import TYPE_CHECKING, Any

import pytest

from qcodes.instrument import Instrument
from qcodes.parameters import Group, GroupParameter

if TYPE_CHECKING:
from collections.abc import Callable


@pytest.fixture(autouse=True)
def close_all_instruments():
Expand All @@ -23,7 +26,7 @@ def __init__(
initial_a: int | None = None,
initial_b: int | None = None,
scale_a: float | None = None,
get_cmd: str | None = "CMD?",
get_cmd: "str | Callable[[], str] | None" = "CMD?",
) -> None:
super().__init__(name)

Expand Down Expand Up @@ -60,7 +63,9 @@ def write(self, cmd: str) -> None:
self._a, self._b = (int(i) for i in result.groups())

def ask(self, cmd: str) -> str:
assert cmd == self._get_cmd
assert self._get_cmd is not None
get_cmd = self._get_cmd if isinstance(self._get_cmd, str) else self._get_cmd()
assert cmd == get_cmd
return ",".join(str(i) for i in [self._a, self._b])


Expand All @@ -85,6 +90,23 @@ def test_sanity() -> None:
assert dummy.b() == 10


def test_get_cmd_being_a_callable_that_returns_a_string_works() -> None:
dummy = Dummy("dummy", get_cmd=lambda: "CMD?")

assert dummy.a() == 0
assert dummy.b() == 0

dummy.a(3)
dummy.b(6)

assert dummy.a() == 3
assert dummy.b() == 6

dummy.b(10)
assert dummy.a() == 3
assert dummy.b() == 10


def test_raise_on_get_set_cmd() -> None:
for arg in ["set_cmd", "get_cmd"]:
kwarg = {arg: ""}
Expand Down
Loading