Source code for neurokit2.data.read_acqknowledge

# -*- coding: utf-8 -*-
import os

from collections import Counter

import numpy as np
import pandas as pd

from ..signal import signal_resample


[docs] def read_acqknowledge(filename, sampling_rate="max", resample_method="interpolation", impute_missing=True): """**Read and format a BIOPAC's AcqKnowledge file into a pandas' dataframe** The function outputs both the dataframe and the sampling rate (retrieved from the AcqKnowledge file). Parameters ---------- filename : str Filename (with or without the extension) of a BIOPAC's AcqKnowledge file (e.g., ``"data.acq"``). sampling_rate : int Sampling rate (in Hz, i.e., samples/second). Since an AcqKnowledge file can contain signals recorded at different rates, harmonization is necessary in order to convert it to a DataFrame. Thus, if `sampling_rate` is set to ``max`` (default), will keep the maximum recorded sampling rate and upsample the channels with lower rate if necessary (using the :func:`.signal_resample()` function). If the sampling rate is set to a given value, will resample the signals to the desired value. Note that the value of the sampling rate is outputted along with the data. resample_method : str Method of resampling (see :func:`.signal_resample()`). impute_missing : bool Sometimes, due to connections issues, there are lapses in the recorded signal (short periods without signal). If ``impute_missing`` is ``True``, will automatically fill the signal interruptions using padding. Returns ---------- df : DataFrame The AcqKnowledge file as a pandas dataframe. sampling rate: int The sampling rate at which the data is sampled. See Also -------- .signal_resample Example ---------- .. ipython:: python import neurokit2 as nk # data, sampling_rate = nk.read_acqknowledge('file.acq') """ # Try loading bioread try: import bioread except ImportError: raise ImportError( "NeuroKit error: read_acqknowledge(): the 'bioread' module is required", " for this function to run. ", "Please install it first (`pip install bioread`).", ) # Check filename if ".acq" not in filename: filename += ".acq" if os.path.exists(filename) is False: raise ValueError("NeuroKit error: read_acqknowledge(): couldn't" " find the following file: " + filename) # Read file file = bioread.read(filename) # Get desired frequency if sampling_rate == "max": freq_list = [] for channel in file.named_channels: freq_list.append(file.named_channels[channel].samples_per_second) sampling_rate = np.max(freq_list) # Counter for checking duplicate channel names channel_counter = Counter() # Loop through channels data = {} for channel_num, channel in enumerate(file.channels): signal = np.array(file.channels[channel_num].data) # Fill signal interruptions if impute_missing is True and np.isnan(np.sum(signal)): signal = pd.Series(signal).fillna(method="pad").values # Resample if necessary if file.channels[channel_num].samples_per_second != sampling_rate: signal = signal_resample( signal, sampling_rate=file.channels[channel_num].samples_per_second, desired_sampling_rate=sampling_rate, method=resample_method, ) # If there is a duplicate channel name, append a number if channel_counter[channel.name] == 0: data[channel.name] = signal else: data[f"{channel.name} ({channel_counter[channel.name]})"] = signal channel_counter[channel.name] += 1 # Sanitize lengths lengths = [] for channel in data: lengths += [len(data[channel])] if len(set(lengths)) > 1: # If different lengths length = pd.Series(lengths).mode()[0] # Find most common (target length) for channel in data: if len(data[channel]) > length: data[channel] = data[channel][0:length] if len(data[channel]) < length: data[channel] = np.concatenate( [ data[channel], np.full((length - len(data[channel])), data[channel][-1]), ] ) # Final dataframe df = pd.DataFrame(data) return df, sampling_rate