Warning

You are reading the documentation related to the development version. Go here if you are looking for the documentation of the stable release.

One-dimensional (1D) Fourier transformation

In this notebook, we are going to transform time-domain data into 1D or 2D spectra using SpectroChemPy processing tools

[1]:
import spectrochempy as scp
  SpectroChemPy's API - v.0.6.9.dev9
© Copyright 2014-2024 - A.Travert & C.Fernandez @ LCS

FFT of 1D NMR spectra

First we open read some time domain data. Here is a NMD free induction decay (FID):

[2]:
path = scp.preferences.datadir / "nmrdata" / "bruker" / "tests" / "nmr" / "topspin_1d"
fid = scp.read_topspin(path)
fid
[2]:
name topspin_1d expno:1 procno:1 (FID)
author runner@fv-az1501-19
created 2024-04-28 03:11:42+02:00
DATA
title intensity
values
R[ 1078 2284 ... 0.2342 -0.1008] pp
I[ -1037 -2200 ... 0.06203 -0.05273] pp
size 12411 (complex)
DIMENSION `x`
size 12411
title F1 acquisition time
coordinates
[ 0 4 ... 4.964e+04 4.964e+04] µs

The type of the data is complex:

[3]:
fid.dtype
[3]:
dtype('complex128')

We can represent both real and imaginary parts on the same plot using the show_complex parameter.

[4]:
prefs = fid.preferences
prefs.figure.figsize = (6, 3)
_ = fid.plot(show_complex=True, xlim=(0, 15000))
print("td = ", fid.size)
td =  12411
../../_images/userguide_processing_fourier_9_1.png

Now we perform a Fast Fourier Transform (FFT):

[5]:
spec = scp.fft(fid)
_ = spec.plot(xlim=(100, -100))
print("si = ", spec.size)
spec
si =  16384
[5]:
name topspin_1d expno:1 procno:1 (FID)
author runner@fv-az1501-19
created 2024-04-28 03:11:42+02:00
history
2024-04-28 03:11:42+02:00> `zf_size` shift performed on dimension `x` with parameters: {'size': 16384}
2024-04-28 03:11:42+02:00> Fft applied on dimension x
2024-04-28 03:11:42+02:00> Inplace binary op: imul with `[ 0.61+0.793j 0.61+0.793j ... 0.813+0.582j 0.813+0.582j]`
2024-04-28 03:11:42+02:00> `pk` applied to dimension `x` with parameters: {'phc0': 52.43836, 'phc1': -16.8366, 'pivot': 0.0, 'exptc': 0.0}
DATA
title intensity
values
R[ -1093 -1014 ... -1031 -1079] pp
I[ -229.7 -126.8 ... 187.2 216.1] pp
size 16384 (complex)
DIMENSION `x`
size 16384
title $\delta\ ^{1}H$
coordinates
[ 253.1 253.1 ... -246.8 -246.8] ppm
../../_images/userguide_processing_fourier_11_2.png

Alternative notation

[6]:
k = 1024
spec = fid.fft(size=32 * k)
_ = spec.plot(xlim=(100, -100))
print("si = ", spec.size)
si =  32768
../../_images/userguide_processing_fourier_13_1.png
[7]:
newfid = spec.ifft()
# x coordinate is in second (base units) so lets transform it
_ = newfid.plot(show_complex=True, xlim=(0, 15000))
../../_images/userguide_processing_fourier_14_0.png

Let’s compare fid and newfid. There differs as a rephasing has been automatically applied after the first FFT (with the parameters found in the original fid metadata: PHC0 and PHC1).

First point in the time domain of the real part is at the maximum.

[8]:
_ = newfid.real.plot(c="r", label="fft + ifft")
ax = fid.real.plot(clear=False, xlim=(0, 5000), ls="--", label="original real part")
_ = ax.legend()
../../_images/userguide_processing_fourier_16_0.png

First point in the time domain of the imaginary part is at the minimum.

[9]:
_ = fid.imag.plot(ls="--", label="original imaginary part")
ax = newfid.imag.plot(clear=False, xlim=(0, 5000), c="r", label="fft + ifft")
_ = ax.legend(loc="lower right")
../../_images/userguide_processing_fourier_18_0.png

Preprocessing

Line broadening

Often before applying FFT, some exponential multiplication emor other broadening filters such as gm or sp are applied. See the dedicated apodization tutorial.

[10]:
fid2 = fid.em(lb="50. Hz")
spec2 = fid2.fft()
_ = spec2.plot()
_ = spec.plot(
    clear=False, xlim=(10, -5), c="r"
)  # superpose the non broadened spectrum in red and show expansion.
../../_images/userguide_processing_fourier_20_0.png

Zero-filling

[11]:
print("td = ", fid.size)
td =  12411
[12]:
td = 64 * 1024  # size: 64 K
fid3 = fid.zf_size(size=td)
print("new td = ", fid3.x.size)
new td =  65536
[13]:
spec3 = fid3.fft()
_ = spec3.plot(xlim=(100, -100))
print("si = ", spec3.size)
si =  65536
../../_images/userguide_processing_fourier_24_1.png

Time domain baseline correction

See the dedicated Time domain baseline correction tutorial.

Magnitude calculation

[14]:
ms = spec.mc()
_ = ms.plot(xlim=(10, -10))
_ = spec.plot(clear=False, xlim=(10, -10), c="r")
../../_images/userguide_processing_fourier_27_0.png

Power spectrum

[15]:
mp = spec.ps()
_ = (mp / mp.max()).plot()
_ = (spec / spec.max()).plot(
    clear=False, xlim=(10, -10), c="r"
)  # Here we have normalized the spectra at their max value.
../../_images/userguide_processing_fourier_29_0.png

Real Fourier transform

In some case, it might be interesting to perform real Fourier transform . For instance, as a demonstration, we will independently transform real and imaginary part of the previous fid, and recombine them to obtain the same result as when performing complex fourier transform on the complex dataset.

[16]:
lim = (-20, 20)
_ = spec3.plot(xlim=lim)
_ = spec3.imag.plot(xlim=lim)
../../_images/userguide_processing_fourier_32_0.png
../../_images/userguide_processing_fourier_32_1.png
[17]:
Re = fid3.real.astype("complex64")
fR = Re.fft()
_ = fR.plot(xlim=lim, show_complex=True)
Im = fid3.imag.astype("complex64")
fI = Im.fft()
_ = fI.plot(xlim=lim, show_complex=True)
../../_images/userguide_processing_fourier_33_0.png
../../_images/userguide_processing_fourier_33_1.png

Recombination:

[18]:
_ = (fR - fI.imag).plot(xlim=lim)
_ = (fR.imag + fI).plot(xlim=lim)
../../_images/userguide_processing_fourier_35_0.png
../../_images/userguide_processing_fourier_35_1.png