Source code for herosdevices.hardware.menlo.dds

"""HERO driver for a DDS-based RF output of a Menlo Systems frequency comb."""

from herosdevices.helper import mark_driver
from herosdevices.interfaces.atomiq import RFSource

from .functional_layer import FunctionalLayerModule
from .ofc import OFC


[docs] @mark_driver( name="Menlo DDS", info="DDS-based RF output of a Menlo Systems frequency comb, via QWebChannel", state="alpha", additional_docs=["/tutorials/menlo_ofc.rst"], product_page="https://www.menlosystems.com/", ) class DDS(FunctionalLayerModule, RFSource): """Driver for a DDS-based RF output of a Menlo Systems frequency comb. Wraps one `functionalLayer.<funclayer_identifier>Settings` sub-tree of an already-running :py:class:`~herosdevices.hardware.menlo.ofc.OFC`. This covers only the bare DDS output. For a module that additionally has a closed feedback loop locking the DDS to a reference (a beat-note PLL), use :py:class:`~herosdevices.hardware.menlo.LaserLock` instead. Polls :py:attr:`DEFAULT_OBSERVABLES` for `observable_data` with live reads from the OFC, superseding the `RFSource` interface's own cached-value observable. Args: ofc: The OFC HERO this DDS output belongs to. funclayer_identifier: Identifier of the module's functional-layer settings object, e.g. "cw1112_1" for the sub-tree at `functionalLayer.cw1112_1Settings`. Use `ofc.explore("functionalLayer")` to find the identifier for a given module. observables: Additional observables to poll, merged on top of `DEFAULT_OBSERVABLES`, see :py:class:`~herosdevices.hardware.menlo.functional_layer.FunctionalLayerModule`. """ amp_max: float = 1.0 amp_min: float = 0.0 freq_max: float = 100e6 freq_min: float = 0.0 DEFAULT_OBSERVABLES: dict[str, dict[str, str]] = { "frequency": {"path": "dds.ddsFrequency", "unit": "Hz"}, "amplitude": {"path": "dds.outputPower", "unit": "total"}, "output_enabled": {"path": "dds.outputOn", "unit": ""}, } def __init__( self, ofc: OFC, funclayer_identifier: str, observables: dict[str, dict[str, str]] | None = None ) -> None: FunctionalLayerModule.__init__( self, ofc, f"functionalLayer.{funclayer_identifier}Settings", observables=observables ) def _set_frequency(self, frequency: float) -> None: self.ofc.set_node(self._path("dds.ddsFrequency"), int(frequency)) self.frequency = frequency def _get_frequency(self) -> float: return float(self.ofc.get_node(self._path("dds.ddsFrequency"))) def _set_amplitude(self, amplitude: float) -> None: self.ofc.set_node(self._path("dds.outputPower"), amplitude) self.amplitude = amplitude def _get_amplitude(self) -> float: return float(self.ofc.get_node(self._path("dds.outputPower"))) def _set_phase(self, phase: float) -> None: raise NotImplementedError("The Menlo DDS does not support setting a phase") def _get_phase(self) -> float: raise NotImplementedError("The Menlo DDS does not support setting a phase") @property def output_enabled(self) -> bool: """Whether the DDS output is enabled.""" return self.ofc.get_node(self._path("dds.outputOn")) @output_enabled.setter def output_enabled(self, enabled: bool) -> None: self.ofc.set_node(self._path("dds.outputOn"), enabled)