2. T2 Measurement#

The following example shows how to perform a T2 measurement and fit the T2 decay to get the T2 value. The example can essentially be broken down as follows:

  1. Create an AcquisitionControl using the default device configuration from the repository. Here we can also set the log level for the log-file and the console log-output.

  2. Construct the T2 relaxation sequence. The range of echo times used for the measurement is given as a tuple. The number of experiments in between is defined by num_steps. The repetition time (TR) between each spin-echo experiments can also be specified. Note that this sequence constructor also returns a list of TE values used in the experiment.

  3. Define AcquisitionParameter, namely Larmor frequency \(f_0\), b1 scaling factor and the DDC decimation factor.

  4. Execute the experiment and extract the raw data. The data for the different TE values is stored in the phase encoding dimension. E.g. if num_steps = 50, the second last dimension of the raw data should be 50.

  5. Extract the maximum of the complex signal in time domain for each echo time.

  6. Define the T2 model given by \(A + B e^{- \frac{\text{TE}}{C}}\) and fit the determined maximum values using the TE values from the sequence.

  7. The fitted parameters are used to calculate the decay for a larger echo-time-space and the result is plotted along with the measured data points.

  8. Add some note to the meta data of the AcquisitionData and save the results using the write method.

  9. Delete the acquisition control. This is an important step, as the destructor __del__ of the AcquisitionControl class disconnects from the measurement cards.

"""Spin-echo spectrum."""

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

import console
from console.interfaces.acquisition_data import AcquisitionData
from console.spcm_control.acquisition_control import AcquisitionControl
from console.utilities import sequences

# Create acquisition control instance
acq = AcquisitionControl(configuration_file="example_device_config.yaml")

# Construct and plot sequence
params = {
    "echo_time_range": (10e-3, 100e-3),
    "num_steps": 50,
    "repetition_time": 600e-3,
}
seq, te_values = sequences.t2_relaxation.constructor(**params)

# Set larmor frequency and b1 scaling factor
console.parameter.larmor_frequency = 2038550.0
console.parameter.b1_scaling = 2.43

# Perform acquisition
acq.set_sequence(sequence=seq)
acq_data: AcquisitionData = acq.run()
data = np.mean(acq_data.raw, axis=0).squeeze()

peaks = np.max(data, axis=-1)


# T2 model to fit the acquired data
def t2_model(te_values, a, b, c) -> np.ndarray:
    """Model for T2 relaxation."""
    return a + b * np.exp(-te_values / c)


# Fit parameters to measured data
params = curve_fit(t2_model, xdata=te_values, ydata=np.abs(peaks))[0]
t2 = params[-1]

te_values_fit = np.linspace(te_values[0], te_values[-1], 1000)

# Calculate decay with fitted parameters
t2_fit = t2_model(te_values_fit, *params)

# Plot measurement and fit
fig, ax = plt.subplots(1, 1, figsize=(10, 6))
ax.scatter(te_values * 1e3, np.abs(peaks), marker="x", c="b", label="Measurement")
ax.set_xlabel("TE [ms]")
ax.set_ylabel("Abs. signal ampliude [mV]")
ax.plot(te_values_fit * 1e3, t2_fit, linestyle="--", c="r", label=f"Fit, T2 = {round(t2 * 1e3, 4)} ms")
ax.legend()

# Save
# Add information to acquisition data
acq_data.add_info({
    "preamp": "china_preamp",
    "te_values": list(te_values),
    "T2_ms": t2,
})
acq_data.save()

del acq