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