Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

FFT Basics

In MRI and MRS, we constantly move between the time domain and frequency domain, or between kk-space and image space.

While numpy.fft is incredibly fast, applying it directly to physical data is notoriously finicky: it places the zero-frequency (DC) component at the edges, requiring manual fftshift operations, and it scales the signal amplitude by the number of points, breaking energy conservation (Parseval’s theorem) between domains.

The xmris Fourier module provides a mathematically rigorous, xarray-native toolbox to solve these issues. It handles orthogonal normalization, coordinate math, and shifting automatically.

Overview of Available Functions

The module provides three pairs of functions to handle any transformation scenario:

  1. Pure Transforms (fft / ifft):

    Performs orthogonal, N-dimensional transforms with no shifting. Perfect for signals that strictly start at t=0t=0.

  2. Explicit Shifts (fftshift / ifftshift):

    Safely rolls both the data matrix and the coordinate axes, keeping physical labels perfectly aligned with the data.

  3. Centered Transforms (fftc / ifftc):

    Convenience wrappers for symmetrically sampled data (like imaging). It chains shifts before and after the transform to keep the zero-frequency component dead center.

Under the Hood: No Magic Strings

As a user, you can pass simple strings like "time" and "frequency" to xmris functions. However, internally, the package never uses raw strings. It maps your input to a strict global vocabulary (xmris.core.config.DIMS and COORDS).

This architecture allows xmris to intercept your request and automatically inject physical metadata (like setting the new coordinate units to Hz or s) without you ever having to ask for it!

For more info see xmris Architecture: Why We Built It This Way


1. 1D Signal: Time Domain to Frequency Domain

Let’s generate a simple, synthetic time-domain signal: a decaying sine wave with a 50 Hz frequency offset.

<Figure size 1200x450 with 1 Axes>

Now, we apply the Fourier transform.

Crucial detail: Because this specific signal starts exactly at t=0t=0, we cannot use the centered wrapper fftc. Applying an ifftshift to the input would physically split our t=0t=0 data point and move it to the center of the array, completely destroying the signal phase.

Instead, we use the pure .xmr.fft() followed by an explicit .xmr.fftshift(). By providing out_dim="frequency", the toolbox automatically calculates the reciprocal coordinate values (Hz) based on the input dwell time and renames the dimension for us.

<Figure size 1200x450 with 1 Axes>
Notebook Cell

2. Imaging: 2D kk-space to Image Space

The true power of xarray + xmris shines in multi-dimensional data. Let’s create a synthetic 2D kk-space using custom dimension strings ("kx" and "ky"). We will use a simple 2D rectangle, which analytically transforms into a 2D sinc function in the image domain.

<Figure size 750x750 with 1 Axes>

Unlike the 1D signal starting at t=0t=0, imaging data is symmetrically sampled around the center of kk-space. To transform this correctly, we must shift the input before the transform, and shift the output after.

We use the convenience wrapper .xmr.ifftc() to handle these shifts automatically. By passing a list of dimensions, we perform a 2D inverse Fourier transform and seamlessly map ["kx", "ky"] to ["x", "y"] in a single line.

<Figure size 750x750 with 1 Axes>