Source code for herosdevices.hardware.menlo.beat_loop
"""Base class for a Menlo Systems OFC-stabilization beat-note loop (repetition rate, CEO)."""
from .functional_layer import FunctionalLayerModule
[docs]
class BeatLoop(FunctionalLayerModule):
"""Base for an OFC-stabilization loop that locks a beat note to a target frequency.
Covers the `mainControls` shape shared by the OFC's repetition-rate and CEO loops (see
:py:class:`~herosdevices.hardware.menlo.RepetitionRate` and
:py:class:`~herosdevices.hardware.menlo.CEO`). Both loops also expose a `dds` sub-tree identical in
shape to :py:class:`~herosdevices.hardware.menlo.DDS`'s, therefore concrete subclasses mix that in directly
(`class RepetitionRate(DDS, BeatLoop)`).
"""
DEFAULT_OBSERVABLES: dict[str, dict[str, str]] = {
"locked": {"path": "mainControls.lock", "unit": ""},
"fast_output_monitor": {"path": "mainControls.fastOutput.monitor", "unit": "V"},
"slow_output_monitor": {"path": "mainControls.slowOutput.monitor", "unit": "V"},
}
@property
def locked(self) -> bool:
"""Whether the loop is currently locked."""
return self.ofc.get_node(self._path("mainControls.lock"))
@locked.setter
def locked(self, locked: bool) -> None:
self.ofc.set_node(self._path("mainControls.lock"), locked)
@property
def fast_output_locked(self) -> bool:
"""Whether the loop's fast feedback branch is currently locked. Read-only status."""
return self.ofc.get_node(self._path("mainControls.fastOutput.locked"))
@property
def fast_output_monitor(self) -> float:
"""Monitor voltage of the loop's fast feedback branch. Read-only."""
return self.ofc.get_node(self._path("mainControls.fastOutput.monitor"))
@property
def fast_output_setpoint(self) -> float:
"""Setpoint of the loop's fast feedback branch."""
return self.ofc.get_node(self._path("mainControls.fastOutput.setpoint"))
@fast_output_setpoint.setter
def fast_output_setpoint(self, setpoint: float) -> None:
self.ofc.set_node(self._path("mainControls.fastOutput.setpoint"), setpoint)
@property
def slow_output_locked(self) -> bool:
"""Whether the loop's slow feedback branch is currently locked. Read-only status."""
return self.ofc.get_node(self._path("mainControls.slowOutput.locked"))
@property
def slow_output_monitor(self) -> float:
"""Monitor voltage of the loop's slow feedback branch. Read-only."""
return self.ofc.get_node(self._path("mainControls.slowOutput.monitor"))
@property
def slow_output_setpoint(self) -> float:
"""Setpoint of the loop's slow feedback branch."""
return self.ofc.get_node(self._path("mainControls.slowOutput.setpoint"))
@slow_output_setpoint.setter
def slow_output_setpoint(self, setpoint: float) -> None:
self.ofc.set_node(self._path("mainControls.slowOutput.setpoint"), setpoint)
[docs]
def unlock_here(self) -> None:
"""Unlock the loop and immediately re-engage it at the current beat frequency.
Shared with :py:class:`~herosdevices.hardware.menlo.LaserLock`, which uses the same
`mainControls.unlockHere` node name.
Inferred from context (Menlo's own naming and the sibling `lock`/setpoint nodes) rather than verified
against vendor documentation: releases the lock if engaged, then re-engages it using the beat note as
it currently stands as the new setpoint, instead of servoing to a previously configured setpoint.
"""
self.ofc.call_method(self._path("mainControls.unlockHere"))