# ==============================================================================
# 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.
# ==============================================================================
"""
Stark effect for NV center.
The NV center exhibits both DC and AC Stark effects when exposed
to electric fields. The quadratic Stark effect shifts the spin
levels through coupling to the orbital states.
Physics
-------
The Stark Hamiltonian is:
H_stark = d_⊥ · E_⊥ · (S_x² - S_y²) + d_∥ · E_∥ · S_z²
where:
- d_⊥ ≈ 17 Hz/(V/m) is the perpendicular Stark coefficient
- d_∥ ≈ 3.5 Hz/(V/m) is the parallel Stark coefficient
- E_⊥, E_∥ are the electric field components
The full tensor form is:
H_stark = Σ_{ij} D_{ij} E_j {S_i, S_i'}/2
Typical Values
--------------
- d_⊥ = 17 ± 3 Hz/(V/m)
- d_∥ = 3.5 ± 0.8 Hz/(V/m)
For typical lab fields of 10⁶ V/m, this gives shifts of ~10-20 kHz.
References
----------
[1] van Oort & Glasbeek, Chemical Physics Letters 168, 529 (1990)
[2] Dolde et al., Phys. Rev. Lett. 112, 097603 (2014)
"""
import numpy as np
from typing import Optional, Callable, Tuple
from numpy.typing import ArrayLike
from .base import HamiltonianTerm
from ...core.operators import spin1_operators, extend_to_18x18
from ...core.constants import HZ
[docs]
class Stark(HamiltonianTerm):
"""
Stark effect (DC and AC electric field coupling).
Parameters
----------
d_perp : float
Perpendicular Stark coefficient in Hz/(V/m). Default: 17e-3
d_par : float
Parallel Stark coefficient in Hz/(V/m). Default: 3.5e-3
E_field : array_like
Static electric field vector [Ex, Ey, Ez] in V/m. Default: (0,0,0)
E_field_func : callable, optional
Time-dependent E(t) function returning [Ex, Ey, Ez].
If provided, makes the term time-dependent.
name : str, optional
Custom name for the term
Attributes
----------
d_perp : float
Perpendicular Stark coefficient in Hz/(V/m)
d_par : float
Parallel Stark coefficient in Hz/(V/m)
E_field : np.ndarray
Static electric field in V/m
Examples
--------
>>> from sim import HamiltonianBuilder
>>> from sim.hamiltonian.terms import ZFS, Stark
>>>
>>> # Static electric field along z
>>> H = HamiltonianBuilder()
>>> H.add(ZFS(D=2.87))
>>> H.add(Stark(E_field=[0, 0, 1e6])) # 1 MV/m along z
>>>
>>> # AC Stark effect (from optical field)
>>> def ac_field(t):
... return [1e6 * np.sin(2 * np.pi * 1e9 * t), 0, 0]
>>>
>>> H.add(Stark(E_field_func=ac_field))
Notes
-----
The Stark effect is typically small compared to ZFS and Zeeman
effects unless very strong electric fields are applied.
The AC Stark shift from optical fields can be significant
when the laser is detuned from the optical transition.
"""
[docs]
def __init__(
self,
d_perp: float = 17e-3, # Hz/(V/m)
d_par: float = 3.5e-3, # Hz/(V/m)
E_field: ArrayLike = (0, 0, 0), # V/m
E_field_func: Optional[Callable] = None,
name: Optional[str] = None
):
super().__init__(name=name)
self.d_perp = d_perp
self.d_par = d_par
self.E_field = np.array(E_field, dtype=float)
self._E_func = E_field_func
# Cache for static term
self._cache: Optional[np.ndarray] = None
@property
def is_time_dependent(self) -> bool:
"""True if E_field_func is provided."""
return self._E_func is not None
def _build_3x3(self, E: np.ndarray) -> np.ndarray:
"""
Build 3×3 Stark Hamiltonian for given electric field.
Parameters
----------
E : np.ndarray
Electric field vector [Ex, Ey, Ez] in V/m
Returns
-------
np.ndarray
3×3 complex Hermitian matrix in rad/s
"""
S = spin1_operators()
Ex, Ey, Ez = E
# Perpendicular coupling
E_perp = np.sqrt(Ex**2 + Ey**2)
# Calculate the azimuthal angle
if E_perp > 0:
phi = np.arctan2(Ey, Ex)
else:
phi = 0
# H = d_⊥ · E_⊥ · (cos(2φ)(Sx² - Sy²) + sin(2φ){Sx, Sy})
# + d_∥ · Ez · Sz²
H_perp = self.d_perp * E_perp * (
np.cos(2 * phi) * (S.Sx @ S.Sx - S.Sy @ S.Sy) +
np.sin(2 * phi) * (S.Sx @ S.Sy + S.Sy @ S.Sx)
)
H_par = self.d_par * Ez * (S.Sz @ S.Sz)
# Convert to rad/s (d is in Hz/(V/m), E in V/m, so result is Hz)
H = (H_perp + H_par) * HZ
return H
[docs]
def build(self, t: float = 0.0) -> np.ndarray:
"""
Build the 18×18 Stark Hamiltonian at time t.
Parameters
----------
t : float
Time in seconds
Returns
-------
np.ndarray
18×18 complex Hermitian matrix in rad/s
"""
if self.is_time_dependent:
E_t = np.array(self._E_func(t))
H_3x3 = self._build_3x3(E_t)
return extend_to_18x18(H_3x3)
else:
if self._cache is None:
H_3x3 = self._build_3x3(self.E_field)
self._cache = extend_to_18x18(H_3x3)
return self._cache.copy()
[docs]
def shift_khz(self, E_par: float = 0, E_perp: float = 0) -> Tuple[float, float]:
"""
Calculate the Stark shift for given field components.
Parameters
----------
E_par : float
Parallel electric field in V/m
E_perp : float
Perpendicular electric field in V/m
Returns
-------
tuple
(shift_par, shift_perp) in kHz
"""
shift_par = self.d_par * E_par / 1000 # Convert to kHz
shift_perp = self.d_perp * E_perp / 1000
return (shift_par, shift_perp)
def __repr__(self) -> str:
if self.is_time_dependent:
return f"Stark(time-dependent)"
else:
E_mag = np.linalg.norm(self.E_field)
return f"Stark(|E|={E_mag:.2e} V/m)"