Source code for spin_pulse.environment.noise.noise_time_trace
# --------------------------------------------------------------------------------------
# This code is part of SpinPulse.
#
# (C) Copyright Quobly 2025.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# --------------------------------------------------------------------------------------
from enum import Enum
import matplotlib.pyplot as plt
import numpy as np
[docs]
class NoiseType(Enum):
"""Enumerate the supported noise models for spin-qubit simulations.
Each enum value corresponds to the time-trace class used to generate
the associated noise realization.
Noise types:
- QUASISTATIC: Quasistatic noise generated by
`QuasistaticNoiseTimeTrace`.
- PINK: Pink (1/f) noise generated by `PinkNoiseTimeTrace`.
- WHITE: White Gaussian noise generated by `WhiteNoiseTimeTrace`.
"""
[docs]
QUASISTATIC = "QuasistaticNoiseTimeTrace"
[docs]
PINK = "PinkNoiseTimeTrace"
[docs]
WHITE = "WhiteNoiseTimeTrace"
[docs]
class NoiseTimeTrace:
r"""Base class for generating and manipulating noise time traces.
A noise time trace is represented as an array of length ``duration``,
containing the instantaneous noise values :math:`\epsilon(t)` that affect the qubit.
Subclasses implement specific noise models (quasistatic, pink, white, etc.)
and populate the ``values`` array accordingly.
Attributes:
- duration (int): Total number of time steps in the noise trace.
- values (ndarray): Array of noise values of length ``duration``.
"""
def __init__(self, duration: int):
"""Initializes an empty noise time trace of given duration.
Parameters:
duration (int): Total number of time steps in the noise trace.
"""
[docs]
self.duration = duration
[docs]
self.values = np.zeros(duration)
[docs]
def ramsey_contrast(self, ramsey_duration: int) -> float:
r"""Compute the Ramsey contrast for a qubit subject to this noise trace.
The qubit is initialized in the equal superposition state :math:`\frac{\\lvert 0 \rangle + \\lvert 1 \rangle}{\\sqrt{2}}`
and evolves under a pure dephasing Hamiltonian :math:`H(t) = \\omega(t) Z`.
The Ramsey contrast is obtained from the accumulated phase :math:`\\sum_t \\omega(t)`
over segments of length ``ramsey_duration``. The trace is divided into independent
experiments of equal length and the contrast is averaged over all experiments.
Parameters:
ramsey_duration (int): Number of time steps per Ramsey experiment.
Returns:
- float: Averaged Ramsey contrast of length ``ramsey_duration``.
"""
n_exp = self.duration // ramsey_duration
contrast = 0.0
i_min = 0
for _ in range(n_exp):
omega = self.values[i_min : i_min + ramsey_duration]
contrast += np.real(np.exp(-1j * np.cumsum(omega))) / n_exp
i_min += ramsey_duration
return contrast
[docs]
def plot_ramsey_contrast(self, ramsey_duration: int):
"""Plot the Ramsey contrast computed from the noise trace.
Parameters:
ramsey_duration (int): Number of time steps per Ramsey experiment.
"""
contrast = self.ramsey_contrast(ramsey_duration)
plt.plot(contrast, label="numerics", color="blue")
plt.legend(loc=0)
plt.xlabel("$t$")
plt.ylabel("$C$")
[docs]
def plot(self, n_max: int | None = None):
"""Plot the noise trace up to a specified number of points.
Parameters:
n_max (int | None): Number of time steps to display. If None,
the full trace is shown.
"""
if n_max is None:
n_max = self.duration
plt.plot(self.values[:n_max])
plt.xlabel("$t$")
plt.ylabel(r"$\epsilon(t)$")