202 lines
6.4 KiB
Python
202 lines
6.4 KiB
Python
# 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")
|