1. Working with SpectData

SpectData is the central data structure in NMRflux.jl. It stores an N-dimensional numerical data array, and one coordinate vector for each dimension, and is defined as a subtype of AbstractArray{T,N}. This means that SpectData behaves like a regular Julia array in most contexts: it supports indexing, slicing, broadcasting, and can be passed to most numerical functions that expect an array.

For reference, the type is defined as:

struct SpectData{T,N} <: AbstractArray{T,N}
dat::AbstractArray{T,N}
coord::NTuple{N,AbstractVector}
end

1.1 Loading a simple JOEL dataset

using NMRflux
using NMRflux.Examples

using Plots

data_jeol = NMRflux.Examples.Data["Spheroid culture medium"]
jdf_file  = joinpath(data_jeol["path"], "yp-5-fu-2.5-100.jdf")

params_jeol, data_td_jeol = NMRflux.load(jdf_file, :JEOL)

t_jeol = data_td_jeol.coord[1]    # time axis (s)
y_jeol = real.(data_td_jeol.dat)  # real part

plot(t_jeol, y_jeol;
xlabel = "time / s",
ylabel = "signal (a.u.)",
title = "JEOL FID (real part)")

savefig("jeol_fid_plot.svg"); nothing

The returned data from above is of type SpectData:

typeof(data_td_jeol)
SpectData{ComplexF64, 1}

1.2 Basic indexing

SpectData can be indexed just like a normal array. When you index with a range, you obtain a SpectData view with the corresponding subset of the data and coordinates:

data_td_jeol[1:5] # SpectData containing the first 5 complex points
5-element SpectData{ComplexF64, 1} with coords:(0.0:8.879999999999999e-5:0.00035519999999999996,):
  -2.1497944882665717e-7 - 7.707002455031156e-6im
 -0.00013950422110987898 - 0.00017234635428217768im
  -0.0051844162649977935 - 0.05157299135423599im
    -0.08807038729465194 - 0.21358801463142338im
    -0.08907652978845076 + 0.1320968426880609im

To access the underlying numerical values directly, you can use the dat field or broadcasted operations:

data_td_jeol.dat[1:5]     # first 5 complex values as a plain array
real.(data_td_jeol)[1:5]  # real part of first 5 points
imag.(data_td_jeol)[1:5]  # imaginary part of first 5 points
5-element SpectData{Float64, 1} with coords:(0.0:8.879999999999999e-5:0.00035519999999999996,):
 -7.707002455031156e-6
 -0.00017234635428217768
 -0.05157299135423599
 -0.21358801463142338
  0.1320968426880609

Multi dimensional SpectData objects behave analogously, with size and indexing following standard Julia conventions.

1.3 Internal structure

For a 1D SpectData object such as data_td_jeol, the two fields are:

  • data_td_jeol.dat the underlying AbstractArray{T,1} holding the numerical data values

(e.g. a complex FID or spectrum)

  • data_td_jeol.coord a 1-tuple of coordinate vectors, one per dimension. For 1D data,

coord[1] is the time axis (for FIDs) or frequency axis (for spectra)

For a 1D time domain FID:

data_array = data_td_jeol.dat   # numerical array (complex FID)
t_axis = data_td_jeol.coord[1]  # time axis
(first(t_axis), last(t_axis))
(0.0, 2.0487048)

In higher dimensions (e.g. 2D or 3D spectra), dat becomes an N-dimensional array, and coord[k] stores the coordinate vector (time, frequency, ppm, etc.) for the k-th dimension. Thus SpectData always keeps the numerical values and their physical axes together in a single coherent object. Conversion to frequency domain spectra (FFT, shifting, phasing, etc.) is handled by the processing tools described in the following sections.