# 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="