InOut.jl

This module declares a structure for EEG-based BCI data and methods for reading and writing data

Methods

FunctionDescription
Eegle.InOut.EEGa structure for EEG-based BCI holding data and metadata
Eegle.InOut.readNYread EEG/BCI data in NY format as an EEG structure
Eegle.InOut.readgTecread EEG data recorded by the g.Tec g.Recorder software
Eegle.InOut.readASCIIread EEG data in ASCII text format (2 methods)
Eegle.InOut.readSensorsread EEG sensor labels from an ASCII text file
Eegle.InOut.writeASCIIwrite EEG data in ASCII text format (3 methods)

📖

Eegle.InOut.EEGType
    struct EEG
        id              :: Dict{Any,Any} 
        acquisition     :: Dict{Any,Any} 
        documentation   :: Dict{Any,Any} 
        formatversion   :: String        

        # the following fields are those most useful in practice
        db              :: String  
        paradigm        :: Symbol      
        subject         :: Int           
        session         :: Int           
        run             :: Int           
        sensors         :: Vector{String}
        sr              :: Int           
        ne              :: Int           
        ns              :: Int           
        wl              :: Int           
        offset          :: Int           
        nClasses        :: Int           
        clabels         :: Vector{String} 
        stim            :: Vector{Int}    
        mark            :: Vector{Vector{Int}}  
        y               :: Vector{Int}          
        X               :: Matrix{T} where T<:Real 
        trials          :: Union{Vector{Matrix{T}}, Nothing} 
    where T<:Real 

Data structure for an EEG BCI (Brain-Computer Interface) session, holding data and metadata.

It is written by readNY.

While conceived specifically for BCI sessions, the structure can be used also for general EEG recordings.

Fields

  • db: name of the database to which the recording belongs
  • paradigm: BCI paradigm
  • subject: serial number of the present subject in the above database
  • session: serial number of the present session for the above subject
  • run: serial number of the present run of the above session
  • sensors: labels of the scalp electrode leads in standard notation (10-20, 10-10,...)
  • sr: sampling rate in samples
  • ne: number of electrode leads
  • ns: number of samples
  • wl: window length in samples. Typically, the duration of a BCI trial
  • offset: see offset
  • nClasses: number of classes (non-zero tags)
  • clabels: labels of the classes
  • stim: the stimulation vector
  • mark: the marker vectors
  • X: the $T×N$ EEG data, with $T$ and $N$ the number of samples and channels (sensors), respectively
  • trials: a vector of trials, each of size $N×wl$, extracted in the order of tags given in stim (optional)
  • y: the non-zero tags of stim as a vector. Each tag is the class label of the corresponding trial
  • dictionaries id, acquisition, and documentation — see NY Metadata (YAML)). Their keys are:
idacquisitiondocumentation
"run""sensors""doi"
"timestamp""software""repository"
"database""ground""description"
"subject""reference""investigators"
"session""filter""place"
"condition""sensortype"
"paradigm""samplingrate"
"hardware"
tags

Regardless the class labels (tags) in the file, the .stim and .y fields are always populated using the first o.nClasses natural numbers (1,2, ...) when the structure is created by the readNY function.

In Julia, a structure has a default constructor taking all fields as arguments. A simplified constructor is also available, as

    EEG(    X::Matrix{T}, 
            sr::Int, 
            sensors::Vector{String};
        db::String = "",
        paradigm::Symbol = :NA,
        subject::Int = 0,
        session::Int = 1,
        run::Int = 1,
        wl::Int = sr,
        offset::Int = 0,
        nClasses::Int = 1,
        clabels::Vector{String} = [""],
        stim::Vector{Int} = ["0"],
        mark::Vector{Vector{Int}} = [[""]],
        y::Vector{Int} = [0])
    where T<:Real

The above creates an EEG structure providing, ad minima:

  • the EEG data X
  • the sampling rate sr
  • the sensor labels sensors.

The kwarg of this constructor are useful fields that can be filled. The remaining fields of the structure are left empty.

source
Eegle.InOut.readNYFunction
    function readNY(filename :: AbstractString;
        toFloat64   :: Bool = true,
        bandStop    :: Tuple = (),
        bandPass    :: Tuple = (),
        bsDesign    :: DSP.ZeroPoleGain = Butterworth(8),
        bpDesign    :: DSP.ZeroPoleGain = Butterworth(4),
        rate        :: Union{Real, Rational, Int} = 1,
        upperLimit  :: Union{Real, Int} = 0,
        classes     :: Union{Bool, Vector{String}} = true, 
        stdClass    :: Bool = true, 
        msg         :: String="") 

Read EEG/BCI data in NY format, prepreprocess them if desired, and create an EEG structure.

If requested, the preprocessing operations are performed in the order of the kwargs as listed here below.

Arguments

  • filename: the complete path of either the .npz or the .yml file of the recording to be read.

Optional Keyword Arguments

  • toFloat64: if true, the EEG data is converted to Float64 if it is not already (default: true)
  • bandStop: a 2-tuple holding the limits in Hz of a notch filter (default: no filter)
  • bandPass: a 2-tuple holding the limits in Hz of a band-pass filter (default: no filter)
  • bsDesign: the filter design method for the notch filter passed to filtfilt (default: Butterworth(8))
  • bpDesign: the filter design method for the band-pass filter passed to filtfilt (default: Butterworth(4))
  • rate: argument passed to resample for resampling the data (default: 1, no resampling)
  • upperLimit: argument passed to Eegle.ERPs.reject for artifact rejection (default: 0, no artifact rejection)
  • classes:
    • if true (default), the .trials field of the EEG structure is filled with the trials for all classes
    • If it is a vector of class labels (for example, classes=["left_hand", "right_hand"]), only the trials with those class labels will be stored. The tags corresponding to each class labels will be replaced by natural numbers (1, 2,...) and written in the .stim and y fields of the output — see stimulation vector
    • If false, the field trials of the returned EEG structure will be set to nothing.
  • stdClass:
    • if true (default), a standardization is applied to the class labels, according to predefined conventions to facilitate transfer learning and model training across heterogeneous databases. The standardization applies uniform numerical codes regardless of the original database encoding:
      • MI paradigm: "left_hand" → 1, "right_hand" → 2, "feet" → 3, "rest" → 4, "both_hands" → 5, "tongue" → 6
      • P300 paradigm: "nontarget" → 1, "target" → 2
      • ERP paradigm: not currently supported
    • if false, original class labels and their corresponding numerical values are preserved as found in the database
    The standardization is case-insensitive, but requires correct spelling of class names. When used with classes as a vector of class labels, standardization is applied after class selection. If class labels are already standardized, the original mapping is preserved. Ii is recommended to leave the default setting for stdClass (true) when all relevant classes are available in your database configuration.
  • msg: print in the REPL string msg on exit if it is not empty. By default it is empty.
Resampling

If you use resampling, the new sampling rate will be rounded to the nearest integer.

stim and mark

If the field offset of the NY file is different from zero, the stimulations in stim and markers in mark will be shifted to account for the offset - see stimulation vector. The field .offset will then be reset to zero.

Return an EEG data structure.

See Also readASCII, readgTec, Eegle.ERPs.mark2stim, Eegle.ERPs.stim2mark

Examples

# Using examples data provided by Eegle
o = readNY(EXAMPLE_P300_1)

# filter the data and do artifact-rejection
# by adaptive amplitude thresholding
o = readNY(EXAMPLE_P300_1; bandPass=(1, 24), upperLimit = 1)

# read the whole recording, but store in o.trials the trials 
# only for classes "right_hand" and "feet" (exclude "rest")
o = readNY(EXAMPLE_MI_1; 
        bandPass=(1, 24), 
        upperLimit = 1, 
        classes=["right_hand", "feet"])
source
Eegle.InOut.readgTecFunction
    function readgTec(fileName::AbstractString;
        dataType::Type = Float32,
        writeMetaDataFiles::Bool = true,
        verbose::Bool = true,
        skipFirstSamples::Int = 0,
        chRange::Union{UnitRange, Symbol} = :All)

Read an EEG data file saved in HDF5 format by the g.Tec g.Recorder software.

Arguments

  • fileName: the complete path of the .hdf5 file to be read.

Optional Keyword Arguments

  • dataType: Float32 by default. Can be Float64.
  • writeMetaDataFiles: true by default. All metadata files will be saved as .xml or .txt files, in the same director where filename is with the same name to which a suffix indicating the type of metadata will be appended. If writeMetaDataFiles is true and verbose is true (default), the metadata will be shown in the REPL.
  • skipFirstSamples: if greater than 0 (default), this number of samples at the beginning of the file will not be read.
  • chRange: if a unit range is provided (e.g., 1:10), only this range of channels will be read. All channels are read by default.

Return

The EEG data as a $T×N$ matrix, where $T$ and $N$ denotes the number of samples and channels, respectively.

See Also readASCII, readNY

Examples

xxx

source
Eegle.InOut.readASCIIFunction
(1) function readASCII(fileName::AbstractString; 
        msg::String="")

(2) readASCII(  fileNames::Vector{String}; 
        skip::Vector{Int}=Int[])        

Read EEG data from one file (method 1) or several files (method 2) in LORETA-Key format. The format is a space- or tab-delimited ASCII file, usually with extension .txt, holding a matrix of data with $N$ columns and $T$ rows, denoting the number of channels and samples, respectively.

(1) fileName is the full path to the ASCII file.

  • If kwarg msg is not empty, print msg in the REPL on exit.

(2) fileNames is a vector of the full paths to the ASCII files.

  • If kwarg skip is a vector of indices (integers), skip the files with these indices (empty by default).

Return

(1) The EEG data as a $T×N$ matrix, where $T$ and $N$ denote the number of samples and channels, respectively.

(2) A vector of matrices as in (1).

See Also writeASCII, readgTec, readNY

source
Eegle.InOut.readSensorsFunction
    function readSensors(fileName::String; 
        hasHeader::Bool=true)

Read a list of EEG sensor labels from ASCII file fileName. The file has one sensor label per line.

If hasHeader is true (default), the first line is the number of labels; this is the format of sensors file used by the LORETA-Key software.

As an example, a sensors file looks like this:

3

Fz

Pz

Cz

Examples

sensors = readSensors(fileName)
source
Eegle.InOut.writeASCIIFunction
(1) function writeASCII(X::Matrix{T}, 
                        fileName::String;
        samplesRange::UnitRange = 1:size(X, 1),
        overwrite::Bool = false,
        digits = 6,
        msg::String = "") 
    where T <: Real

(2) function writeASCII(X::Matrix{S}, 
                        fileName::S;
        overwrite::Bool = false,
        msg::S = "") 
    where S <: String

(3) function writeASCII(v::Vector{S}, 
                        fileName::S;
        samplesRange::UnitRange = 1:size(v, 1),
        overwrite::Bool = false,
        oneline::Bool = false,
        msg::S = "")
    where S <: String

(1)

Write a data matrix X into an ASCII text file that can be read by readASCII.

Arguments

  • X: a Julia matrix of real numbers.
  • fileName: the full path of the file to be saved, usually with extension .txt.

Optional Keyword Arguments

  • samplesRange: the unit range of rows of X (samples for ASCII EEG data files) to be written (all samples by default)
  • overwrite: if false (default), return an error if fileName is an existing file
  • digits: the number of decimal digits written for each value. Default: 6
  • msg: print string msg in the REPL on exit if it is not empty (empty by default).

If you need to remove columns of X (channels) before writing, see Eegle.Miscellaneous.remove or removeChannels.

(2)

Write a matrix of strings into an ASCII file.

Arguments

  • X: the matrix of string to be written
  • fileName: as in (1).

Optional Keyword Arguments

  • overwrite and msg: as in (1).

(3)

Write a vector of strings into an ASCII text file.

Arguments

  • v: the vector of string to be written
  • fileName: as in (1).

Optional Keyword Arguments

  • samplesRange: a unit range of elements of v to be written (all elements by default)
  • overwrite and msg: as in (1)
  • oneline:
    • if true, write all elements in the first line, delimiting them by a space
    • if false (default), write one element per line.
End of line

All methods include character "\r\n" (ASCII end of line and carriage return) at the end of each line. Visualizing these files properly by means of a standard text editor may require some care on Linux.

Examples

xxx

source