Source code for herosdevices.hardware.menlo.oscillator

"""HERO driver for the main seed oscillator of a Menlo Systems frequency comb."""

from herosdevices.helper import mark_driver

from .functional_layer import FunctionalLayerModule
from .ofc import OFC


[docs] @mark_driver( name="Menlo Oscillator", info="Main seed oscillator of a Menlo Systems frequency comb, via QWebChannel", state="alpha", additional_docs=["/tutorials/menlo_ofc.rst"], product_page="https://www.menlosystems.com/", ) class Oscillator(FunctionalLayerModule): """Driver for the main seed oscillator (fs laser) of a Menlo Systems frequency comb. Wraps the OFC's `functionalLayer.ofcSettings` sub-tree, a fixed, singleton module (there is only one seed oscillator per OFC, so unlike :py:class:`~herosdevices.hardware.menlo.DDS`/ :py:class:`~herosdevices.hardware.menlo.LaserLock` there is no `funclayer_identifier` to select). `ofcSettings` also has `xps`/`fsOscillator` pump-diode current-control nodes (e.g. `xps.diode01`, `fsOscillator.preampDiode01`), but which diodes are actually populated appears to vary by comb configuration (one observed unit had `diode01`/`diode03`/`diode04` under both trees, with no `diode02`) - not modeled here since it isn't confirmed to be a fixed, general shape. Poll/control specific diode nodes for your comb via `observables`, or `ofc.get_node`/`set_node` directly. Args: ofc: The OFC HERO this oscillator belongs to. observables: Additional observables to poll, merged on top of `DEFAULT_OBSERVABLES`, see :py:class:`~herosdevices.hardware.menlo.functional_layer.FunctionalLayerModule`. """ DEFAULT_OBSERVABLES: dict[str, dict[str, str]] = { "mode_locked": {"path": "fsOscillator.modeLockStatus.oscillatorModeLocked", "unit": ""}, "temperature": {"path": "fsOscillator.oscillatorTec.actualTemperature", "unit": "deg C"}, "dc_act": {"path": "fsOscillator.modeLockStatus.dcAct", "unit": "mV"}, "ac_act": {"path": "fsOscillator.modeLockStatus.acAct", "unit": "mV"}, "laser_enabled": {"path": "mainControls.laserEnabled", "unit": ""}, } def __init__(self, ofc: OFC, observables: dict[str, dict[str, str]] | None = None) -> None: FunctionalLayerModule.__init__(self, ofc, "functionalLayer.ofcSettings", observables=observables) @property def mode_locked(self) -> bool: """Whether the oscillator is currently mode-locked. Read-only.""" return self.ofc.get_node(self._path("fsOscillator.modeLockStatus.oscillatorModeLocked")) @property def temperature(self) -> float: """Actual temperature of the oscillator's TEC. Read-only.""" return self.ofc.get_node(self._path("fsOscillator.oscillatorTec.actualTemperature")) @property def dc_act(self) -> float: """DC component of the mode-lock detection signal. Read-only.""" return self.ofc.get_node(self._path("fsOscillator.modeLockStatus.dcAct")) @property def ac_act(self) -> float: """AC component of the mode-lock detection signal. Read-only.""" return self.ofc.get_node(self._path("fsOscillator.modeLockStatus.acAct")) @property def laser_enabled(self) -> bool: """Whether the oscillator's pump laser is enabled.""" return self.ofc.get_node(self._path("mainControls.laserEnabled")) @laser_enabled.setter def laser_enabled(self, enabled: bool) -> None: self.ofc.set_node(self._path("mainControls.laserEnabled"), enabled)