epyr.signalprocessing module

The epyr.signalprocessing package provides FFT-based frequency analysis for time-dependent EPR signals: Rabi oscillations, DEER, HYSCORE, and other pulse-EPR experiments.

Frequency analysis

Frequency Analysis for Time-Domain EPR Signals

Comprehensive FFT-based frequency analysis with support for: - 1D time-domain signals (Rabi, DEER, echo decay, etc.) - 2D time-domain data with row-by-row 1D FFT processing - 2D HYSCORE-type measurements with full 2D FFT

Includes DC offset removal and apodization windows for clean spectral analysis.

epyr.signalprocessing.frequency_analysis.analyze_frequencies(time_data, signal_data, window='hann', window_alpha=None, zero_padding=2, remove_dc=True, plot=True, freq_range=None, **plot_kwargs)[source]

FFT-based frequency analysis of time-domain EPR signals.

This function performs clean FFT analysis to identify frequency components in time-dependent EPR signals, with proper DC offset removal.

Parameters:

time_datanp.ndarray

Time axis data (in ns, μs, or s)

signal_datanp.ndarray

EPR signal intensity vs time

windowstr or None, optional

Apodization window type (‘hann’, ‘hamming’, ‘blackman’, ‘kaiser’, None) Default: ‘hann’

window_alphafloat, optional

Alpha parameter for Kaiser, Gaussian windows (default: 6 for Kaiser)

zero_paddingint, optional

Zero padding factor (2 = double length, 4 = quadruple, etc.) Default: 2

remove_dcbool, optional

Remove DC offset before analysis (recommended: True)

plotbool, optional

Generate analysis plots. Default: True

freq_rangetuple of float, optional

Frequency range (min, max) to display in plots

Returns:

dict

Analysis results containing: - ‘frequencies’: Frequency axis in appropriate units - ‘power_spectrum’: Power spectral density (normalized) - ‘phase_spectrum’: Phase spectrum - ‘dominant_frequencies’: List of peak frequencies - ‘time_data’: Original time data - ‘processed_signal’: Signal after DC removal and windowing - ‘sampling_rate’: Sampling rate in Hz - ‘time_unit’: Detected time unit - ‘freq_unit’: Frequency unit

Examples:

>>> from epyr import eprload
>>> from epyr.signalprocessing import analyze_frequencies
>>>
>>> # Load Rabi data
>>> time, signal, params, _ = eprload('rabi_data.DTA')
>>> result = analyze_frequencies(time, signal, window='hann', plot=True)
>>> print(f"Dominant frequency: {result['dominant_frequencies'][0]:.3f} MHz")
Parameters:
Return type:

Dict

epyr.signalprocessing.frequency_analysis.power_spectrum(time_data, signal_data, method='welch', window='hann', nperseg=None, overlap=0.5, remove_dc=True, plot=True)[source]

Calculate power spectral density using Welch or periodogram methods.

Parameters:

time_datanp.ndarray

Time axis data

signal_datanp.ndarray

Signal data

methodstr

Method: ‘welch’ or ‘periodogram’

windowstr

Window function for Welch method

npersegint, optional

Length of each segment for Welch method

overlapfloat

Overlap fraction for Welch method (0-1)

remove_dcbool

Remove DC offset before analysis

plotbool

Generate plots

Returns:

dict

Results with frequencies and power spectrum

Parameters:
Return type:

Dict

epyr.signalprocessing.frequency_analysis.spectrogram_analysis(time_data, signal_data, window='hann', nperseg=None, overlap=0.8, remove_dc=True, plot=True)[source]

Time-frequency analysis using spectrogram.

Parameters:

time_datanp.ndarray

Time axis data

signal_datanp.ndarray

Signal data

windowstr

Window function

npersegint, optional

Length of each segment

overlapfloat

Overlap fraction (0-1)

remove_dcbool

Remove DC offset

plotbool

Generate spectrogram plot

Returns:

dict

Results with time axis, frequencies, and spectrogram

Parameters:
Return type:

Dict

epyr.signalprocessing.frequency_analysis.analyze_frequencies_2d(time_data, signal_data, mode='row_by_row', window='hann', window_alpha=None, zero_padding=2, remove_dc=True, axis=1, plot_result=False, freq_range=None, **plot_kwargs)[source]

FFT-based frequency analysis of 2D time-domain EPR signals.

This function handles 2D EPR data with two processing modes: 1. Row-by-row 1D FFT: Process each row/column independently (e.g., 2D Rabi) 2. Full 2D FFT: Process both dimensions together (e.g., HYSCORE)

Parameters:

time_datanp.ndarray or tuple of np.ndarray

Time axis data. Can be: - Single 1D array: time axis for the FFT dimension - Tuple of two 1D arrays: (time_axis1, time_axis2) for 2D FFT

signal_datanp.ndarray

2D EPR signal intensity array (shape: n_traces x n_points)

modestr, optional

Processing mode: - ‘row_by_row’: Apply 1D FFT to each row/column independently - ‘full_2d’: Apply 2D FFT to entire dataset (HYSCORE-type) Default: ‘row_by_row’

windowstr or None, optional

Apodization window type. Default: ‘hann’

window_alphafloat, optional

Alpha parameter for Kaiser, Gaussian windows

zero_paddingint, optional

Zero padding factor. Default: 2

remove_dcbool, optional

Remove DC offset before analysis. Default: True

axisint, optional

Axis to process for row_by_row mode (0=columns, 1=rows). Default: 1

plot_resultbool, optional

Generate analysis plots. Default: False

freq_rangetuple of float, optional

Frequency range (min, max) to display in plots

Returns:

For mode=’row_by_row’:
fqnp.ndarray

Frequency axis (1D array)

axis2np.ndarray

Secondary axis (field, angle, trace index, etc.)

spectrumnp.ndarray

2D FFT spectrum magnitude (n_traces x n_frequencies)

infodict

Analysis information (units, sampling_rate, mode, etc.)

For mode=’full_2d’:
fq1np.ndarray

Frequency axis 1 (1D array)

fq2np.ndarray

Frequency axis 2 (1D array)

spectrumnp.ndarray

2D FFT spectrum magnitude (n_freq1 x n_freq2)

infodict

Analysis information

Examples:

>>> # Row-by-row 1D FFT (2D Rabi oscillations)
>>> x_2d, y_2d, params, _ = eprload('rabi_2d.DTA')
>>> fq, axis2, spectrum, info = analyze_frequencies_2d(
...     x_2d[0], y_2d, mode='row_by_row', plot_result=False)
>>> # Full 2D FFT (HYSCORE)
>>> x_hyscore, y_hyscore, params, _ = eprload('hyscore.DTA')
>>> fq1, fq2, spectrum_2d, info = analyze_frequencies_2d(
...     (x_hyscore[0], x_hyscore[1]), y_hyscore,
...     mode='full_2d', plot_result=True)
Parameters:
Return type:

Tuple

epyr.signalprocessing.frequency_analysis.demo()[source]

Simple demonstration of EPR FFT analysis. Shows clean frequency analysis with DC removal and windowing.

Apodization windows

Apodization windows for signal processing Modern implementation with additional window types and features

epyr.signalprocessing.apowin.apowin(window_type, n_points, alpha=None, half_window=None)[source]

Generate apodization windows for signal processing.

Apodization windows are used to reduce spectral leakage and improve signal-to-noise ratio in Fourier transform spectroscopy.

Parameters:

window_typestr

Window type: - ‘hamming’ or ‘ham’: Hamming window - ‘hann’ or ‘han’: Hann (Hanning) window - ‘blackman’ or ‘bla’: Blackman window - ‘bartlett’ or ‘bar’: Bartlett (triangular) window - ‘connes’ or ‘con’: Connes window - ‘cosine’ or ‘cos’: Cosine window - ‘welch’ or ‘wel’: Welch window - ‘kaiser’ or ‘kai’: Kaiser window (needs alpha) - ‘gaussian’ or ‘gau’: Gaussian window (needs alpha) - ‘exponential’ or ‘exp’: Exponential window (needs alpha)

n_pointsint

Number of points in the window

alphafloat, optional

Shape parameter for Kaiser, Gaussian, and Exponential windows

half_windowstr, optional

Generate half window: ‘left’ (-1 to 0) or ‘right’ (0 to 1)

Returns:

array

Normalized window values (peak = 1)

Examples:

>>> # Hamming window
>>> w = apowin('hamming', 256)
>>> # Kaiser window with beta=6
>>> w_kaiser = apowin('kaiser', 256, alpha=6)
>>> # Half Hann window (right side)
>>> w_half = apowin('hann', 128, half_window='right')
epyr.signalprocessing.apowin.window_comparison(n_points=256)[source]

Compare different window types side by side.

Parameters:

n_pointsint

Number of points for each window

epyr.signalprocessing.apowin.frequency_response_demo(n_points=256)[source]

Show frequency response characteristics of different windows.

epyr.signalprocessing.apowin.apply_window_demo()[source]

Demonstrate windowing effect on a test signal

epyr.signalprocessing.apowin.demo()[source]

Comprehensive demonstration of apodization windows

Usage Examples

1D Rabi analysis

from epyr import eprload
from epyr.signalprocessing import analyze_frequencies

# Load a Rabi oscillation trace (time-domain)
t, y, params, _ = eprload("examples/data/Rabi2D_GdCaWO4_13dB_3057G.DSC")
trace = y[0]  # first row of the 2D dataset

# FFT with DC offset removal, Hann window, 4x zero padding
result = analyze_frequencies(
    t[0], trace,
    window="hann",
    zero_pad=4,
    remove_dc=True,
)
print(f"Dominant Rabi frequency: {result['dominant_frequencies'][0]:.3f} MHz")

2D processing modes

The 2D analysis supports two strategies:

  • Row-by-row 1D FFT – for 2D Rabi datasets, each row is an oscillation.

  • Full 2D FFT – for HYSCORE, exposes cross-peaks in the (f1, f2) plane.

from epyr.signalprocessing import analyze_frequencies_2d

result = analyze_frequencies_2d(t, y, params, mode="row_by_row")
print(f"Power spectrum shape: {result['power_spectrum'].shape}")