Bruker EPR data, EPRpy and ILTpy
[1]:
# This file is part of ILTpy examples.
# Author : Dr. Davis Thomas Daniel
# Last updated : 25.08.2025
This example shows an ILTpy workflow involving EPR data acuqired on a Bruker spectrometer, reading it using eprpy and then ILT analysis using ILTpy.
eprpy is a python library for reading EPR data stored in Bruker file formats. For more information see eprpy’s documentation.
The dataset is a field-resolved inversion recovery dataset, the sample is TEMPO radical. The measurement was done at room temperature.
Imports
[2]:
import eprpy as epr # eprpy
import iltpy as ilt # iltpy
import numpy as np # numpy
import matplotlib.pyplot as plt # matplotlib
plt.style.use("../../../examples/latex_style.mplstyle")
print("eprpy version: ",epr.__version__)
print("ILTpy version: ",ilt.__version__)
eprpy version: 0.9.0a8
ILTpy version: 1.0.0
Read the Bruker data using eprpy
[3]:
epr_data = epr.load("../../../examples/EPR/bruker_data_IR/T1_VS_FIELD.DSC")
[4]:
data,t,field_vals = epr_data.data.real,epr_data.x,epr_data.y # extract real data, echo delays, and field values
[5]:
print(f"Data shape : {data.shape}")
print(f"Number of delays : {t.shape}")
print(f"Number of field values: {field_vals.shape}")
Data shape : (128, 512)
Number of delays : (512,)
Number of field values: (128,)
[6]:
# note that iltpy requires the dimension which is to be inverted to be the first in case of inversions where both dimensions are not inverted.
Data preparation
[7]:
plt.plot(data[64]) # 64th recovery delay
[7]:
[<matplotlib.lines.Line2D at 0x1352b5190>]

[8]:
# set noise variance to unity by finding a noise region and its standard deviation
noise = np.std(data[0][0:200])
print(f"SD: {noise}")
data = data/noise
SD: 791.9111297992977
[9]:
# iltpy expects the dimension to be inverted to be the first, so we transpose the data
data = data.T # new shape : (512,128)
ILTpy workflow
Load the data
[10]:
ilt_data = ilt.iltload(data=data,t=t)
Initialize and invert
[11]:
ilt_data.init(tau = np.logspace(2,8,100),kernel=ilt.Exponential())
[12]:
ilt_data.invert()
Starting iterations ...
100%|██████████| 100/100 [00:37<00:00, 2.65it/s]
Done.
Plot the results
[13]:
import numpy as np
import matplotlib.pyplot as plt
# Prepare the data
x = field_vals/10 # convert Gauss to mT
y = np.log10(ilt_data.tau[0].flatten()/1000) # convert from ns to µs
Z = -ilt_data.g # Relaxation distribution, we use the negative since this is an inversion recovery dataset
X, Y = np.meshgrid(x, y)
fig = plt.figure(figsize=(8*0.8, 6*0.8))
ax = fig.add_subplot(111, projection='3d')
ax.view_init(elev=50, azim=-35)
surf = ax.plot_surface(X, Y, Z, cmap='jet', edgecolor='none', antialiased=True)
ax.set_xlabel("Magnetic field [mT]",fontsize=10)
ax.set_ylabel(r'$log(T_{1}/ \mu s)$',fontsize=10)
fig.colorbar(surf, ax=ax, shrink=0.5)
plt.tight_layout()
plt.show()

Note
Inversion recovery curves may exhibit non-zero baselines, which may be interpreted by the algorithm as a slow relaxing component.
This artefact manifests in the obtained relaxation distribution as a negative peak with a long relaxation time constant, as seen above.
You can separate this artifact from the real feature by defining a tau vector which has its maximum farther away from the feature of interest.