Math

spinlab.math.lineshape.dysonian(x, x0, gamma, alpha, integral=1.0, deriv=False)

Dysonian distribution. Asymmetric lineshape from a mix of absorption (Lorentzian) and dispersion contributions, as observed by EPR/CESR on conducting samples where the microwave skin depth is comparable to or smaller than the sample size.

Parameters:
  • x (array_like) -- input x

  • x0 (float) -- Center of distribution

  • gamma (float) -- Lorentzian width. 2*gamma is full width at half maximum (FWHM)

  • alpha (float) -- Asymmetry (dispersion-to-absorption mixing) parameter. alpha=0 reduces the Dysonian to a pure (symmetric) Lorentzian.

  • integral (float) -- Integral of the absorption (symmetric) part of the distribution

  • deriv (boolean) -- Derivative of a Dysonian distribution

Returns:

Dysonian distribution

Return type:

ndarray

The Dysonian distribution is defined as:

\[f(x) = \frac{1}{\pi} \left[\frac{\gamma + \alpha (x - x_0)}{(x-x_0)^2 + \gamma^2}\right]\]

Derivative:

\[f(x) = \frac{1}{\pi} \left[\frac{\alpha \left(\gamma^2 - (x-x_0)^2\right) - 2 \gamma (x - x_0)}{\left( (x-x_0)^2 + \gamma^2 \right)^2}\right]\]

Example

Evaluate a Dysonian at its center and its derivative off-center:

>>> from spinlab.math import lineshape
>>> round(float(lineshape.dysonian(0, 0, gamma=1, alpha=0.5)), 4)
0.3183
>>> round(float(lineshape.dysonian(1, 0, gamma=1, alpha=0.5)), 4)
0.2387
>>> round(float(lineshape.dysonian(1, 0, gamma=1, alpha=0.5, deriv=True)), 4)
-0.1592
spinlab.math.lineshape.gaussian(x, x0, sigma, integral=1.0, deriv=False)

Gaussian distribution.

Parameters:
  • x (array_like) -- input x

  • x0 (float) -- Center of distribution

  • sigma (float) -- Standard deviation of Gaussian distribution

  • integral (float) -- Integral of distribution

  • deriv (boolean) -- If True, return the first derivative of the Gaussian distribution instead of the distribution itself (e.g. for a field-modulated/phased spectrum). Defaults to False.

Returns:

Gaussian distribution

Return type:

ndarray

The Gaussian distribution is defined as:

\[f(x; x_0, \sigma) = \frac{1}{\sigma \sqrt{2 \pi}} \exp{\left(-\frac{(x-x_0)^2}{2 \sigma^2}\right)}\]

Derivative:

\[f(x) = -\frac{x - x_0}{\sigma^3 \sqrt{2 \pi}} \exp{\left(-\frac{(x-x_0)^2}{2 \sigma^2}\right)}\]

Example

Evaluate a Gaussian at its center and one standard deviation away, and its derivative one standard deviation away:

>>> from spinlab.math import lineshape
>>> round(float(lineshape.gaussian(0, 0, sigma=1)), 4)
0.3989
>>> round(float(lineshape.gaussian(1, 0, sigma=1)), 4)
0.242
>>> round(float(lineshape.gaussian(1, 0, sigma=1, deriv=True)), 4)
-0.242
spinlab.math.lineshape.lorentzian(x, x0, gamma, integral=1.0, deriv=False)

Lorentzian Distribution.

Parameters:
  • x (array_like) -- input x

  • x0 (float) -- Center of distribution

  • gamma (float) -- Lorentzian width. 2*gamma is full width at half maximum (FWHM)

  • integral (float) -- Integral of distribution

  • deriv (boolean) -- Derivative of a Lorentzian Distribution (Imaginary part of a phased spectrum)

Returns:

Lorentzian distribution

Return type:

ndarray

The Lorentzian distribution is defined as:

\[f(x) = \frac{1}{\pi \gamma} \left[\frac{\gamma^2}{(x-x_0)^2 + \gamma^2}\right]\]

Derivative:

\[f(x) = \frac{1}{\pi \gamma} \left[\frac{- 2\gamma^2 (x-x_0)}{\left( (x-x_0)^2 + \gamma^2 \right)^2}\right]\]

Example

Evaluate a Lorentzian at its center and its derivative off-center:

>>> from spinlab.math import lineshape
>>> round(float(lineshape.lorentzian(0, 0, gamma=1)), 4)
0.3183
>>> round(float(lineshape.lorentzian(1, 0, gamma=1, deriv=True)), 4)
-0.1592
spinlab.math.lineshape.voigtian(x, x0, sigma, gamma, integral=1.0, deriv=False)

Voigtian distribution. Lineshape given by a convolution of Gaussian and Lorentzian distributions.

Parameters:
  • x (array_like) -- input x

  • x0 (float) -- center of distribution

  • sigma (float) -- Gaussian Linewidth. Standard deviation of Gaussian distribution.

  • gamma (float) -- Lorentzian linewidth. 2*gamma is the full width at half maximum (FWHM)

  • integral (float) -- Integral of distribution

  • deriv (boolean) -- Derivative of a Voigtian distribution (Gaussian broadened imaginary part of a phased spectrum).

Returns:

Voigtian distribution

Return type:

ndarray

The Voigtian distribution is defined as:

\[f(x; x_0, \sigma, \gamma) = \frac{\operatorname{Re}[w(z)]}{\sigma \sqrt{2 \pi}}\]

with

\[z = \frac{(x - x_0) + i\gamma}{\sigma \sqrt{2}}\]

Derivative: .. math:

f(x) = \frac{1}{\sigma^3 \sqrt{2 \pi}} \left[ \gamma \operatorname{Im}[w(z)] - \left(x - x0\right) \operatorname{Re}[w(z)] \right]

with

\[z = \frac{\left( \left( x - x0 \right) + 1j \gamma \right)}{\sigma \sqrt{2}}\]

Example

Evaluate a Voigtian at its center:

>>> from spinlab.math import lineshape
>>> round(float(lineshape.voigtian(0, 0, sigma=1, gamma=1)), 4)
0.2087
spinlab.math.relaxation.buildup_function(p, E_max, p_half)

Calculate an enhancement buildup curve with a baseline of 1.

Parameters:
  • p (array_like) -- Microwave power values.

  • E_max (float) -- Saturating enhancement relative to the baseline.

  • p_half (float) -- Power where the enhancement term reaches half of E_max.

Returns:

Buildup curve evaluated at p.

Return type:

ndarray

\[f(p) = 1 + E_\mathrm{max} \frac{p}{p_{1/2} + p}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> power = np.array([0.0, 1.0, 2.0])
>>> y = sl.relaxation.buildup_function(power, E_max=-10.0, p_half=1.0)
spinlab.math.relaxation.general_biexp(t, C1, C2, tau1, C3, tau2)

Calculate a bi-exponential curve.

Parameters:
  • t (array_like) -- Time values.

  • C1 (float) -- Constant offset.

  • C2 (float) -- Amplitude of the first exponential component.

  • tau1 (float) -- Time constant of the first exponential component.

  • C3 (float) -- Amplitude of the second exponential component.

  • tau2 (float) -- Time constant of the second exponential component.

Returns:

Bi-exponential curve evaluated at t.

Return type:

ndarray

\[f(t) = C_1 + C_2 e^{-t/\tau_1} + C_3 e^{-t/\tau_2}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> t = np.linspace(0.0, 5.0, 51)
>>> y = sl.relaxation.general_biexp(t, C1=0.0, C2=1.0, tau1=0.5, C3=0.2, tau2=3.0)
spinlab.math.relaxation.general_exp(t, C1, C2, tau)

Calculate a mono-exponential curve.

Parameters:
  • t (array_like) -- Time values.

  • C1 (float) -- Constant offset.

  • C2 (float) -- Exponential amplitude.

  • tau (float) -- Exponential time constant.

Returns:

Mono-exponential curve evaluated at t.

Return type:

ndarray

\[f(t) = C_1 + C_2 e^{-t/\tau}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> t = np.linspace(0.0, 5.0, 51)
>>> y = sl.relaxation.general_exp(t, C1=0.0, C2=1.0, tau=2.0)
spinlab.math.relaxation.ksigma_smax(p, E_max, p_half)

Calculate an asymptotic saturation curve without a baseline offset.

Parameters:
  • p (array_like) -- Microwave power values.

  • E_max (float) -- Saturating value of the curve.

  • p_half (float) -- Power where the curve reaches half of E_max.

Returns:

Saturation curve evaluated at p.

Return type:

ndarray

\[f(p) = E_\mathrm{max} \frac{p}{p_{1/2} + p}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> power = np.array([0.0, 1.0, 2.0])
>>> y = sl.relaxation.ksigma_smax(power, E_max=5.0, p_half=1.0)
spinlab.math.relaxation.logistic(x, c, x0, L, k)

Calculate a logistic growth curve.

Parameters:
  • x (array_like) -- Input values.

  • c (float) -- Baseline offset.

  • x0 (float) -- Midpoint of the sigmoid.

  • L (float) -- Sigmoid amplitude.

  • k (float) -- Growth steepness.

Returns:

Logistic curve evaluated at x.

Return type:

ndarray

\[f(x) = c + \frac{L}{1 + e^{-k(x-x_0)}}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> x = np.linspace(0.0, 1.0, 5)
>>> y = sl.relaxation.logistic(x, c=0.0, x0=0.5, L=1.0, k=2.0)
spinlab.math.relaxation.t1(t, T1, M_0, M_inf)

Calculate a T1 exponential recovery curve.

This form can describe inversion-recovery or saturation-recovery data depending on the chosen initial magnetization M_0.

Parameters:
  • t (array_like) -- Time values.

  • T1 (float) -- Longitudinal relaxation time constant.

  • M_0 (float) -- Initial magnetization at t = 0.

  • M_inf (float) -- Equilibrium magnetization as t approaches infinity.

Returns:

T1 recovery curve evaluated at t.

Return type:

ndarray

\[f(t) = M_{\infty} - (M_{\infty} - M_0)e^{-t/T_1}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> t = np.linspace(0.0, 10.0, 101)
>>> y = sl.relaxation.t1(t, T1=2.0, M_0=-1.0, M_inf=1.0)
spinlab.math.relaxation.t2(t, M_0, T2, p=1.0)

Calculate a stretched or mono-exponential T2 decay curve.

Parameters:
  • t (array_like) -- Time values.

  • M_0 (float) -- Initial signal amplitude.

  • T2 (float) -- Transverse relaxation time constant.

  • p (float) -- Stretching exponent. The default p=1 gives a standard mono-exponential decay.

Returns:

T2 decay curve evaluated at t.

Return type:

ndarray

\[f(t) = M_0 e^{-(t/T_2)^p}\]

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> t = np.linspace(0.0, 5.0, 51)
>>> y = sl.relaxation.t2(t, M_0=1.0, T2=1.5)
spinlab.math.window.exponential(x, lw, shift=0.0)

Calculate exponential window function.

The window maximum is at shift (default 0) and decays symmetrically on both sides. For data starting at 0 this reproduces the classic one-sided exponential decay.

Parameters:
  • x (array_like) -- Vector of points (e.g. time axis).

  • lw (int or float) -- Linewidth in Hz.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

Exponential window function.

Return type:

ndarray

\[\mathrm{exponential} = e^{-\pi \, |x - \mathrm{shift}| \, lw}\]
spinlab.math.window.gaussian(x, lw, shift=0.0)

Calculate gaussian window function.

Parameters:
  • x (array_like) -- Vector of points (e.g. time axis).

  • lw (float) -- Full width at half maximum (FWHM) of the Gaussian.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

Gaussian window function.

Return type:

ndarray

\[\begin{split}\sigma &= \frac{lw}{2\sqrt{2\ln(2)}} \\ \mathrm{gaussian} = e^{-2\pi^{2} \sigma^{2} (x - \mathrm{shift})^{2}}\end{split}\]
spinlab.math.window.hamming(x, shift=0.0)

Calculate Hamming window function.

Parameters:
  • x (array_like, int) -- Vector of points or number of points.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

Hamming window function.

Return type:

ndarray

\[\mathrm{hamming} = 0.53836 + 0.46164\cos\left(\pi \frac{x - \mathrm{shift}}{x_{\max}}\right)\]
spinlab.math.window.hann(x, shift=0.0)

Calculate Hann window function.

Parameters:
  • x (array_like, int) -- Vector of points or number of points.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

Hann window function.

Return type:

ndarray

\[\mathrm{hann} = 0.5 + 0.5\cos\left(\pi \frac{x - \mathrm{shift}}{x_{\max}}\right)\]
spinlab.math.window.lorentz_gauss(x, lw, gauss_lw, gaussian_max=0)

Calculate lorentz-gauss window function.

Parameters:
  • x (array_like) -- Vector of points.

  • lw (int or float) -- Exponential linewidth.

  • gauss_lw (int or float) -- Gaussian linewidth.

  • gaussian_max (int or float) -- Location of maximum in gaussian window.

Returns:

Lorentz-Gauss window function.

Return type:

ndarray

\[\begin{split}\mathrm{lorentz\_gauss} &= \exp(L - G^{2}) \\ L(t) &= \pi \cdot lw \cdot t \\ G(t) &= 0.6\pi \cdot gauss\_lw \cdot (\mathrm{gaussian\_max} \cdot (N - 1) - t)\end{split}\]
spinlab.math.window.sin2(x, shift=0.0)

Calculate sin-squared window function.

Parameters:
  • x (array_like, int) -- Vector of points or number of points.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

Sin-squared window function.

Return type:

ndarray

\[\sin^{2} = \cos\left(\frac{\pi}{2} \frac{x - \mathrm{shift}}{x_{\max}}\right)^{2}\]
spinlab.math.window.traf(x, lw, shift=0.0)

Calculate TRAF (Trafficante) window function.

Parameters:
  • x (array_like) -- Vector of points (e.g. time axis).

  • lw (float) -- Linewidth in Hz.

  • shift (float) -- Position of the window maximum (default: 0).

Returns:

TRAF window function.

Return type:

ndarray

\[\begin{split}\mathrm{traf} &= \frac{f_1 (f_1 + f_2)}{f_1^{2} + f_2^{2}} \\ f_1(t) &= \exp(-|t - \mathrm{shift}| \, \pi \, lw) \\ f_2(t) &= \exp(-(T_{\max} - |t - \mathrm{shift}|) \, \pi \, lw)\end{split}\]

The shaped pulses simulation

Author: Timothy Keller

Edit: Yen-Chun Huang

spinlab.math.pulses.adiabatic(tp, BW, beta, resolution=1e-09)

Generate a complex hyperbolic-secant adiabatic pulse.

Parameters:
  • tp (float) -- Pulse length.

  • BW (float) -- Pulse bandwidth.

  • beta (float) -- Dimensionless truncation factor.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex pulse shape.

Return type:

tuple

\[\mathrm{pulse}(t) = \operatorname{sech}\left(\frac{\beta}{t_p} \left(t-\frac{t_p}{2}\right)\right)^{1+i\mu}\]

with

\[\mu = \frac{\pi BW}{\beta/t_p}\]

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.adiabatic(tp=1e-6, BW=10e6, beta=5, resolution=1e-9)
spinlab.math.pulses.chirp(tp, BW, resolution=1e-09)

Generate a complex quadratic chirp pulse.

Parameters:
  • tp (float) -- Pulse length.

  • BW (float) -- Pulse bandwidth.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex pulse shape.

Return type:

tuple

\[\mathrm{pulse}(t) = e^{i 2\pi \frac{k}{2}\left(t-\frac{t_p}{2}\right)^2}\]

with

\[k = \frac{BW}{t_p}\]

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.chirp(tp=1e-6, BW=10e6, resolution=1e-9)
spinlab.math.pulses.gaussian(tp, sigmas, resolution=1e-09)

Generate a Gaussian envelope pulse.

Parameters:
  • tp (float) -- Pulse length.

  • sigmas (float) -- Number of standard deviations from the center to each pulse edge.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex-valued Gaussian envelope.

Return type:

tuple

\[\mathrm{pulse}(t) = e^{-\frac{1}{2}\left(\frac{t-t_p/2}{\sigma}\right)^2}\]

with

\[\sigma = \frac{t_p}{2\,\mathrm{sigmas}}\]

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.gaussian(tp=1e-6, sigmas=3, resolution=1e-9)
spinlab.math.pulses.load_shape(filename)

Load a pulse shape from Xepr text shape format.

Parameters:

filename (str or path-like) -- Path to a pulse shape file.

Returns:

Complex-valued pulse shape. Real-only files are returned with zero imaginary components.

Return type:

ndarray

Examples

>>> import spinlab as sl
>>> pulse = sl.pulses.load_shape("shape.txt")
spinlab.math.pulses.plane_wave(tp, f, resolution=1e-09)

Generate a complex plane-wave pulse.

Parameters:
  • tp (float) -- Pulse length.

  • f (float) -- Plane-wave frequency.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex pulse shape.

Return type:

tuple

\[\mathrm{pulse}(t) = e^{i2\pi f\left(t-\frac{t_p}{2}\right)}\]

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.plane_wave(tp=1e-6, f=1e6, resolution=1e-9)
spinlab.math.pulses.save_shape(pulse_shape, filename, num=101)

Save a pulse shape in Xepr text shape format.

Parameters:
  • pulse_shape (array_like) -- One-dimensional real or complex pulse shape.

  • filename (str or path-like) -- Output filename.

  • num (int) -- Xepr shape number written in the header and footer.

Returns:

None

Examples

>>> import numpy as np
>>> import spinlab as sl
>>> pulse = np.array([0.0, 0.5, 1.0])
>>> sl.pulses.save_shape(pulse, "shape.txt", num=7)
spinlab.math.pulses.sinc(tp, n, resolution=1e-09)

Generate a sinc pulse.

Parameters:
  • tp (float) -- Pulse length.

  • n (float) -- Number of sinc lobes. Odd values produce a full symmetric sinc shape.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Sinc pulse shape.

Return type:

tuple

\[\mathrm{pulse}(t) = \frac{\sin\left(\frac{\pi}{2}(n+1)x\right)}{x}\]

with

\[x = \frac{t-t_p/2}{t_p/2}\]

The center point uses the analytic limit ((n + 1) / 2) * pi instead of evaluating 0 / 0.

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.sinc(tp=1e-6, n=3, resolution=1e-9)
spinlab.math.pulses.square(tp, t_length=0.0, resolution=1e-09)

Generate a square pulse.

If t_length is greater than tp, the pulse is centered in a longer zero-padded time axis. The active pulse interval is half-open: start <= t < stop.

Parameters:
  • tp (float) -- Pulse length.

  • t_length (float) -- Total length of the time axis. If this is less than or equal to tp, the time axis length is tp.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex-valued square pulse.

Return type:

tuple

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.square(tp=1e-6, resolution=1e-9)
>>> t, pulse = sl.pulses.square(tp=1e-6, t_length=2e-6, resolution=1e-9)
spinlab.math.pulses.wurst(tp, N, resolution=1e-09)

Generate a WURST envelope pulse.

Parameters:
  • tp (float) -- Pulse length.

  • N (float) -- WURST exponent controlling edge steepness.

  • resolution (float) -- Time resolution of the generated shape.

Returns:

Tuple containing:

t (ndarray): Time axis. pulse (ndarray): Complex-valued WURST envelope.

Return type:

tuple

\[\mathrm{pulse}(t) = 1 - \left|\cos\left(\frac{\pi}{t_p} \left(t-\frac{t_p}{2}\right)+\frac{\pi}{2}\right)\right|^N\]

Examples

>>> import spinlab as sl
>>> t, pulse = sl.pulses.wurst(tp=1e-6, N=20, resolution=1e-9)