Source code for semi_cr.core.lab.instrument.dummy_d5a
from qcodes.instrument import Instrument
from qcodes.validators import Enum, Numbers
NUM_CHANNELS = 16
# Maps span name → (min_voltage, max_voltage), matching the real D5a driver.
SPAN_RANGES: dict[str, tuple[float, float]] = {
"4v uni": (0.0, 4.0),
"4v bi": (-4.0, 4.0),
"2v bi": (-2.0, 2.0),
}
DEFAULT_SPAN = "4v bi"
[docs]
class DummyD5a(Instrument):
"""
Dummy stand-in for the SPI Rack D5a 16-channel DAC module.
Mirrors the interface of QCoDesD5a: channels and spans are accessed as
QCoDeS parameters on ``driver`` (which returns self):
driver.dac1 … driver.dac16 — voltage parameters (V)
driver.span1 … driver.span16 — span parameters ('4v uni', '4v bi', '2v bi')
Changing a span updates the corresponding dac validator, matching the
behaviour of the real driver.
Example:
>>> d = DummyD5a("d5a_1")
>>> d.driver.dac1(1.5)
>>> d.driver.dac1()
1.5
>>> d.driver.span1("2v bi") # restrict channel 1 to ±2 V
>>> d.driver.span1()
'2v bi'
"""
def __init__(self, name: str, **kwargs):
super().__init__(name, **kwargs)
self._voltages = [0.0] * NUM_CHANNELS
self._spans: list[str] = [DEFAULT_SPAN] * NUM_CHANNELS
for i in range(NUM_CHANNELS):
self.add_parameter(
f"dac{i + 1}",
unit="V",
vals=Numbers(*SPAN_RANGES[DEFAULT_SPAN]),
get_cmd=lambda i=i: self._voltages[i],
set_cmd=lambda v, i=i: self._voltages.__setitem__(i, v),
label=f"Channel {i + 1} voltage",
)
self.add_parameter(
f"span{i + 1}",
initial_value=DEFAULT_SPAN,
vals=Enum(*SPAN_RANGES.keys()),
get_cmd=lambda i=i: self._spans[i],
set_cmd=lambda span, i=i: self._set_span(i, span),
label=f"Channel {i + 1} span",
)
def _set_span(self, channel: int, span: str) -> None:
self._spans[channel] = span
getattr(self, f"dac{channel + 1}").vals = Numbers(*SPAN_RANGES[span])
@property
def driver(self) -> "DummyD5a":
"""Return self so that d5a.driver.dacN() works identically to QCoDesD5a."""
return self
[docs]
def get_idn(self) -> dict:
return {"vendor": "Dummy", "model": "D5a", "serial": None, "firmware": None}