Parameters and Noise
Parametric simulations
AtomTwin uses a lightweight symbolic parameter system to separate model structure from numerical values. Rather than hard-coding frequencies, detunings, and other quantities, you wrap them in a Parameter and pass them to add_coupling!, add_detuning!, and similar functions. At play time the values are resolved — either to their defaults or to values you supply — without rebuilding the system.
Parameter objects can be combined with standard arithmetic to build ParametricExpression trees:
Ω = Parameter(:Omega, 2π * 1.0e6) # 1 MHz Rabi frequency
δ = Parameter(:delta, 0.0; std = 0.1e6) # detuning with 100 kHz shot-to-shot disorder
amp = 0.5 * Ω + δ # ParametricExpressionPass these expressions directly to physics functions, then sweep or sample at run time:
coupling = add_coupling!(system, atom, g => e, amp)
# sweep Omega over a grid
for Ω_val in range(0, 4π*1e6; length = 50)
out = play(system, seq; initial_state = g, Omega = Ω_val)
endAtomTwin.Parameter — Type
Parameter(name::Symbol, default; std = 0.0)Scalar simulation parameter with an optional static-noise standard deviation.
Parameter stores a symbolic name, a default (mean) value and a standard deviation std. The default std = 0.0 corresponds to a deterministic, noise‑free parameter; nonzero std values are typically used to draw static random offsets for disorder or calibration errors. switchable=true indicates that this parameter can be turned off for error budget calculations.
Parameters can be combined arithmetically (e.g. 2*Ω + δ) to build ParametricExpressions which are resolved to concrete numbers at run time for each noise realization or sweep point.
AtomTwin.ParametricExpression — Type
ParametricExpressionSymbolic expression tree built from Parameters, numeric literals, and basic arithmetic operations.
A ParametricExpression pairs an operator symbol (e.g. :+, :*, :abs) with a tuple of argument nodes, which can themselves be Parameters, ParametricExpressions, or plain numbers. These expressions are not evaluated immediately; instead they are resolved later given a concrete dictionary of parameter values.
Laser phase noise
Realistic laser phase noise is added by attaching a LaserPhaseNoiseModel to a coupling. The model synthesizes a time-domain noise realization from a parameterized frequency-noise power spectral density (PSD) that combines a Gaussian servo bump with a power-law background.
noise_model = LaserPhaseNoiseModel(
bump_ampl = 2.0e5, # Hz²
bump_center = 1.0e6, # Hz — servo resonance at 1 MHz
bump_width = 2.0e5, # Hz — Gaussian σ
powerlaw_ampl = 0.25e5, # Hz² — white noise floor
)
coupling = add_coupling!(system, atom, g => e, Ω;
noise_model = noise_model)Each Monte Carlo shot draws an independent noise realization; averaging over many shots (via shots = N in play) recovers ensemble-averaged dynamics.
The helper functions laser_freq_psd and laser_phase_psd evaluate the model's PSD at arbitrary frequencies, which is useful for plotting noise spectra before committing to a simulation:
freqs = range(0.1e6, 10e6; length = 500)
psd = laser_freq_psd.(Ref(noise_model), freqs)AtomTwin.LaserPhaseNoiseModel — Type
LaserPhaseNoiseModel(; bump_ampl, bump_center, bump_width,
powerlaw_ampl, powerlaw_exp = 0.0, n_freqs = 100)Realistic laser phase noise model using a parameterized frequency-noise power spectral density (PSD) in Hz²/Hz.
The PSD model combines a Gaussian “servo bump” and a power-law background:
- Servo bump: centered at
bump_centerwith widthbump_widthand amplitudebump_ampl. - Power-law:
powerlaw_ampl * f^powerlaw_exp(white frequency noise forpowerlaw_exp = 0).
Fields:
bump_ampl::Float64: Servo bump amplitude (Hz²).bump_center::Float64: Center frequency of the servo bump (Hz).bump_width::Float64: Gaussian width σ of the bump (Hz).powerlaw_ampl::Float64: Amplitude of the power-law background.powerlaw_exp::Float64: Exponentdof the power law.n_freqs::Int: Number of frequency components used when synthesizing noise.
AtomTwin.NoisyField — Type
NoisyField{A,T,N} <: Dynamiq.AbstractFieldWrapper that adds time-correlated noise to an underlying field or coupling.
Type parameters:
A: Atom type associated with the coupling.T: Type of the wrapped field/coupling (e.g.GlobalCoupling,Detuning).N <: AbstractNoiseModel: Noise model type (e.g.LaserPhaseNoiseModel).
Fields:
coupling::T: Original coupling/field object.noise::N: Noise model and parameters.global_time_ref::Ref{Float64}: Reference to the global simulation time, used to maintain temporal continuity across segments.n_freqs::Int: Number of frequency components used in the noise synthesis.rng::AbstractRNG: Random-number generator used to draw noise phases.
AtomTwin.laser_freq_psd — Function
laser_freq_psd(freqs, noise::AbstractNoiseModel) -> psdCompute the laser frequency-noise power spectral density S_ν(f) in Hz²/Hz for one or more frequencies freqs, given a noise model.
Arguments:
freqs: Single frequency (Number) or an array of frequencies (Hz).noise: Noise model, typicallyLaserPhaseNoiseModel.
Returns:
- A single PSD value if
freqsis a scalar, or a vector of PSD values matchingfreqsotherwise.
Internally this:
- Constructs a time span consistent with the requested frequency range.
- Uses
get_noise_spectrumto evaluate the canonical frequency-noise PSD on a grid. - Interpolates the result to the requested frequencies.
Example:
noise = LaserPhaseNoiseModel()
f = 10 .^ range(2, 7; length = 500) # 100 Hz to 10 MHz
Sν = laser_freq_psd(f, noise) # frequency noise PSD in Hz^2/HzAtomTwin.laser_phase_psd — Function
laser_phase_psd(freqs, noise::AbstractNoiseModel) -> psd_phaseCompute the laser phase-noise power spectral density Sφ(f) in rad²/Hz from the frequency-noise PSD Sν(f) in Hz²/Hz, using
[ S\phi(f) = \frac{S\nu(f)}{(2\pi f)^2}. ]
Arguments:
freqs: Single frequency (Number) or an array of frequencies (Hz).noise: Noise model, typicallyLaserPhaseNoiseModel.
Returns:
- Phase-noise PSD values
S_φ(f)with the same shape asfreqs.
Example:
noise = LaserPhaseNoiseModel()
f = 10 .^ range(2, 7; length = 500)
Sφ = laser_phase_psd(f, noise) # phase noise PSD in rad^2/HzGate tomography
process_tomography runs a complete set of input states through a compiled sequence and returns the Choi matrix of the resulting quantum channel. This is useful for computing gate fidelities and diagnosing error mechanisms.
choi = process_tomography(system, seq)The returned matrix is in the standard column-vectorisation convention and can be used with any quantum-information library that accepts Choi matrices.
AtomTwin.process_tomography — Function
process_tomography(
sys, seq, atom, computational_levels;
output_levels=computational_levels,
kwargs...
)Perform single-qubit quantum process tomography for atom in system sys under the pulse sequence seq.
The channel is characterized by simulating its action on the standard set of input states |0⟩, |1⟩, |+⟩, and |+i⟩ defined by computational_levels. The dynamics are obtained using play, and the output is projected onto the output_levels subspace.
Keyword arguments are forwarded to the underlying simulation calls, e.g. to control density-matrix vs. trajectory evolution or the number of shots.
Returns a named tuple with fields:
• input_states – list of prepared input states in the full Hilbert space • output_states – list of simulated output density matrices • choi_matrix – Choi matrix of the reconstructed quantum channel • ptm_matrix – Pauli transfer matrix (PTM) of the channel • kraus_operators – vector of Kraus operators
Typical usage:
res = process_tomography(sys, seq, atom, [g, e]; shots=256)
res.ptm_matrix
res.kraus_operators