Preprocessing.jl

This module implements preprocessing for EEG data.

See also Processing.jl

Methods

FunctionDescription
Eegle.Preprocessing.resampleresample EEG data
Eegle.Preprocessing.standardizestandardize EEG data
Eegle.Preprocessing.removeChannelsremove channels from EEG data
Eegle.Preprocessing.removeSamplesremove samples from EEG data
Eegle.Preprocessing.embedLagslag embedding of EEG data

📖

StatsBase.standardizeFunction
    function standardize(X::AbstractArray{T}; 
        robust::Bool = false,
        prop::Real = 0.2) 
    where T<:Real

Standardize the whole $T×N$ EEG recording X, where $T$ and $N$ denotes the number of samples and channels (sensors), respectively, using:

  • the arithmetic mean and standard deviation of all data in X if robust is false (default)
  • the Winsorized (trimmed) mean and standard deviation of all data in X if robust is true.

The trimmed statistics are computed excluding the prop proportion of data at both sides (default=0.2), thus, prop is used only if robust is true.

Example

using Eegle # or using Eegle.Preprocessing

X = randn(1024, 19) # 1024 samples, 19 sensors

stX = standardize(X)

stX = standardize(X; robust=true, prop=0.1)
source
DSP.Filters.resampleFunction
    function resample(  X::AbstractMatrix{T},
                        sr::S,
                        rate::Union{T, S, Rational};
        Nϕ::Integer = 32,
        rel_bw::Float64 = 1.0,
        attenuation::Int = 60,
        stim::Union{Vector{S}, Nothing} = nothing) 
    where {T<:Real, S<:Int}

Resampling of an EEG data matrix using the polyphase FIR filter with Kaiser window filter taps, as per the resample method in DSP.jl.

Arguments

  • X: the $T×N$ EEG matrix, where $T$ and $N$ denotes the number of samples and channels (sensors), respectively
  • sr: the original sampling rate of X
  • rate: the resampled data will have sampling rate sr * rate.

Optional Keyword Arguments

  • , rel_bw and attenuation: see resample
  • stim: a stimulation vector. If it is passed, it will be resampled so as to match the resampling of X as precisely as possible. stim must be a vector of $T$ integers.
Resampling of trials

If you need to work with individual trials (or epochs), do not resample trials individually; rather, resample the whole EEG recording and then extract the trials — see Eegle.ERPs.trials. Function Eegle.InOut.readNY allows to read data, do resampling and extract trials at once.

Downsampling

Downsampling must always be preceeded by low-pass filtering to ensure the suppression of energy above the Nyquist frequency ($s/2$), where $s$ is the new sampling rate after downsampling. The cut-off frequency for the filter is usually taken as $s/3$ and a sharp filter is used (see examples). This applies also if you wish to apply downsampling by decimation — see the examples for decimating in Eegle.Miscellaneous.remove and removeSamples.

Return the resampled data matrix.

Examples

using Eegle # or using Eegle.Preprocessing

sr = 512
X = randn(sr*10, 19)

# to downsample by a factor 4, low-pass filter at s/3 = sr/(4*3) Hz 
Z = filtfilt(X, sr, Bandpass(1, sr/(4*3)); designMethod = Butterworth(8))
Y = resample(Z, sr, 1//4) # 1//4 is Julia rational number 1/4

# upsample by a factor 2, i.e., double the sampling rate
Y = resample(X, sr, 2) 

# upsample to 128 samples per second
sr = 100
X = randn(sr*10, 19)
Y = resample(X, sr, 128/sr) 
source
Eegle.Preprocessing.removeChannelsFunction
    function removeChannels(X::AbstractMatrix{T}, 
                            what::Union{Int, Vector{S}},
                            sensors::Vector{String}) 
    where {T<:Real, S<:Int}

Remove one or more channels, i.e., columns, from the $T×N$ EEG recording X, where $T$ and $N$ denotes the number of samples and channels (sensors), respectively, and remove the corresponding elements from sensors, the provided associated vector of $N$ sensor labels.

For the use of kwarg what, see method Eegle.Miscellaneous.remove, which can be used instead of this function if you do not need to remove channels from a sensor labels vector.

Return the 3-tuple (newX, s, ne), where newX is the new EEG recording, s is the new sensor labels vector and ne is the new number of channels (sensors) in newX.

See Also Eegle.InOut.readSensors

Examples

using Eegle # or using Eegle.Preprocessing

X = randn(128, 7)
sensors = ["F7", "F8", "C3", "Cz", "C4", "P7", "P8"]

# remove second channel
X_, sensors_, ne = removeChannels(X, 2, sensors)

# remove the first five channels
X_, sensors_, ne = removeChannels(X, collect(1:5), sensors)

# remove the channel labeled as "Cz" in `sensors`
X_, sensors_, ne = removeChannels(X, findfirst(x->x=="Cz", sensors), sensors)

# remove the channels labeled as "C3", "Cz", and "C4" in `sensors`
X_, sensors_, ne = removeChannels(X, findall(x->x∈("Cz", "C3", "C4"), sensors), sensors)

# keep only channels labeled as "C3", "Cz", and "C4" in `sensors`
X_, sensors_, ne = removeChannels(X, findall(x->x∉("Cz", "C3", "C4"), sensors), sensors)
source
Eegle.Preprocessing.removeSamplesFunction
    function removeSamples( X::AbstractMatrix{T}, 
                            what::Union{Int, Vector{S}},
                            stim::Vector{S}) 
    where {T<:Real, S<:Int}

Remove one or more samples, i.e., rows, from the $T×N$ EEG recording X, where $T$ and $N$ denotes the number of samples and channels (sensors), respectively, and remove the corresponding elements from stim, the associated stimulation vector.

For the use of kwarg what, see method Eegle.Miscellaneous.remove, which can be used instead of this function if you do not need to remove tags from a stimulation vector.

Print a warning if elements in what correspond to non-zero tags in stim.

Return the 3-tuple (newX, s, ne), where newX is the new data, s is the new stimulation vector and ns is the new number of samples in newX.

Examples

using Eegle

sr, ne = 256, 7
X = randn(sr, ne)
stim = rand(0:3, sr)

# remove second sample
X_, stim_, ns = removeSamples(X, 2, stim)

# remove the first 128 samples
X_, stim_, ns = removeSamples(X, collect(1:128), stim)

# remove every other sample (decimation by a factor of 2)
X_, stim_, ns = removeSamples(X, collect(1:2:length(stim)), stim)

# NB: before decimating the data must be low-pass filtered,
# see the documentation of `resample`
source
Eegle.Preprocessing.embedLagsFunction
    function embedLags( X::AbstractMatrix{T}, 
                        lags = 0) 
    where T<:Real 

Lag embedding (or delay embedding) is a technique to augment the data. Second-order statistics of the augmented data, that is, covariance or cross-spectral matrices, hold information not only of volume conduction and instantaneous connectivity, but also of lagged connectivity. These matrices can be used, for example, in blind source separation and Riemannian classification.

Lag embedding is employed in chaos theory for studying dynamical systems by means of recurrence analysis — see package DelayEmbeddings.jl for advanced delay embedding techniques.

If lags = 0 (default), return X (no lag embedding).

Tutorials xxx, xxx

Description

Given the $T×N$ EEG recording X, where $T$ and $N$ denotes the number of samples and channels (sensors), respectively, and $L>0$ lags, the $T×N(L+1)$ lag-embedded data matrix is

\[X_{\text{lags}} = \left[ X^{(0)} \;\; X^{(1)} \;\; \cdots \;\; X^{(L)} \right],\]

where, letting $\mathbf{0}_{A \times B}$ the $A \times B$ matrix of zeros, for each $l = 0, \ldots, L$, the $T×N$ lagged partition $X^{(l)}$ is defined as

\[X^{(l)} = \left[ \begin{matrix} \mathbf{0}_{(L - l) \times N} \\ X[1:(T - L), \: :] \\ \mathbf{0}_{l \times N} \end{matrix} \right].\]

Notice that the are no zeros appended to the first partition and no zeros prepended to the last partition. Notice also that the lag-embedded data has the same size of the input, however the last $L$ samples are lost.

Return the $T×N(L+1)$ lag-embedded data matrix $X_{\text{lags}}$.

Example

using Eegle # or using Eegle.Preprocessing

X = randn(8, 2) # small example to see the effect

elX = embedLags(X, 3)
source