"""
Measurement settings
"""
from devctrl.devices import * # all device classes
from typing import Any
mset = dict[str, Any]
import logging
log = logging.getLogger(__name__)
[docs]
def assert_subdict_exists(d, key):
"""
Create a sub-dictionary if it does not exist
"""
if key in d:
if type(d[key]) != dict:
raise ValueError(f"Value to key '{key}' is not a dict, but a {type(d[key])}")
else:
d[key] = {}
[docs]
def get_subdict(d, key):
assert_subdict_exists(d, key)
return d[key]
def _apply_settings(
device: Device|None,
device_settings: mset|None,
measurement_settings: mset,
device_key: str,
key_to_setter: dict,
ignore: list[str],
defaults={},
add_name=True,
raise_when_invalid=True,
ignore_error=True,
**kwargs
) -> dict:
dev_settings = defaults | extract_settings_dict(measurement_settings, device_key, device_settings) | kwargs
log.debug(f"{device_key}: {device} <- {dev_settings}")
if dev_settings and (device is None):
log.warning(f"Found {device_key} settings, but the device is None!")
elif device and (not dev_settings):
log.warning(f"No settings for device '{device_key}'")
if device is not None:
for k, v in dev_settings.items():
if k in key_to_setter:
try:
key_to_setter[k](device, v)
except Exception as e:
if ignore_error:
log.error(f"Device={device_key}: failed to set '{k}' to '{v}': {e}")
else:
raise e
elif k in ignore:
pass
elif raise_when_invalid:
raise KeyError(f"Invalid key for {device_key}: '{k}'")
else:
log.warning(f"Invalid key for {device_key}: '{k}'")
if add_name:
dev_settings["name"] = str(device)
if isinstance(device, Device):
dev_settings["name_model"] = device.get_device_name()
return dev_settings
"""
Each of the apply_settings_xxx function takes
- a device
- a device settings dictionary, that only contains keys associated with the device
- a measurement dictionary, containing general measurement settings. Device settings are stored
in a sub-dictionary with a given key. Device settings that are applied are removed from this dictionary.
Only one method must be used: If the device settings are given directly, the device key must appear in measurement_settings.
If the device are given via the sub-dictionary in measurement_settings, device_settings must be None.
The function returns a dictionary of all the settings that were applied to the device.
"""
[docs]
def apply_settings_amplifier(amplifier: Amplifier|None, device_settings: mset|None, measurement_settings: mset, **kwargs):
key_to_setter = {
"coupling": lambda dev, v: dev.set_coupling(v),
"gain": lambda dev, v: dev.set_gain(v)
}
settings = _apply_settings(amplifier, device_settings, measurement_settings, "pre-amp", key_to_setter, [], **kwargs)
try:
mode = amplifier.get_mode()
settings["mode"] = mode
except Exception as e:
log.debug(f"Failed to get amplifier mode: {e}")
return settings
[docs]
def apply_settings_monochromator(mcm: Monochromator|None, device_settings: mset|None, measurement_settings: mset, **kwargs):
key_to_setter = {
"bandwidth_nm": lambda dev, v: dev.set_resolution_nm(v),
"bandwidth_eV": lambda dev, v: dev.set_resolution_eV(v),
}
return _apply_settings(mcm, device_settings, measurement_settings, "monochromator", key_to_setter, [], **kwargs)
[docs]
def apply_settings_led(led: LedController|None, device_settings: mset|None, measurement_settings: mset, **kwargs):
key_to_setter = {
"mode": lambda dev, v: dev.set_mode(v),
"current_A": lambda dev, v: dev.set_current_A(v),
}
settings = _apply_settings(led, device_settings, measurement_settings, "led", key_to_setter, [], **kwargs)
# Get the name of the LED lamp that is connected to the controller
if isinstance(led, LedController):
try:
settings["name_led"] = led.get_led_name(),
except Exception as e:
log.error(f"Failed to get led name: {e}")
return settings
[docs]
def apply_settings_laser(laser: Laser|None, device_settings: mset|None, measurement_settings: mset, **kwargs):
key_to_setter = {
"mode": lambda dev, v: dev.set_mode(v),
"power_mW": lambda dev, v: dev.set_power_mW(v),
}
return _apply_settings(laser, device_settings, measurement_settings, "laser", key_to_setter, [], **kwargs)
[docs]
def apply_settings_lockin(lockin: LockInAmp|None, device_settings: mset|None, measurement_settings: mset, defaults: mset={}, **kwargs):
key_to_setter = {
"time_constant_s": lambda dev, v: dev.set_time_constant_s(v),
"filter_slope": lambda dev, v: dev.set_filter_slope(v),
"sync_filter": lambda dev, v: dev.set_sync_filter(v),
"reserve": lambda dev, v: dev.set_reserve(v), # not all lockins have it
"sensitivity_volt": lambda dev, v: dev.set_sensitivity_volt(v),
"frequency_Hz": lambda dev, v: dev.set_frequency_Hz(v),
"reference": lambda dev, v: dev.set_reference(v),
"reference_trigger": lambda dev, v: dev.set_reference_trigger(v),
}
ignore = ["aux_DC", "sample_rate_Hz"]
return _apply_settings(lockin, device_settings, measurement_settings, "lock-in-amp", key_to_setter, ignore=ignore, defaults=defaults, **kwargs)