initial commit
This commit is contained in:
7
mne/io/nicolet/__init__.py
Normal file
7
mne/io/nicolet/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
"""Nicolet module for conversion to FIF."""
|
||||
|
||||
# Authors: The MNE-Python contributors.
|
||||
# License: BSD-3-Clause
|
||||
# Copyright the MNE-Python contributors.
|
||||
|
||||
from .nicolet import read_raw_nicolet
|
||||
201
mne/io/nicolet/nicolet.py
Normal file
201
mne/io/nicolet/nicolet.py
Normal file
@@ -0,0 +1,201 @@
|
||||
# Authors: The MNE-Python contributors.
|
||||
# License: BSD-3-Clause
|
||||
# Copyright the MNE-Python contributors.
|
||||
|
||||
import calendar
|
||||
import datetime
|
||||
from os import path
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..._fiff.constants import FIFF
|
||||
from ..._fiff.meas_info import _empty_info
|
||||
from ..._fiff.utils import _create_chs, _find_channels, _read_segments_file
|
||||
from ...utils import fill_doc, logger
|
||||
from ..base import BaseRaw
|
||||
|
||||
|
||||
@fill_doc
|
||||
def read_raw_nicolet(
|
||||
input_fname, ch_type, eog=(), ecg=(), emg=(), misc=(), preload=False, verbose=None
|
||||
) -> "RawNicolet":
|
||||
"""Read Nicolet data as raw object.
|
||||
|
||||
..note:: This reader takes data files with the extension ``.data`` as an
|
||||
input. The header file with the same file name stem and an
|
||||
extension ``.head`` is expected to be found in the same
|
||||
directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_fname : path-like
|
||||
Path to the data file (ending with ``.data`` not ``.head``).
|
||||
ch_type : str
|
||||
Channel type to designate to the data channels. Supported data types
|
||||
include ``'eeg'``, ``'dbs'``.
|
||||
eog : list | tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
EOG channels. If ``'auto'``, the channel names beginning with
|
||||
``EOG`` are used. Defaults to empty tuple.
|
||||
ecg : list or tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
ECG channels. If ``'auto'``, the channel names beginning with
|
||||
``ECG`` are used. Defaults to empty tuple.
|
||||
emg : list or tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
EMG channels. If ``'auto'``, the channel names beginning with
|
||||
``EMG`` are used. Defaults to empty tuple.
|
||||
misc : list or tuple
|
||||
Names of channels or list of indices that should be designated
|
||||
MISC channels. Defaults to empty tuple.
|
||||
%(preload)s
|
||||
%(verbose)s
|
||||
|
||||
Returns
|
||||
-------
|
||||
raw : instance of Raw
|
||||
A Raw object containing the data.
|
||||
|
||||
See Also
|
||||
--------
|
||||
mne.io.Raw : Documentation of attributes and methods.
|
||||
"""
|
||||
return RawNicolet(
|
||||
input_fname,
|
||||
ch_type,
|
||||
eog=eog,
|
||||
ecg=ecg,
|
||||
emg=emg,
|
||||
misc=misc,
|
||||
preload=preload,
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
|
||||
def _get_nicolet_info(fname, ch_type, eog, ecg, emg, misc):
|
||||
"""Extract info from Nicolet header files."""
|
||||
fname, extension = path.splitext(fname)
|
||||
|
||||
if extension != ".data":
|
||||
raise ValueError(f'File name should end with .data not "{extension}".')
|
||||
|
||||
header = fname + ".head"
|
||||
|
||||
logger.info("Reading header...")
|
||||
header_info = dict()
|
||||
with open(header) as fid:
|
||||
for line in fid:
|
||||
var, value = line.split("=")
|
||||
if var == "elec_names":
|
||||
value = value[1:-2].split(",") # strip brackets
|
||||
elif var == "conversion_factor":
|
||||
value = float(value)
|
||||
elif var in ["num_channels", "rec_id", "adm_id", "pat_id", "num_samples"]:
|
||||
value = int(value)
|
||||
elif var != "start_ts":
|
||||
value = float(value)
|
||||
header_info[var] = value
|
||||
|
||||
ch_names = header_info["elec_names"]
|
||||
if eog == "auto":
|
||||
eog = _find_channels(ch_names, "EOG")
|
||||
if ecg == "auto":
|
||||
ecg = _find_channels(ch_names, "ECG")
|
||||
if emg == "auto":
|
||||
emg = _find_channels(ch_names, "EMG")
|
||||
|
||||
date, time = header_info["start_ts"].split()
|
||||
date = date.split("-")
|
||||
time = time.split(":")
|
||||
sec, msec = time[2].split(".")
|
||||
date = datetime.datetime(
|
||||
int(date[0]),
|
||||
int(date[1]),
|
||||
int(date[2]),
|
||||
int(time[0]),
|
||||
int(time[1]),
|
||||
int(sec),
|
||||
int(msec),
|
||||
)
|
||||
info = _empty_info(header_info["sample_freq"])
|
||||
info["meas_date"] = (calendar.timegm(date.utctimetuple()), 0)
|
||||
|
||||
if ch_type == "eeg":
|
||||
ch_coil = FIFF.FIFFV_COIL_EEG
|
||||
ch_kind = FIFF.FIFFV_EEG_CH
|
||||
elif ch_type == "seeg":
|
||||
ch_coil = FIFF.FIFFV_COIL_EEG
|
||||
ch_kind = FIFF.FIFFV_SEEG_CH
|
||||
else:
|
||||
raise TypeError(
|
||||
"Channel type not recognized. Available types are 'eeg' and 'seeg'."
|
||||
)
|
||||
cals = np.repeat(header_info["conversion_factor"] * 1e-6, len(ch_names))
|
||||
info["chs"] = _create_chs(ch_names, cals, ch_coil, ch_kind, eog, ecg, emg, misc)
|
||||
info["highpass"] = 0.0
|
||||
info["lowpass"] = info["sfreq"] / 2.0
|
||||
info._unlocked = False
|
||||
info._update_redundant()
|
||||
return info, header_info
|
||||
|
||||
|
||||
class RawNicolet(BaseRaw):
|
||||
"""Raw object from Nicolet file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_fname : path-like
|
||||
Path to the Nicolet file.
|
||||
ch_type : str
|
||||
Channel type to designate to the data channels. Supported data types
|
||||
include ``'eeg'``, ``'seeg'``.
|
||||
eog : list | tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
EOG channels. If ``'auto'``, the channel names beginning with
|
||||
``EOG`` are used. Defaults to empty tuple.
|
||||
ecg : list or tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
ECG channels. If ``'auto'``, the channel names beginning with
|
||||
``ECG`` are used. Defaults to empty tuple.
|
||||
emg : list or tuple | ``'auto'``
|
||||
Names of channels or list of indices that should be designated
|
||||
EMG channels. If ``'auto'``, the channel names beginning with
|
||||
``EMG`` are used. Defaults to empty tuple.
|
||||
misc : list or tuple
|
||||
Names of channels or list of indices that should be designated
|
||||
MISC channels. Defaults to empty tuple.
|
||||
%(preload)s
|
||||
%(verbose)s
|
||||
|
||||
See Also
|
||||
--------
|
||||
mne.io.Raw : Documentation of attributes and methods.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_fname,
|
||||
ch_type,
|
||||
eog=(),
|
||||
ecg=(),
|
||||
emg=(),
|
||||
misc=(),
|
||||
preload=False,
|
||||
verbose=None,
|
||||
):
|
||||
input_fname = path.abspath(input_fname)
|
||||
info, header_info = _get_nicolet_info(input_fname, ch_type, eog, ecg, emg, misc)
|
||||
last_samps = [header_info["num_samples"] - 1]
|
||||
super().__init__(
|
||||
info,
|
||||
preload,
|
||||
filenames=[input_fname],
|
||||
raw_extras=[header_info],
|
||||
last_samps=last_samps,
|
||||
orig_format="int",
|
||||
verbose=verbose,
|
||||
)
|
||||
|
||||
def _read_segment_file(self, data, idx, fi, start, stop, cals, mult):
|
||||
"""Read a chunk of raw data."""
|
||||
_read_segments_file(self, data, idx, fi, start, stop, cals, mult, dtype="<i2")
|
||||
Reference in New Issue
Block a user