epyr.lineshapes.pseudo_modulation

epyr.lineshapes.pseudo_modulation(x, y, mod_amplitude, harmonic=1, pad=True)[source]

Compute the pseudomodulated spectrum for simulated lock-in detection.

Reproduces the signal a lock-in amplifier would record under sinusoidal field modulation of peak-to-peak amplitude mod_amplitude, applied to a spectrum recorded without field modulation.

Parameters:
  • x (np.ndarray) – Magnetic field axis, in Gauss (G) or millitesla (mT), uniformly spaced (ascending or descending).

  • y (np.ndarray) – Spectrum values at each point in x, same length as x. Real or complex.

  • mod_amplitude (float) – Peak-to-peak field modulation amplitude, in the same unit as x. Must be positive.

  • harmonic (int, default=1) – Detection harmonic: 1 for first-harmonic (first-derivative-like) detection, 2 for second-harmonic detection.

  • pad (bool, default=True) – Edge-pad y before the FFT convolution to suppress circular wraparound artifacts at the spectrum boundaries, then crop the result back to the original length.

Returns:

Pseudomodulated spectrum, same length as y. Real if y is real, complex if y is complex.

Return type:

np.ndarray

Raises:

ValueError – If x and y have different lengths, x is not uniformly spaced, mod_amplitude is not positive, or harmonic is not 1 or 2.

Notes

For a sinusoidal modulation B(t) = B0 + (mod_amplitude/2) sin(theta), the signal detected at the n-th harmonic of the modulation frequency is

S_n(B) = IFFT[ FFT(A)(k) * i^n * J_n(k * mod_amplitude / 2) ]

where A is the input spectrum, k = 2*pi*fftfreq(N, dx) is the spatial frequency conjugate to the field axis, and J_n is the Bessel function of the first kind of order n. The i^n phase factor is required: J_n(-z) = (-1)^n J_n(z), so J_n(k * mod_amplitude/2) alone is odd in k for odd n, which breaks the Hermitian symmetry a real spectrum’s FFT has and makes the IFFT purely imaginary. Multiplying by i^n restores Hermitian symmetry for every n, so the IFFT is real whenever A is real. In the small-amplitude limit, J_1(z) ~ z/2, so S_1(B) approaches (mod_amplitude/4) * dA/dB.

Examples

>>> x = np.linspace(-50, 50, 2000)
>>> y = np.exp(-x**2 / (2 * 5.0**2))
>>> y_pm = pseudo_modulation(x, y, mod_amplitude=2.0, harmonic=1)