mutable struct NEURO
header::NeuroAnalyzer.HEADER
history::Vector{String}
markers::DataFrame
locs::DataFrame
time_pts::Vector{Float64}
epoch_time::Vector{Float64}
data::Array{Float64, 3}
endNeuroAnalyzer.NEURO
NeuroAnalyzer functions operate on NeuroAnalyzer objects. The main object is NeuroAnalyzer.NEURO, which holds a single recording of any type (e.g. EEG, MEG or NIRS) together with its metadata.
| Field | Contents |
|---|---|
header |
metadata: subject, recording and experiment (see Header) |
history |
list of the processing steps applied to the object, with their parameters |
markers |
event markers (see Event markers) |
locs |
channel (electrode, magnetometer, gradiometer or optode) locations |
time_pts |
time of each sample (in seconds) from the start of the recording |
epoch_time |
time of each sample (in seconds) within an epoch; negative before the event onset |
data |
the signal: channels × samples × epochs |
A NEURO object is created by importing a recording (e.g. import_edf(), import_fiff(), import_snirf()), by loading a saved object (load_neuro()) or by creating an empty object (create_object()). Objects are saved with save_neuro().
using NeuroAnalyzer
eeg = import_edf("files/eeg/eeg.edf")println("data type: ", datatype(eeg))
println("channels: ", nchannels(eeg))
println("epochs: ", nepochs(eeg))
println("sampling rate: ", sr(eeg), " Hz")
println("duration: ", signal_duration(eeg), " s")data type: eeg
channels: 24
epochs: 1
sampling rate: 256 Hz
duration: 1205.0 s
info() prints a summary of the object:
info(eeg) Data type: EEG
File format: EDF
Source file: files/eeg/eeg.edf
File size [MB]: 14.13
Memory size [MB]: 61.2
Subject: 528004 SIT 52, 20220831-122227-{d589f756-53fc-4f1b-915d-6e3b8c1560ad}
Recording: EEGDigiTrack EEG-1042 (42-channel EEG Amplifier) V0.5 Rev. 41
Recording notes:
Recording date: 31.08.22
Recording time: 12:32:53
Sampling rate (Hz): 256
Signal length [samples]: 308480
Signal length [seconds]: 1205.0
Number of channels: 24
Epochs ID:
Number of epochs: 1
Epoch length [samples]: 308480
Epoch length [seconds]: 1205.0
Reference type: physical
Line frequency: 50 Hz
Markers: no
Channel locations: yes
Number of EEG channels: 19
Channels:
ch label type unit bad
------ --------------- ----------- ------- -------
1 Fp1 EEG μV false
2 Fp2 EEG μV false
3 F3 EEG μV false
4 F4 EEG μV false
5 C3 EEG μV false
6 C4 EEG μV false
7 P3 EEG μV false
8 P4 EEG μV false
9 O1 EEG μV false
10 O2 EEG μV false
11 F7 EEG μV false
12 F8 EEG μV false
13 T3 EEG μV false
14 T4 EEG μV false
15 T5 EEG μV false
16 T6 EEG μV false
17 A1 REF μV false
18 A2 REF μV false
19 Fz EEG μV false
20 Cz EEG μV false
21 Pz EEG μV false
22 EOG1 EOG μV false
23 EOG2 EOG μV false
24 ECG ECG μV false
Header
The header holds the metadata in three dictionaries:
mutable struct HEADER
subject::Dict
recording::Dict
experiment::Dict
endThey are accessed as e.g. eeg.header.recording[:sampling_rate]; for the most common fields there are accessor functions (sr(), labels(), chtypes(), datatype(), channel_order()). header() prints the header.
Subject
| Key | Type | Contents |
|---|---|---|
:id |
String |
subject identifier |
:first_name |
String |
|
:middle_name |
String |
|
:last_name |
String |
|
:handedness |
String |
|
:head_circumference |
Real |
-1 if unknown |
:weight |
Real |
-1 if unknown |
:height |
Real |
-1 if unknown |
Personal data are removed with anonymize().
Recording
Keys common to all data types:
| Key | Type | Contents |
|---|---|---|
:data_type |
String |
e.g. "eeg", "meg", "nirs" (see NeuroAnalyzer.data_types) |
:file_name |
String |
source file |
:file_size_mb |
Real |
source file size in MB |
:file_type |
String |
e.g. "EDF", "BDF", "BrainVision", "FIFF", "SNIRF" |
:recording |
String |
equipment description |
:recording_date |
String |
|
:recording_time |
String |
|
:recording_notes |
String |
|
:label |
Vector{String} |
channel labels, e.g. ["Fp1", "Fp2"] |
:channel_type |
Vector{String} |
channel types, e.g. ["eeg", "eog"] (see NeuroAnalyzer.channel_types) |
:unit |
Vector{String} |
channel units, e.g. ["μV"] (see NeuroAnalyzer.channel_units) |
:channel_order |
Vector{Int64} |
logical order of channels (sorted by type), see Data |
:sampling_rate |
Int64 |
in Hz |
:bad_channel |
Vector{Bool} |
true for channels marked as bad |
:epoch_id |
String |
how the epochs were created, e.g. "length_2s" (not for MEP) |
Additional keys for EEG, sEEG and ECoG:
| Key | Type | Contents |
|---|---|---|
:reference |
String |
e.g. "physical", "AVG" |
:transducers |
Vector{String} |
electrode type per channel |
:prefiltering |
Vector{String} |
hardware filters per channel |
:gain |
Vector{Float64} |
gain per channel |
:line_frequency |
Real |
power line frequency in Hz (default 50) |
Additional keys for MEG:
| Key | Type | Contents |
|---|---|---|
:reference |
String |
|
:prefiltering |
Vector{String} |
hardware filters per channel |
:line_frequency |
Real |
power line frequency in Hz, read from the file (0 if not stored) |
:magnetometers |
Vector{Int64} |
magnetometer channel numbers |
:gradiometers |
Vector{Int64} |
gradiometer channel numbers |
:coil_type |
Vector{String} |
sensor type per channel |
:coil_id |
Vector{Int64} |
FIFF coil type code per channel |
:coil_loc |
Matrix{Float64} |
sensor geometry, channels × 12: position (m) and orientation (FIFF/MNE loc convention) |
:dev_head_t |
Matrix{Float64} |
4 × 4 device → head transform |
:head_origin |
Vector{Float64} |
origin of the head sphere fitted to the digitization points (m) |
:hpi |
Dict{Symbol, Any} |
head position indicator (cHPI) coils: frequencies, positions, coil numbers |
:first_time |
Float64 |
time (s) of the first sample from the start of the acquisition |
:ssp_labels |
Vector{String} |
names of the SSP projectors |
:ssp_channels |
Vector{Bool} |
channels the SSP projectors apply to |
:ssp_data |
Matrix{Float64} |
SSP projection vectors |
:maxshield |
Bool |
true for data recorded with internal active shielding |
:sss, :tsss |
Bool |
true after Maxwell filtering (SSS / tSSS) |
:sss_info |
Dict{Symbol, Any} |
Maxwell filtering parameters (added by maxwell_filter()), including the data rank |
Additional keys for NIRS:
| Key | Type | Contents |
|---|---|---|
:wavelengths |
Vector{Float64} |
wavelengths in nm |
:wavelength_index |
Vector{Int64} |
wavelength (index into :wavelengths) of each nirs_int / nirs_od channel |
:optode_pairs |
Matrix{Int64} |
source and detector number of each channel |
:src_labels |
Vector{String} |
source labels, e.g. ["S1", "S2"] |
:det_labels |
Vector{String} |
detector labels, e.g. ["D1", "D2"] |
:optode_labels |
Vector{String} |
all optode labels (sources and detectors) |
NIRS channel labels combine the source, the detector and the wavelength or signal type, e.g. "S1_D1 760" or "S1_D1 OD".
Additional keys for MEP:
| Key | Type | Contents |
|---|---|---|
:stimulation_intensity |
Vector{Int64} |
stimulation intensity per channel |
:coil_type |
Vector{String} |
stimulation coil |
:stimulation_sample |
Vector{Int64} |
sample of the stimulus |
:markers_pos |
Vector{Int64} |
sample of the positive MEP peak |
:markers_neg |
Vector{Int64} |
sample of the negative MEP peak |
Additional keys for sensors, EDA and TPT:
| Key | Type | Contents |
|---|---|---|
:prefiltering |
Vector{String} |
hardware filters per channel |
Example (EEG):
rec = eeg.header.recording
for k in [:file_type, :recording, :reference, :line_frequency]
println(rpad(string(k), 16), rec[k])
endfile_type EDF
recording EEGDigiTrack EEG-1042 (42-channel EEG Amplifier) V0.5 Rev. 41
reference physical
line_frequency 50
Experiment
| Key | Type | Contents |
|---|---|---|
:name |
String |
experiment name |
:notes |
String |
|
:design |
String |
experimental design |
Event markers
markers is a DataFrame with one row per event:
| Column | Type | Contents |
|---|---|---|
:id |
String |
event identifier |
:start |
Float64 |
event start in seconds |
:length |
Float64 |
event duration in seconds |
:value |
String |
event value or description |
:channel |
Int64 |
channel the event refers to; 0 = all channels |
Markers are added, edited and deleted with add_marker!(), edit_marker!() and delete_marker!(), and exported with export_markers().
Channel locations
locs is a DataFrame with one row per channel:
| Column | Contents |
|---|---|
:label |
channel label |
:loc_radius |
planar radius |
:loc_theta |
planar angle (degrees) |
:loc_x, :loc_y, :loc_z |
Cartesian coordinates (RAS) |
:loc_radius_sph |
spherical radius |
:loc_theta_sph |
spherical azimuth (degrees) |
:loc_phi_sph |
spherical elevation (degrees) |
Locations are loaded with load_locs!() and exported with export_locs(); see Channel locations.
Data
All computations are performed in double precision (64-bit floating point). The signal is stored in data as Array{Float64, 3}: channels × samples × epochs. If epochs are not defined, the whole signal is a single epoch, i.e. there is always at least one epoch:
println("continuous: ", size(eeg.data))
ep = epoch(eeg; ep_len = 2)
println("epoched: ", size(ep.data))continuous: (24, 308480, 1)
epoched: (24, 512, 602)
Because the data are a standard Julia array, they can be processed with any Julia package. to_df() converts an object into a DataFrame (one column per channel, plus time), and export_csv() saves it as CSV.
Channels are stored in the original sequence (physical order). For plotting, channels are grouped by type (logical order: e.g. MEG, EEG, reference, EOG, ECG, EMG, other); the logical order is stored in :channel_order and returned by channel_order().
Other objects
NeuroAnalyzer.DIPOLE holds an equivalent current dipole fitted with dipole_fit(): dipole position(s), moments over time, goodness of fit and the fitted head sphere. Dipoles are plotted with plot_dipole2d() and plot_dipole3d().
Functions
Functions operating on NEURO objects take the object(s) as positional arguments and all other arguments as keyword arguments, e.g. delete_epoch!(eeg; ep = 12). Multiple dispatch is used wherever possible.
Most edit and process functions have a mutator variant (e.g. delete_epoch() and delete_epoch!()). Mutators modify the input object in place: delete_channel!(eeg; ch = "Fp1") instead of eeg = delete_channel(eeg; ch = "Fp1"). Functions without ! return a new object and leave the input unchanged.
Channels are selected with the ch keyword, by label (ch = "C4"), by several labels (ch = ["Fp1", "Fp2"]), by type (ch = "eeg", ch = ["eeg", "eog"]), with a regular expression (ch = r"^F"), or as ch = "all" or ch = "bad". See the Glossary.
Functions whose names start with _ (e.g. NeuroAnalyzer._band_power()) are private: they work on plain vectors and arrays, are used internally by the public functions, and may change without notice.