Source code for herosdevices.hardware.toptica.clock_laser

"""Drivers for the Toptica Clock Laser System (CLS) modules."""

import numpy as np

from herosdevices.core import DeviceCommandQuantity
from herosdevices.core.templates import SerialDeviceTemplate as SerialDevice
from herosdevices.helper import log, mark_driver


[docs] @mark_driver( name="CLS Bridge", info="Clock Laser Bridge AOM module", state="beta", product_page="https://www.toptica.com/products/narrow-linewidth-lasers/cls", ) class Bridge(SerialDevice): """Driver for Toptica Clock Laser CLS Bridge module. This class controls the CLS Bridge AOM (Acousto-Optic Modulator) module for Toptica Clock Lasers. The CLS Bridge allows precise control of the laser frequency through RF signal modulation. Attributes: freq_max (float): Maximum frequency limit of the AOM in Hz (RF signal). freq_min (float): Minimum frequency limit of the AOM in Hz (RF signal). Note: All frequencies are specified in terms of the RF signal, the diffracted light experiences double the frequency shift due to the double-pass configuration. """ freq_max: float freq_min: float _frequency: float = DeviceCommandQuantity( command_set="BRIDGE:REFERENCE:FREQUENCYOFFSET:SETPOINT {}", command_get="BRIDGE:REFERENCE:FREQUENCYOFFSET:SETPOINT?", dtype=float, ) frequency_slope: float = DeviceCommandQuantity( command_set="BRIDGE:REFERENCE:FREQUENCYOFFSET:SLEW {}", command_get="BRIDGE:REFERENCE:FREQUENCYOFFSET:SLEW?", dtype=float, ) status: str = DeviceCommandQuantity( command_get="BRIDGE:STatus?", dtype=str, ) _status_desc: str = DeviceCommandQuantity( command_get="BRIDGE:STatus:DESCription?", dtype=str, ) def __init__(self, address: str, freq_max: float, freq_min: float, timeout: float = 1.0) -> None: """Initialize the CLS Bridge device. Args: address: Serial port address for communication. freq_max: Maximum frequency limit of the AOM in Hz (RF signal). freq_min: Minimum frequency limit of the AOM in Hz (RF signal). timeout: Communication timeout in seconds (default: 1.0). """ SerialDevice.__init__( self, address, baudrate=115200, timeout=timeout, delays={"read_echo": 1.0}, read_line_termination=b"\r", write_line_termination=b"\r", ) self.freq_min = freq_min self.freq_max = freq_max def _check_frequency(self, value: float) -> bool: """Check if a frequency value is within the allowed range. Args: value: Frequency value to check in Hz (RF signal). Returns: bool: True if value is within range, False otherwise. """ if value < self.freq_min or value > self.freq_max: log.error(f"Value {value} is out of range [{self.freq_min}, {self.freq_max}]") return False return True @property def frequency(self) -> float: """Get the current frequency setting in Hz (RF signal). Returns: float: Current frequency in Hz. """ return self._frequency @frequency.setter def frequency(self, value: float) -> None: """Set the frequency instantly (no ramping). This method sets the frequency immediately by temporarily setting the slope to a very high value (1e22 Hz/s), effectively bypassing any ramping behavior. Args: value: Target frequency in Hz (RF signal). Must be within [freq_min, freq_max]. Note: The frequency is set instantly without ramping. For slow frequency changes, use the ramp_to() method instead to maintain the laser lock. """ if self._check_frequency(value): old_slope = self.frequency_slope self.frequency_slope = 1e22 self._frequency = value self.frequency_slope = old_slope
[docs] def ramp_to(self, frequency_end: float, slope: float = 1e6) -> float: """Ramp the frequency to a target value with a specified slope. This method changes the frequency gradually according to the specified slope. Args: frequency_end: Target frequency in Hz (RF signal). Must be within [freq_min, freq_max]. slope: Ramping slope in Hz/s (default: 1 MHz/s). Returns: float: Time required for the ramp to complete in seconds. Note: The returned value is the calculated time for the ramp to complete. It is the responsibility of the caller to wait for this duration before assuming the ramp is complete. The actual ramping is handled by the device hardware. """ if self._check_frequency(frequency_end): dt = np.abs(self.frequency - frequency_end) / slope self.frequency_slope = slope self._frequency = frequency_end return dt return 0.0
[docs] def get_status_description(self) -> str: """Get the detailed status description of the FNC Bridge. Returns: str: Detailed status description from the device. """ return self._status_desc