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)