Source code for sim.interfaces.laser
# ==============================================================================
# QUSIM - Quantum Simulator for NV Centers
# Leon Kaiser, MSQC Goethe University, Frankfurt, Germany
# https://msqc.cgi-host6.rz.uni-frankfurt.de
# I.kaiser[at]em.uni-frankfurt.de
#
# This software is provided for scientific and educational purposes.
# Free to use, modify, and distribute with attribution.
# ==============================================================================
"""
Laser interface for optical control.
The laser provides optical excitation for:
- Spin initialization (optical pumping)
- Spin readout (fluorescence detection)
- Coherent optical control (Rabi oscillations)
Laser Parameters
----------------
- Wavelength: 532 nm (green) or 637 nm (ZPL)
- Power: Typically 0.1-10 mW
- Rabi frequency: Depends on power and beam waist
The optical Rabi frequency is related to laser power by:
Ω_L = d·E₀/ℏ = d·√(2P/(ε₀cπw₀²))/ℏ
where d is the dipole moment and w₀ is the beam waist.
"""
import numpy as np
from typing import Optional, List, Tuple
from dataclasses import dataclass, field
[docs]
@dataclass
class LaserPulse:
"""Single laser pulse."""
start: float # Start time in seconds
duration: float # Duration in seconds
power: float # Power in mW
shape: str = "rect" # Pulse shape
[docs]
@dataclass
class LaserInterface:
"""
Laser interface for optical control.
Parameters
----------
wavelength : float
Laser wavelength in nm. Default: 532 (green)
power_to_rabi : float
Conversion factor from mW to MHz. Default: 10 MHz/mW
Attributes
----------
wavelength : float
Laser wavelength in nm
pulses : list
List of scheduled laser pulses
Examples
--------
>>> laser = LaserInterface()
>>> laser.add_pulse(start=0, duration=1e-6, power=1.0)
>>> laser.add_pulse(start=2e-6, duration=100e-9, power=0.5)
>>>
>>> # Get power at specific time
>>> p = laser.get_power(500e-9) # 1.0 mW
"""
wavelength: float = 532.0 # nm
power_to_rabi: float = 10.0 # MHz/mW
linewidth: float = 0.0 # MHz (for noise simulation)
_pulses: List[LaserPulse] = field(default_factory=list)
def __post_init__(self):
# Laser frequency
c = 3e8 # m/s
self.frequency = c / (self.wavelength * 1e-9) # Hz
@property
def pulses(self) -> List[LaserPulse]:
"""List of scheduled pulses."""
return self._pulses.copy()
[docs]
def clear(self):
"""Clear all pulses."""
self._pulses.clear()
[docs]
def add_pulse(
self,
start: float,
duration: float,
power: float,
shape: str = "rect"
):
"""
Add a laser pulse.
Parameters
----------
start : float
Start time in seconds
duration : float
Pulse duration in seconds
power : float
Laser power in mW
shape : str
Pulse shape: 'rect', 'gauss'. Default: 'rect'
"""
pulse = LaserPulse(start, duration, power, shape)
self._pulses.append(pulse)
[docs]
def add_cw(self, power: float, t_start: float = 0, t_end: float = 1e-3):
"""
Add continuous wave operation.
Parameters
----------
power : float
CW power in mW
t_start : float
Start time. Default: 0
t_end : float
End time. Default: 1 ms
"""
self.add_pulse(t_start, t_end - t_start, power, "rect")
[docs]
def get_power(self, t: float) -> float:
"""
Get laser power at time t.
Parameters
----------
t : float
Time in seconds
Returns
-------
float
Power in mW (0 if laser is off)
"""
for pulse in self._pulses:
if pulse.start <= t < pulse.start + pulse.duration:
if pulse.shape == "rect":
return pulse.power
elif pulse.shape == "gauss":
t0 = pulse.start + pulse.duration / 2
sigma = pulse.duration / 6
return pulse.power * np.exp(-((t - t0) / sigma) ** 2)
return 0.0
[docs]
def get_rabi(self, t: float) -> float:
"""
Get optical Rabi frequency at time t.
Parameters
----------
t : float
Time in seconds
Returns
-------
float
Rabi frequency in MHz
"""
power = self.get_power(t)
return power * self.power_to_rabi
[docs]
def is_on(self, t: float) -> bool:
"""Check if laser is on at time t."""
return self.get_power(t) > 0
[docs]
def to_optical_coupling(self):
"""
Create an OpticalCoupling term from this laser.
Returns
-------
OpticalCoupling
Hamiltonian term with this laser waveform
"""
from ..hamiltonian.terms import OpticalCoupling
return OpticalCoupling(omega=self.get_rabi)
[docs]
def schedule_initialization(
self,
t_start: float = 0,
duration: float = 1e-6,
power: float = 1.0
):
"""
Schedule an initialization pulse.
Typical initialization uses a few microseconds of green light
to optically pump into ms=0.
Parameters
----------
t_start : float
Start time in seconds
duration : float
Pulse duration in seconds. Default: 1 μs
power : float
Laser power in mW. Default: 1 mW
"""
self.add_pulse(t_start, duration, power, "rect")
[docs]
def schedule_readout(
self,
t_start: float,
duration: float = 300e-9,
power: float = 1.0
):
"""
Schedule a readout pulse.
Readout typically uses a short pulse (~300 ns) to measure
fluorescence before spin flips occur.
Parameters
----------
t_start : float
Start time in seconds
duration : float
Pulse duration. Default: 300 ns
power : float
Laser power in mW. Default: 1 mW
"""
self.add_pulse(t_start, duration, power, "rect")
def __repr__(self) -> str:
n_pulses = len(self._pulses)
return f"LaserInterface(wavelength={self.wavelength} nm, {n_pulses} pulses)"