Menlo Dual Laser Lock

From: Menlo Systems

Class: herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock

Driver Quality Index: alpha

Additional Information Check before use

Menlo OFC Setup

This driver is split into one core device and several modules attached to it.

OFC opens the single QWebChannel websocket connection to the comb and exposes its raw control/status tree via get_node/set_node/explore.

Each functional-layer module (DDS, LaserLock, DualLaserLock, FXE, RepetitionRate, CEO, Oscillator) is a separate HERO. It takes the already-running OFC HERO as a constructor argument via BOSS’s "ofc": "$device_menlo_ofc" reference, so all modules share the one physical connection instead of each opening their own.

See examples/menlo/ofc.json for a complete BOSS config wiring one comb with all its modules.

Some CW channels lock two wavelengths through one shared lock loop, with two separate frequency-distribution blocks instead of one. Deploying plain LaserLock against one of these fails, since it hardcodes a single frequency-distribution node name that these channels don’t have. Use DualLaserLock instead, passing both wavelengths’ node names explicitly; see examples/menlo/ofc.json for an example.

FXE wraps the comb’s 16-channel frequency counter. Unlike the other modules, it has no default observables, since which channel carries which signal is deployment-specific. Pass observables for the channels relevant to your comb, e.g. a beat on channel 3:

"arguments": {
  "ofc": "$device_ofc",
  "observables": {
    "cw_beat": {"path": "counterFrequencies.channel03", "unit": "Hz"}
  }
}

Node paths (used in get_node/set_node/observables) are firmware-dependent and not documented by Menlo. Use format_tree() to find them interactively:

>>> print(ofc.format_tree("functionalLayer.rrSettings", depth=2))
functionalLayer.rrSettings
|-- dds
|   |-- ddsFrequency = 28286800
|   |-- outputOn = True
|   `-- outputPower = 0.64
|-- mainControls
|   |-- fastOutput ...
|   |-- lock = True
|   `-- slowOutput ...
`-- repetitionRate
    |-- rrCounterRepRate = 250105340.0
    `-- rrTargetBeatRF = 250105340

Nodes shown as ... are unexpanded branches; raise depth or call format_tree again rooted at that path to descend further. explore() returns the same tree as a plain dict instead of a rendered string, if you want to process it programmatically.

For anything specific to your comb (e.g. a customer-specific fiber-noise-cancellation module), poll or control it directly instead of adding a new class: every module accepts an observables argument, merged on top of its DEFAULT_OBSERVABLES, and OFC.get_node/OFC.set_node give full read/write access to any node regardless.

"arguments": {
  "host": "IP_OR_HOSTNAME",
  "observables": {
    "fnc578_locked": {"path": "functionalLayer.fnc578Settings.mainControls.lock", "unit": ""},
    "fnc1157_locked": {"path": "functionalLayer.fnc1157Settings.mainControls.lock", "unit": ""}
  }
}

Important

The OFC device’s _ensure_connected method must be reachable from the other modules over the network. HEROS excludes underscore-prefixed methods from a RemoteHERO proxy unless marked force_remote, so the OFC row in your BOSS config needs:

"extra_decorators": [["_ensure_connected", "heros.inspect.force_remote"]]

See examples/menlo/ofc.json for this in context.

Warning

The PyPI package named pywebchannel is an unrelated project; installing it will not work. Install it from source instead:

pip install "pywebchannel @ git+https://github.com/MenloSystems/pywebchannel"

pywebchannel is not declared as a project dependency, so this install step must be run manually wherever the Menlo driver is used: locally, in CI, and in any Docker image.

In a Docker Container deployment via BOSS, use the BOSS_PIP_PKGS environment variable (see the BOSS documentation) instead of extending the image:

docker-compose.yml
 services:
   device_ofc:
     image: registry.gitlab.com/atomiq-project/herosdevices:latest
     restart: always
     network_mode: host
     volumes:
       - ./ofc.json:/ofc.json:ro
     environment:
       - BOSS_PIP_PKGS=pywebchannel@git+https://github.com/MenloSystems/pywebchannel
     command: python -m boss.starter -u file:///ofc.json --log info

Driver for a dual-wavelength laser-lock channel of a Menlo Systems frequency comb.

Some CW channels (e.g. “CW 507 / 1014 / 1542”, “CW 578 / 1157 / 1542” in Menlo’s vendor software) lock two wavelengths through one shared dds/mainControls/frequencyControl/amp* node set, but have two separate frequencyDistribution<wavelength> blocks (one per wavelength) instead of a single plain frequencyDistribution, plus a single-wavelength thermo-electric-cooler node. Deploying plain LaserLock against one of these channels fails, since its frequencyDistribution.* properties hardcode a node name these channels don’t have - use DualLaserLock instead, which composes both wavelength-suffixed nodes plus the TEC node explicitly.

Bold arguments are mandatory. For more information on the listed arguments refer to the class documentation: herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock If parameters appear in this list but not in the class definition, please recursively check the linked base classes for the definition of the parameter.

Argument

Type

Default Value

Description

ofc

<class ‘herosdevices.hardware.menlo.ofc.OFC’>

The OFC HERO this dual-wavelength channel belongs to.

funclayer_identifier

<class ‘str’>

Identifier of the module’s functional-layer settings object, e.g. “cw507_1014” for the sub-tree at functionalLayer.cw507_1014Settings.

primary_frequency_distribution_node

<class ‘str’>

Relative node name of the first wavelength’s frequency-distribution block (mapped to frequency_distribution, inherited from LaserLock), e.g. “frequencyDistribution507”.

secondary_frequency_distribution_node

<class ‘str’>

Relative node name of the second wavelength’s frequency-distribution block (mapped to secondary_frequency_distribution), e.g. “frequencyDistribution1014”.

tec_node

<class ‘str’>

Relative node name of the channel’s thermo-electric-cooler block, e.g. “spt1014Tec”.

amp_node

str | None

None

Relative node name of the channel’s shared laser-diode current-control block (amp*), see LaserLock.

observables

dict[str, dict[str, str]] | None

None

Additional observables to poll, merged on top of DEFAULT_OBSERVABLES, see FunctionalLayerModule.

The following JSON strings can be used to start a HERO device representation of DualLaserLock using BOSS.

{
    "_id": "device_menlo_ofc_cw507_1014",
    "classname": "herosdevices.hardware.menlo.DualLaserLock",
    "arguments": {
        "ofc": "$device_menlo_ofc",
        "funclayer_identifier": "cw507_1014",
        "primary_frequency_distribution_node": "frequencyDistribution507",
        "secondary_frequency_distribution_node": "frequencyDistribution1014",
        "tec_node": "spt1014Tec",
        "amp_node": "amp507_1014"
    },
    "datasource": {
        "async": false,
        "interval": 15
    }
}

Note

This example contains a variable that references another HERO with $.

from examples/menlo/ofc.json

{
    "_id": "my_DualLaserLock",
    "classname": "herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock",
    "arguments": {
        "ofc": "<class 'herosdevices.hardware.menlo.ofc.OFC'>",
        "funclayer_identifier": "<class 'str'>",
        "primary_frequency_distribution_node": "<class 'str'>",
        "secondary_frequency_distribution_node": "<class 'str'>",
        "tec_node": "<class 'str'>",
        "amp_node": null,
        "observables": null
    }
}

generated from signature

digraph inheritance5c8a7d80d8 { bgcolor=transparent; rankdir=TB; size=""; "herosdevices.hardware.menlo.dds.DDS" [URL="../../../autoapi/herosdevices/hardware/menlo/dds/index.html#herosdevices.hardware.menlo.dds.DDS",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="Driver for a DDS-based RF output of a Menlo Systems frequency comb."]; "herosdevices.hardware.menlo.functional_layer.FunctionalLayerModule" -> "herosdevices.hardware.menlo.dds.DDS" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; "herosdevices.interfaces.atomiq.RFSource" -> "herosdevices.hardware.menlo.dds.DDS" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; "herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock" [URL="../../../autoapi/herosdevices/hardware/menlo/dual_laser_lock/index.html#herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="Driver for a dual-wavelength laser-lock channel of a Menlo Systems frequency comb."]; "herosdevices.hardware.menlo.laser_lock.LaserLock" -> "herosdevices.hardware.menlo.dual_laser_lock.DualLaserLock" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; "herosdevices.hardware.menlo.functional_layer.FunctionalLayerModule" [URL="../../../autoapi/herosdevices/hardware/menlo/functional_layer/index.html#herosdevices.hardware.menlo.functional_layer.FunctionalLayerModule",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="Base for drivers that address one sub-tree of an OFC's `functionalLayer`, relative to a fixed base path."]; "herosdevices.hardware.menlo.laser_lock.LaserLock" [URL="../../../autoapi/herosdevices/hardware/menlo/laser_lock/index.html#herosdevices.hardware.menlo.laser_lock.LaserLock",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="Driver for a laser-lock module of a Menlo Systems frequency comb."]; "herosdevices.hardware.menlo.dds.DDS" -> "herosdevices.hardware.menlo.laser_lock.LaserLock" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; "herosdevices.interfaces.Interface" [URL="../../../autoapi/herosdevices/interfaces/index.html#herosdevices.interfaces.Interface",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="Generic Interface to describe and check capabilities of a device driver."]; "herosdevices.interfaces.atomiq.AtomiqInterface" [URL="../../../autoapi/herosdevices/interfaces/atomiq/index.html#herosdevices.interfaces.atomiq.AtomiqInterface",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="This interface defines the necessary methods for a HERO to seamlessly being converted into an atomiq component."]; "herosdevices.interfaces.Interface" -> "herosdevices.interfaces.atomiq.AtomiqInterface" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; "herosdevices.interfaces.atomiq.RFSource" [URL="../../../autoapi/herosdevices/interfaces/atomiq/index.html#herosdevices.interfaces.atomiq.RFSource",color="#5fabe8",fillcolor="#5fabe827",fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,penwidth=2,shape=box,style="rounded,filled",target="_top",tooltip="HERO implementation of :external+atomiq:py:class:`atomiq.components.electronics.rfsource.RFSource`."]; "herosdevices.interfaces.atomiq.AtomiqInterface" -> "herosdevices.interfaces.atomiq.RFSource" [arrowsize=1,color="#5fabe8",dir="back",penwidth=2,style="setlinewidth(0.5)"]; }