Пример #1
0
    def get_data(self) -> pd.DataFrame:
        from eegnb.devices.utils import create_stim_array

        data = self.board.get_board_data()  # will clear board buffer

        # transform data for saving
        data = data.T  # transpose data
        print(data)

        # get the channel names for EEG data
        if self.brainflow_id == BoardIds.GANGLION_BOARD.value:
            # if a ganglion is used, use recommended default EEG channel names
            ch_names = ["fp1", "fp2", "tp7", "tp8"]
        else:
            # otherwise select eeg channel names via brainflow API
            ch_names = BoardShim.get_eeg_names(self.brainflow_id)

        # pull EEG channel data via brainflow API
        eeg_data = data[:, BoardShim.get_eeg_channels(self.brainflow_id)]
        timestamps = data[:,
                          BoardShim.get_timestamp_channel(self.brainflow_id)]

        # Create a column for the stimuli to append to the EEG data
        stim_array = create_stim_array(timestamps, self.markers)
        timestamps = timestamps[
            ..., None]  # Add an additional dimension so that shapes match
        total_data = np.append(timestamps, eeg_data, 1)
        total_data = np.append(total_data, stim_array,
                               1)  # Append the stim array to data.

        # Subtract five seconds of settling time from beginning
        # total_data = total_data[5 * self.sfreq :]
        df = pd.DataFrame(total_data,
                          columns=["timestamps"] + ch_names + ["stim"])
        return df
Пример #2
0
    def _stop_brainflow(self):
        """This functions kills the brainflow backend and saves the data to a CSV file."""

        # Collect session data and kill session
        data = self.board.get_board_data()  # will clear board buffer
        self.board.stop_stream()
        self.board.release_session()

        # transform data for saving
        data = data.T  # transpose data

        # get the channel names for EEG data
        if self.brainflow_id == BoardIds.GANGLION_BOARD.value:
            # if a ganglion is used, use recommended default EEG channel names
            ch_names = ['fp1', 'fp2', 'tp7', 'tp8']
        else:
            # otherwise select eeg channel names via brainflow API
            ch_names = BoardShim.get_eeg_names(self.brainflow_id)

        # pull EEG channel data via brainflow API
        eeg_data = data[:, BoardShim.get_eeg_channels(self.brainflow_id)]
        timestamps = data[:, BoardShim.get_timestamp_channel(self.brainflow_id)]

        # Create a column for the stimuli to append to the EEG data
        stim_array = create_stim_array(timestamps, self.markers)
        timestamps = timestamps[..., None]  # Add an additional dimension so that shapes match
        total_data = np.append(timestamps, eeg_data, 1)
        total_data = np.append(total_data, stim_array, 1)  # Append the stim array to data.

        # Subtract five seconds of settling time from beginning
        total_data = total_data[5 * self.sfreq:]
        data_df = pd.DataFrame(total_data, columns=['timestamps'] + ch_names + ['stim'])
        data_df.to_csv(self.save_fn, index=False)
Пример #3
0
    def _brainflow_extract(self, data):
        """
        Formats the data returned from brainflow to get
        ch_names; list of channel names
        eeg_data: NDArray of eeg samples
        timestamps: NDArray of timestamps
        """

        # transform data for saving
        data = data.T  # transpose data

        # get the channel names for EEG data
        if (self.brainflow_id == BoardIds.GANGLION_BOARD.value
                or self.brainflow_id == BoardIds.GANGLION_WIFI_BOARD.value):
            # if a ganglion is used, use recommended default EEG channel names
            ch_names = ["fp1", "fp2", "tp7", "tp8"]
        elif self.brainflow_id == BoardIds.FREEEEG32_BOARD.value:
            ch_names = [f"eeg_{i}" for i in range(0, 32)]
        else:
            # otherwise select eeg channel names via brainflow API
            ch_names = BoardShim.get_eeg_names(self.brainflow_id)

        # pull EEG channel data via brainflow API
        eeg_data = data[:, BoardShim.get_eeg_channels(self.brainflow_id)]
        timestamps = data[:,
                          BoardShim.get_timestamp_channel(self.brainflow_id)]

        return ch_names, eeg_data, timestamps
Пример #4
0
 def initialize_eeg(self,
                    board_type='synthetic',
                    connection_method='usb',
                    usb_port=None):
     BoardShim.enable_dev_board_logger()
     self.board_id, self.params = get_board_info(board_type,
                                                 connection_method,
                                                 usb_port)
     self.board = BoardShim(self.board_id, self.params)
     self.board.prepare_session()
Пример #5
0
 def initialize_eeg(self,
                    board_type='synthetic',
                    usb_port=None,
                    ip_addr=None,
                    ip_port=None,
                    serial_num=None):
     BoardShim.enable_dev_board_logger()
     self.board_id, self.params = get_board_info(board_type, usb_port,
                                                 ip_addr, ip_port,
                                                 serial_num)
     self.board = BoardShim(self.board_id, self.params)
     self.board.prepare_session()
Пример #6
0
    def __init__(self, board_id=BoardIds.CYTON_DAISY_BOARD.value, ip_port=6677, serial_port="COM3"):

        # Board params
        self.board_id = board_id
        self.params = BrainFlowInputParams()
        self.params.ip_port = ip_port
        self.params.serial_port = serial_port
        self.board = BoardShim(board_id, self.params)
        self.sfreq = self.board.get_sampling_rate(board_id)
        self.marker_row = self.board.get_marker_channel(self.board_id)
        self.eeg_names = self.board.get_eeg_names(board_id)

        # Features params
        # todo: get as arg
        self.features_params = {'channels': ['C03', 'C04']}
Пример #7
0
def acquire_signals():
    count = 0
    while True:
        with mutex:
            # print("acquisition_phase")
            if count == 0:
                time.sleep(2)
                count += 1
            # else:
                time.sleep(0.5)
            # get_current_board_data does not remove personal_dataset from board internal buffer
            # thus allowing us to acquire overlapped personal_dataset and compute more classification over 1 sec
            data = board.get_current_board_data(250)

            sample = []
            eeg_channels = BoardShim.get_eeg_channels(BoardIds.CYTON_BOARD.value)
            for channel in eeg_channels:
                sample.append(data[channel])

            shared_vars.sample = np.array(sample)

            # print(shared_vars.sample.shape)

            if shared_vars.key == ord("q"):
                break

            # print("sample_acquired")
        time.sleep(0.1)
Пример #8
0
def sample_to_second(sample: int, board_id: int):
    """"
		This function takes a sample number and a board id.
		It returns the seconds that have passed from sample 0 to the given sample,
		based on the sampling frequency of the given board.
	"""

    return sample / BoardShim.get_sampling_rate(board_id)
Пример #9
0
 def initialize_backend(self):
     if self.backend == "brainflow":
         self._init_brainflow()
         self.timestamp_channel = BoardShim.get_timestamp_channel(
             self.brainflow_id)
     elif self.backend == "muselsl":
         self._init_muselsl()
         self._muse_get_recent()  # run this at initialization to get some
Пример #10
0
 def check(self, max_uv_abs=200) -> List[str]:
     data = self.board.get_board_data()  # will clear board buffer
     # print(data)
     channel_names = BoardShim.get_eeg_names(self.brainflow_id)
     # FIXME: _check_samples expects different (Muse) inputs
     checked = _check_samples(data.T, channel_names,
                              max_uv_abs=max_uv_abs)  # type: ignore
     bads = [ch for ch, ok in checked.items() if not ok]
     return bads
Пример #11
0
class freeRecording:
    def __init__(self, activity=None):
        self.board_prepared = False
        self.board_id = None
        self.params = None
        self.board = None
        self._setup_session(activity)

    def initialize_eeg(self,
                       board_type='synthetic',
                       usb_port=None,
                       ip_addr=None,
                       ip_port=None,
                       serial_num=None):
        self.board_id, self.params = get_board_info(board_type, usb_port,
                                                    ip_addr, ip_port,
                                                    serial_num)
        self.board = BoardShim(self.board_id, self.params)
        self.board.prepare_session()
        self.board_prepared = True

    def _setup_session(self, activity):
        if activity == None:
            activity = 'UNLABELLED'

        self.session_name = activity

    def record(self, duration, subject, run):
        if self.board_prepared == False:
            self.board.prepare_session()
            self.board_prepared = True

        print(
            "Beginning EEG Stream; Wait 5 seconds for signal to settle... \n")
        self.board.start_stream()
        sleep(5)

        print(f"Starting recording for {duration} seconds... \n")
        sleep(duration)

        # cleanup the session
        self.board.stop_stream()
        # self.board_prepared = False
        data = self.board.get_board_data()
        data_fn, event_fn = get_fns(subject, run, self.session_name)
        DataFilter.write_file(data, data_fn, 'w')
Пример #12
0
    def __init__(self,
                 board_id: int = BoardIds.CYTON_DAISY_BOARD.value,
                 ip_port: int = 6677,
                 serial_port: Optional[str] = None,
                 headset: str = "avi13"):

        # Board Id and Headset Name
        self.board_id = board_id
        self.headset: str = headset

        # BrainFlowInputParams
        self.params = BrainFlowInputParams()
        self.params.ip_port = ip_port
        self.params.serial_port = serial_port if serial_port is not None else self.find_serial_port(
        )
        self.params.headset = headset
        self.params.board_id = board_id
        self.board = BoardShim(board_id, self.params)

        # Other Params
        self.sfreq = self.board.get_sampling_rate(board_id)
        self.marker_row = self.board.get_marker_channel(self.board_id)
        self.eeg_names = self.get_board_names()
Пример #13
0
def extract_eeg_data(raw_data, board_id: int) -> np.ndarray:
    """
		Given a board id and a 2d array containing retrieved data from board, this method extracts only the eeg data
		into a separate 2d array containing eeg channels as rows and samples as columns.
	"""

    eeg_indexes = BoardShim.get_eeg_channels(board_id)
    eeg_channels = np.empty(shape=(len(eeg_indexes),
                                   len(raw_data[eeg_indexes[0]])),
                            dtype=float)

    eeg_channel_index = 0

    for row in range(len(raw_data)):
        if row in eeg_indexes:
            eeg_channels[eeg_channel_index] = raw_data[row]
            eeg_channel_index += 1

    return eeg_channels
Пример #14
0
class EEG:
    def __init__(
        self,
        device=None,
        serial_port=None,
        serial_num=None,
        mac_addr=None,
        other=None,
        ip_addr=None,
    ):
        """The initialization function takes the name of the EEG device and determines whether or not
        the device belongs to the Muse or Brainflow families and initializes the appropriate backend.

        Parameters:
            device (str): name of eeg device used for reading data.
        """
        # determine if board uses brainflow or muselsl backend
        self.device_name = device
        self.serial_num = serial_num
        self.serial_port = serial_port
        self.mac_address = mac_addr
        self.ip_addr = ip_addr
        self.other = other
        self.backend = self._get_backend(self.device_name)
        self.initialize_backend()

    def initialize_backend(self):
        if self.backend == "brainflow":
            self._init_brainflow()
        elif self.backend == "muselsl":
            self._init_muselsl()

    def _get_backend(self, device_name):
        if device_name in brainflow_devices:
            return "brainflow"
        elif device_name in ["muse2016", "muse2", "museS"]:
            return "muselsl"

    #####################
    #   MUSE functions  #
    #####################
    def _init_muselsl(self):
        # Currently there's nothing we need to do here. However keeping the
        # option open to add things with this init method.
        pass

    def _start_muse(self, duration):

        if sys.platform in ["linux", "linux2", "darwin"]:
            # Look for muses
            self.muses = list_muses()
            # self.muse = muses[0]

            # Start streaming process
            self.stream_process = Process(target=stream,
                                          args=(self.muses[0]["address"], ))
            self.stream_process.start()

        # Create markers stream outlet
        self.muse_StreamInfo = StreamInfo("Markers", "Markers", 1, 0, "int32",
                                          "myuidw43536")
        self.muse_StreamOutlet = StreamOutlet(self.muse_StreamInfo)

        # Start a background process that will stream data from the first available Muse
        print("starting background recording process")
        print("will save to file: %s" % self.save_fn)
        self.recording = Process(target=record, args=(duration, self.save_fn))
        self.recording.start()

        time.sleep(5)

        self.push_sample([99], timestamp=time.time())

    def _stop_muse(self):

        pass

    def _muse_push_sample(self, marker, timestamp):
        self.muse_StreamOutlet.push_sample(marker, timestamp)

    ##########################
    #   BrainFlow functions  #
    ##########################
    def _init_brainflow(self):
        """This function initializes the brainflow backend based on the input device name. It calls
        a utility function to determine the appropriate USB port to use based on the current operating system.
        Additionally, the system allows for passing a serial number in the case that they want to use either
        the BraintBit or the Unicorn EEG devices from the brainflow family.

        Parameters:
             serial_num (str or int): serial number for either the BrainBit or Unicorn devices.
        """
        # Initialize brainflow parameters
        self.brainflow_params = BrainFlowInputParams()

        if self.device_name == "ganglion":
            self.brainflow_id = BoardIds.GANGLION_BOARD.value
            if self.serial_port == None:
                self.brainflow_params.serial_port = get_openbci_usb()
            # set mac address parameter in case
            if self.mac_address is None:
                print(
                    "No MAC address provided, attempting to connect without one"
                )
            else:
                self.brainflow_params.mac_address = self.mac_address

        elif self.device_name == "ganglion_wifi":
            self.brainflow_id = BoardIds.GANGLION_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr
                self.brainflow_params.ip_port = 6677

        elif self.device_name == "cyton":
            self.brainflow_id = BoardIds.CYTON_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "cyton_wifi":
            self.brainflow_id = BoardIds.CYTON_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr
                self.brainflow_params.ip_port = 6677

        elif self.device_name == "cyton_daisy":
            self.brainflow_id = BoardIds.CYTON_DAISY_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "cyton_daisy_wifi":
            self.brainflow_id = BoardIds.CYTON_DAISY_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr

        elif self.device_name == "brainbit":
            self.brainflow_id = BoardIds.BRAINBIT_BOARD.value

        elif self.device_name == "unicorn":
            self.brainflow_id = BoardIds.UNICORN_BOARD.value

        elif self.device_name == "callibri_eeg":
            self.brainflow_id = BoardIds.CALLIBRI_EEG_BOARD.value
            if self.other:
                self.brainflow_params.other_info = str(self.other)

        elif self.device_name == "notion1":
            self.brainflow_id = BoardIds.NOTION_1_BOARD.value

        elif self.device_name == "notion2":
            self.brainflow_id = BoardIds.NOTION_2_BOARD.value

        elif self.device_name == "freeeeg32":
            self.brainflow_id = BoardIds.FREEEEG32_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "synthetic":
            self.brainflow_id = BoardIds.SYNTHETIC_BOARD.value

        # some devices allow for an optional serial number parameter for better connection
        if self.serial_num:
            serial_num = str(self.serial_num)
            self.brainflow_params.serial_number = serial_num

        if self.serial_port:
            serial_port = str(self.serial_port)
            self.brainflow_params.serial_port = serial_port

        # Initialize board_shim
        self.sfreq = BoardShim.get_sampling_rate(self.brainflow_id)
        self.board = BoardShim(self.brainflow_id, self.brainflow_params)
        self.board.prepare_session()

    def _start_brainflow(self):
        self.board.start_stream()
        # wait for signal to settle
        sleep(5)

    def _stop_brainflow(self):
        """This functions kills the brainflow backend and saves the data to a CSV file."""

        # Collect session data and kill session
        data = self.board.get_board_data()  # will clear board buffer
        self.board.stop_stream()
        self.board.release_session()

        # transform data for saving
        data = data.T  # transpose data

        # get the channel names for EEG data
        if (self.brainflow_id == BoardIds.GANGLION_BOARD.value
                or self.brainflow_id == BoardIds.GANGLION_WIFI_BOARD.value):
            # if a ganglion is used, use recommended default EEG channel names
            ch_names = ["fp1", "fp2", "tp7", "tp8"]
        elif (self.brainflow_id == BoardIds.FREEEEG32_BOARD.value):
            ch_names = [f'eeg_{i}' for i in range(0, 32)]
        else:
            # otherwise select eeg channel names via brainflow API
            ch_names = BoardShim.get_eeg_names(self.brainflow_id)

        # pull EEG channel data via brainflow API
        eeg_data = data[:, BoardShim.get_eeg_channels(self.brainflow_id)]
        timestamps = data[:,
                          BoardShim.get_timestamp_channel(self.brainflow_id)]

        # Create a column for the stimuli to append to the EEG data
        stim_array = create_stim_array(timestamps, self.markers)
        timestamps = timestamps[
            ..., None]  # Add an additional dimension so that shapes match
        total_data = np.append(timestamps, eeg_data, 1)
        total_data = np.append(total_data, stim_array,
                               1)  # Append the stim array to data.

        # Subtract five seconds of settling time from beginning
        total_data = total_data[5 * self.sfreq:]
        data_df = pd.DataFrame(total_data,
                               columns=["timestamps"] + ch_names + ["stim"])
        data_df.to_csv(self.save_fn, index=False)

    def _brainflow_push_sample(self, marker):
        last_timestamp = self.board.get_current_board_data(1)[-1][0]
        self.markers.append([marker, last_timestamp])

    def start(self, fn, duration=None):
        """Starts the EEG device based on the defined backend.

        Parameters:
            fn (str): name of the file to save the sessions data to.
        """
        if fn:
            self.save_fn = fn

        if self.backend == "brainflow":  # Start brainflow backend
            self._start_brainflow()
            self.markers = []
        elif self.backend == "muselsl":
            self._start_muse(duration)

    def push_sample(self, marker, timestamp):
        """Universal method for pushing a marker and its timestamp to store alongside the EEG data.

        Parameters:
            marker (int): marker number for the stimuli being presented.
            timestamp (float): timestamp of stimulus onset from time.time() function.
        """
        if self.backend == "brainflow":
            self._brainflow_push_sample(marker=marker)
        elif self.backend == "muselsl":
            self._muse_push_sample(marker=marker, timestamp=timestamp)

    def stop(self):
        if self.backend == "brainflow":
            self._stop_brainflow()
        elif self.backend == "muselsl":
            pass
Пример #15
0
    def _init_brainflow(self):
        """This function initializes the brainflow backend based on the input device name. It calls
        a utility function to determine the appropriate USB port to use based on the current operating system.
        Additionally, the system allows for passing a serial number in the case that they want to use either
        the BraintBit or the Unicorn EEG devices from the brainflow family.

        Parameters:
             serial_num (str or int): serial number for either the BrainBit or Unicorn devices.
        """
        # Initialize brainflow parameters
        self.brainflow_params = BrainFlowInputParams()

        if self.device_name == "ganglion":
            self.brainflow_id = BoardIds.GANGLION_BOARD.value
            if self.serial_port == None:
                self.brainflow_params.serial_port = get_openbci_usb()
            # set mac address parameter in case
            if self.mac_address is None:
                print(
                    "No MAC address provided, attempting to connect without one"
                )
            else:
                self.brainflow_params.mac_address = self.mac_address

        elif self.device_name == "ganglion_wifi":
            self.brainflow_id = BoardIds.GANGLION_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr
                self.brainflow_params.ip_port = 6677

        elif self.device_name == "cyton":
            self.brainflow_id = BoardIds.CYTON_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "cyton_wifi":
            self.brainflow_id = BoardIds.CYTON_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr
                self.brainflow_params.ip_port = 6677

        elif self.device_name == "cyton_daisy":
            self.brainflow_id = BoardIds.CYTON_DAISY_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "cyton_daisy_wifi":
            self.brainflow_id = BoardIds.CYTON_DAISY_WIFI_BOARD.value
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr

        elif self.device_name == "brainbit":
            self.brainflow_id = BoardIds.BRAINBIT_BOARD.value

        elif self.device_name == "unicorn":
            self.brainflow_id = BoardIds.UNICORN_BOARD.value

        elif self.device_name == "callibri_eeg":
            self.brainflow_id = BoardIds.CALLIBRI_EEG_BOARD.value
            if self.other:
                self.brainflow_params.other_info = str(self.other)

        elif self.device_name == "notion1":
            self.brainflow_id = BoardIds.NOTION_1_BOARD.value

        elif self.device_name == "notion2":
            self.brainflow_id = BoardIds.NOTION_2_BOARD.value

        elif self.device_name == "freeeeg32":
            self.brainflow_id = BoardIds.FREEEEG32_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "synthetic":
            self.brainflow_id = BoardIds.SYNTHETIC_BOARD.value

        # some devices allow for an optional serial number parameter for better connection
        if self.serial_num:
            serial_num = str(self.serial_num)
            self.brainflow_params.serial_number = serial_num

        if self.serial_port:
            serial_port = str(self.serial_port)
            self.brainflow_params.serial_port = serial_port

        # Initialize board_shim
        self.sfreq = BoardShim.get_sampling_rate(self.brainflow_id)
        self.board = BoardShim(self.brainflow_id, self.brainflow_params)
        self.board.prepare_session()
Пример #16
0
def main():
    BoardShim.enable_board_logger()
    BoardShim.enable_dev_board_logger()

    params = BrainFlowInputParams()
    # params.serial_port = "COM3"

    board = BoardShim(BoardIds.SYNTHETIC_BOARD.value, params)

    board.log_message(LogLevels.LEVEL_INFO.value, "Preparing session...")

    board.prepare_session()

    board.log_message(LogLevels.LEVEL_INFO.value, "Starting stream...")

    board.start_stream()

    start_time = time.time()

    run_time = 5  # 5 seconds

    board.log_message(LogLevels.LEVEL_INFO.value,
                      "Start time = {}".format(start_time))

    while time.time() - start_time < run_time:
        if board.get_board_data_count() > 0:
            data = board.get_board_data()

            print("Got data, time = {}, data count = {}.".format(
                time.time() - start_time, len(data)))

            # print(data[BoardShim.get_eeg_channels(BoardIds.CYTON_BOARD.value)])

        time.sleep(0.001)

    board.log_message(LogLevels.LEVEL_INFO.value, "Stopping stream...")
    board.stop_stream()
    board.release_session()
Пример #17
0
import numpy as np
import socket
import platform
import serial

from brainflow import BoardShim, BoardIds


# Default channel names for the various brainflow devices.
EEG_CHANNELS = {
    "ganglion": ["fp1", "fp2", "tp7", "tp8"],
    "cyton": BoardShim.get_eeg_names(BoardIds.CYTON_BOARD.value),
    "cyton_daisy": BoardShim.get_eeg_names(BoardIds.CYTON_DAISY_BOARD.value),
    "brainbit": BoardShim.get_eeg_names(BoardIds.BRAINBIT_BOARD.value),
    "unicorn": BoardShim.get_eeg_names(BoardIds.UNICORN_BOARD.value),
    "synthetic": BoardShim.get_eeg_names(BoardIds.SYNTHETIC_BOARD.value),
    "notion1": BoardShim.get_eeg_names(BoardIds.NOTION_1_BOARD.value),
    "notion2": BoardShim.get_eeg_names(BoardIds.NOTION_2_BOARD.value),
}

BRAINFLOW_CHANNELS = {
    "ganglion": [],
    "cyton": EEG_CHANNELS["cyton"] + ["accel_0", "accel_1", "accel_2"],
    "cyton_daisy": EEG_CHANNELS["cyton_daisy"] + ["accel_0", "accel_1", "accel_2"],
    "synthetic": EEG_CHANNELS["synthetic"],
}

EEG_INDICES = {
    "muse2016": [1, 2, 3, 4],
    "muse2": [1, 2, 3, 4],
    "museS": [1, 2, 3, 4],
Пример #18
0
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--serial-port', type=str, help='serial port',
                        required=False, default='/dev/ttyUSB0')

    # if you are on Linux remember to give permission to access the port:
    # sudo chmod 666 /dev/ttyUSB0
    # or change the user group
    # check BrainFlow documentation for Windows configs

    args = parser.parse_args()
    params = BrainFlowInputParams()
    params.serial_port = args.serial_port

    board = BoardShim(BoardIds.CYTON_BOARD.value, params)
    board.prepare_session()

    shared_vars = Shared()
    mutex = threading.Lock()

    board.start_stream()  # use this for default options

    acquisition = threading.Thread(target=acquire_signals)
    acquisition.start()
    computing = threading.Thread(target=compute_signals)
    computing.start()

    acquisition.join()
    computing.join()
    board.stop_stream()
Пример #19
0
class EEG:
    def __init__(self,
                 device=None,
                 serial_port=None,
                 serial_num=None,
                 mac_addr=None):
        """ The initialization function takes the name of the EEG device and determines whether or not
        the device belongs to the Muse or Brainflow families and initializes the appropriate backend.

        Parameters:
            device (str): name of eeg device used for reading data.
        """
        # determine if board uses brainflow or muselsl backend
        self.device_name = device
        self.serial_num = serial_num
        self.serial_port = serial_port
        self.mac_address = mac_addr
        self.backend = self._get_backend(self.device_name)
        self.initialize_backend()

    def initialize_backend(self):
        if self.backend == 'brainflow':
            self._init_brainflow()
        elif self.backend == 'muselsl':
            self._init_muselsl()

    def _get_backend(self, device_name):
        if (device_name in brainflow_devices):
            return 'brainflow'
        elif device_name in ['muse2016', 'muse2']:
            return 'muselsl'

    #####################
    #   MUSE functions  #
    #####################
    def _init_muselsl(self):
        # Currently there's nothing we need to do here. However keeping the
        # option open to add things with this init method.
        pass

    def _start_muse(self, duration):

        if sys.platform in ["linux", "linux2", "darwin"]:
            # Look for muses
            muses = list_muses()
            # self.muse = muses[0]

            # Start streaming process
            self.stream_process = Process(target=stream,
                                          args=(self.muses[0]['address'], ))
            self.stream_process.start()

        # Create markers stream outlet
        self.muse_StreamInfo = StreamInfo('Markers', 'Markers', 1, 0, 'int32',
                                          'myuidw43536')
        self.muse_StreamOutlet = StreamOutlet(self.muse_StreamInfo)

        # Start a background process that will stream data from the first available Muse
        print("starting background recording process")
        print('will save to file: %s' % self.save_fn)
        self.recording = Process(target=record, args=(duration, self.save_fn))
        self.recording.start()

        time.sleep(5)

        self.push_sample([99], timestamp=time.time())

    def _stop_muse(self):

        pass

    def _muse_push_sample(self, marker, timestamp):
        self.muse_StreamOutlet.push_sample(marker, timestamp)

    ##########################
    #   BrainFlow functions  #
    ##########################
    def _init_brainflow(self):
        """ This function initializes the brainflow backend based on the input device name. It calls
        a utility function to determine the appropriate USB port to use based on the current operating system.
        Additionally, the system allows for passing a serial number in the case that they want to use either
        the BraintBit or the Unicorn EEG devices from the brainflow family.

        Parameters:
             serial_num (str or int): serial number for either the BrainBit or Unicorn devices.
        """

        # Initialize brainflow parameters
        self.brainflow_params = BrainFlowInputParams()

        if self.device_name == 'ganglion':
            self.brainflow_id = BoardIds.GANGLION_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()
            # set mac address parameter in case
            if self.mac_address is not None:
                self.brainflow_params.mac_address = self.mac_address
            else:
                print(
                    "No MAC address provided, attempting to connect without one"
                )

        elif self.device_name == 'ganglion_wifi':
            brainflow_id = BoardIds.GANGLION_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip(
            )

        elif self.device_name == 'cyton':
            self.brainflow_id = BoardIds.CYTON_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == 'cyton_wifi':
            self.brainflow_id = BoardIds.CYTON_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip(
            )

        elif self.device_name == 'cyton_daisy':
            self.brainflow_id = BoardIds.CYTON_DAISY_BOARD.value
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == 'cyton_daisy_wifi':
            self.brainflow_id = BoardIds.CYTON_DAISY_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip(
            )

        elif self.device_name == 'brainbit':
            self.brainflow_id = BoardIds.BRAINBIT_BOARD.value

        elif self.device_name == 'unicorn':
            self.brainflow_id = BoardIds.UNICORN_BOARD.value

        elif self.device_name == 'synthetic':
            self.brainflow_id = BoardIds.SYNTHETIC_BOARD.value

        if self.serial_num:
            serial_num = str(self.serial_num)
            self.brainflow_params.other_info = serial_num

        if self.serial_port:
            serial_port = str(self.serial_port)
            self.brainflow_params.serial_port = serial_port

        # Initialize board_shim
        self.sfreq = BoardShim.get_sampling_rate(self.brainflow_id)
        self.board = BoardShim(self.brainflow_id, self.brainflow_params)
        self.board.prepare_session()

    def _start_brainflow(self):
        self.board.start_stream()
        # wait for signal to settle
        sleep(5)

    def _stop_brainflow(self):
        """This functions kills the brainflow backend and saves the data to a CSV file."""

        # Collect session data and kill session
        data = self.board.get_board_data()  # will clear board buffer
        self.board.stop_stream()
        self.board.release_session()

        # transform data for saving
        data = data.T  # transpose data
        ch_names = BRAINFLOW_CHANNELS[self.device_name]
        num_channels = len(ch_names)
        eeg_data = data[:, 1:num_channels + 1]
        timestamps = data[:, -1]

        # Create a column for the stimuli to append to the EEG data
        stim_array = create_stim_array(timestamps, self.markers)
        timestamps = timestamps[
            ..., None]  # Add an additional dimension so that shapes match
        total_data = np.append(timestamps, eeg_data, 1)
        total_data = np.append(total_data, stim_array,
                               1)  # Append the stim array to data.

        # Subtract five seconds of settling time from beginning
        total_data = total_data[5 * self.sfreq:]
        data_df = pd.DataFrame(total_data,
                               columns=['timestamps'] + ch_names + ['stim'])
        data_df.to_csv(self.save_fn, index=False)

    def _brainflow_push_sample(self, marker):
        last_timestamp = self.board.get_current_board_data(1)[-1][0]
        self.markers.append([marker, last_timestamp])

    def start(self, fn, duration=None):
        """ Starts the EEG device based on the defined backend.

        Parameters:
            fn (str): name of the file to save the sessions data to.
        """
        if fn:
            self.save_fn = fn

        if self.backend == 'brainflow':  # Start brainflow backend
            self._start_brainflow()
            self.markers = []
        elif self.backend == 'muselsl':
            self._start_muse(duration)

    def push_sample(self, marker, timestamp):
        """ Universal method for pushing a marker and its timestamp to store alongside the EEG data.

        Parameters:
            marker (int): marker number for the stimuli being presented.
            timestamp (float): timestamp of stimulus onset from time.time() function.
        """
        if self.backend == 'brainflow':
            self._brainflow_push_sample(marker=marker)
        elif self.backend == 'muselsl':
            self._muse_push_sample(marker=marker, timestamp=timestamp)

    def stop(self):
        if self.backend == 'brainflow':
            self._stop_brainflow()
        elif self.backend == 'muselsl':
            pass
Пример #20
0
class EEG:
    """
    A class used to wrap all the communication with the OpenBCI EEG
    ...

    Attributes
    ----------
    board_id : int
        id of the OpenBCI board
    ip_port : int
        port for the board
    serial_port : str
        serial port for the board
    headset : str
        the headset name we use, will be presented in the metadata
    """
    def __init__(self,
                 board_id: int = BoardIds.CYTON_DAISY_BOARD.value,
                 ip_port: int = 6677,
                 serial_port: Optional[str] = None,
                 headset: str = "avi13"):

        # Board Id and Headset Name
        self.board_id = board_id
        self.headset: str = headset

        # BrainFlowInputParams
        self.params = BrainFlowInputParams()
        self.params.ip_port = ip_port
        self.params.serial_port = serial_port if serial_port is not None else self.find_serial_port(
        )
        self.params.headset = headset
        self.params.board_id = board_id
        self.board = BoardShim(board_id, self.params)

        # Other Params
        self.sfreq = self.board.get_sampling_rate(board_id)
        self.marker_row = self.board.get_marker_channel(self.board_id)
        self.eeg_names = self.get_board_names()

    def extract_trials(self, data: NDArray) -> [List[Tuple], List[int]]:
        """
        The method get ndarray and extract the labels and durations from the data.
        :param data: the data from the board.
        :return:
        """

        # Init params
        durations, labels = [], []

        # Get marker indices
        markers_idx = np.where(data[self.marker_row, :] != 0)[0]

        # For each marker
        for idx in markers_idx:

            # Decode the marker
            status, label, _ = self.decode_marker(data[self.marker_row, idx])

            if status == 'start':

                labels.append(label)
                durations.append((idx, ))

            elif status == 'stop':

                durations[-1] += (idx, )

        return durations, labels

    def on(self):
        """Turn EEG On"""
        self.board.prepare_session()
        self.board.start_stream()

    def off(self):
        """Turn EEG Off"""
        self.board.stop_stream()
        self.board.release_session()

    def insert_marker(self, status: str, label: int, index: int):
        """Insert an encoded marker into EEG data"""

        marker = self.encode_marker(status, label, index)  # encode marker
        self.board.insert_marker(marker)  # insert the marker to the stream

        # print(f'Status: { status }, Marker: { marker }')  # debug
        # print(f'Count: { self.board.get_board_data_count() }')  # debug

    def _numpy_to_df(self, board_data: NDArray):
        """
        gets a Brainflow-style matrix and returns a Pandas Dataframe
        :param board_data: NDAarray retrieved from the board
        :returns df: a dataframe with the data
        """
        # create dictionary of <col index,col name> for renaming DF
        eeg_channels = self.board.get_eeg_channels(self.board_id)
        eeg_names = self.board.get_eeg_names(self.board_id)
        timestamp_channel = self.board.get_timestamp_channel(self.board_id)
        acceleration_channels = self.board.get_accel_channels(self.board_id)
        marker_channel = self.board.get_marker_channel(self.board_id)

        column_names = {}
        column_names.update(zip(eeg_channels, eeg_names))
        column_names.update(zip(acceleration_channels, ['X', 'Y', 'Z']))
        column_names.update({
            timestamp_channel: "timestamp",
            marker_channel: "marker"
        })

        df = pd.DataFrame(board_data.T)
        df.rename(columns=column_names)

        # drop unused channels
        df = df[column_names]

        # decode int markers
        df['marker'] = df['marker'].apply(self.decode_marker)
        df[['marker_status', 'marker_label',
            'marker_index']] = pd.DataFrame(df['marker'].tolist(),
                                            index=df.index)
        return df

    def _board_to_mne(self, board_data: NDArray,
                      ch_names: List[str]) -> mne.io.RawArray:
        """
        Convert the ndarray board data to mne object
        :param board_data: raw ndarray from board
        :return:
        """
        eeg_data = board_data / 1000000  # BrainFlow returns uV, convert to V for MNE

        # Creating MNE objects from BrainFlow data arrays
        ch_types = ['eeg'] * len(board_data)
        info = mne.create_info(ch_names=ch_names,
                               sfreq=self.sfreq,
                               ch_types=ch_types)
        raw = mne.io.RawArray(eeg_data, info, verbose=False)

        return raw

    def get_raw_data(self, ch_names: List[str]) -> mne.io.RawArray:
        """
        The method returns dataframe with all the raw data, and empties the buffer

        :param ch_names: list[str] of channels to select
        :return: mne_raw data
        """

        indices = [self.eeg_names.index(ch) for ch in ch_names]

        data = self.board.get_board_data()[indices]

        return self._board_to_mne(data, ch_names)

    def get_features(self,
                     channels: List[str],
                     selected_funcs: List[str],
                     notch: float = 50,
                     low_pass: float = 4,
                     high_pass: float = 50) -> NDArray:
        """
        Returns features of all data since last call to get_board_data method.
        :return features: NDArray of shape (1, n_features)
        """

        # Get the raw data
        data = self.get_raw_data(ch_names=channels)

        # Filter
        data = self.filter_data(data, notch, low_pass, high_pass)

        # Extract features
        features = extract_features(
            data.get_data()[np.newaxis], self.sfreq, selected_funcs,
            {'pow_freq_bands__freq_bands': np.array([8, 10, 12.5, 30])})

        return features

    def clear_board(self):
        """Clear all data from the EEG board"""

        # Get the data and don't save it
        self.board.get_board_data()

    def get_board_data(self) -> NDArray:
        """The method returns the data from board and remove it"""
        return self.board.get_board_data()

    def get_board_names(self) -> List[str]:
        """The method returns the board's channels"""
        if self.headset == "avi13":
            # return ['Fp1', 'Fp2', 'C3', 'C4', 'CP5', 'CP6', 'O1', 'O2', 'FC1', 'FC2', 'Cz', 'T8', 'FC5', 'FC6', 'CP1', 'CP2']
            return [
                'CP2', 'FC2', 'CP6', 'C4', 'C3', 'CP5', 'FC1', 'CP1', 'Cz',
                'FC6', 'T8', 'T7', 'FC5'
            ]
        else:
            return self.board.get_eeg_names(self.board_id)

    def get_board_channels(self, alternative=True) -> List[int]:
        """Get list with the channels locations as list of int"""
        if alternative:
            return self.board.get_eeg_channels(self.board_id)[:-3]
        else:
            return self.board.get_eeg_channels(self.board_id)

    def get_channels_data(self):
        """Get NDArray only with the channels data (without all the markers and other stuff)"""
        return self.board.get_board_data()[self.get_board_channels()]

    def find_serial_port(self) -> str:
        """
        Return the string of the serial port to which the FTDI dongle is connected.
        If running in Synthetic mode, return ""
        Example: return "COM5"
        """
        if self.board_id == BoardIds.SYNTHETIC_BOARD:
            return ""
        else:
            plist = serial.tools.list_ports.comports()
            FTDIlist = [
                comport for comport in plist if comport.manufacturer == 'FTDI'
            ]
            if len(FTDIlist) > 1:
                raise LookupError(
                    "More than one FTDI-manufactured device is connected. Please enter serial_port manually."
                )
            if len(FTDIlist) < 1:
                raise LookupError(
                    "FTDI-manufactured device not found. Please check the dongle is connected"
                )
            return FTDIlist[0].name

    @staticmethod
    def filter_data(data: mne.io.RawArray, notch: float, low_pass: float,
                    high_pass: float) -> mne.io.RawArray:

        # data.notch_filter(freqs=notch, verbose=False)
        data.filter(l_freq=low_pass, h_freq=high_pass, verbose=False)

        return data

    @staticmethod
    def encode_marker(status: str, label: int, index: int):
        """
        Encode a marker for the EEG data.
        :param status: status of the stim (start/end)
        :param label: the label of the stim (right -> 0, left -> 1, idle -> 2, tongue -> 3, legs -> 4)
        :param index: index of the current label
        :return:
        """
        markerValue = 0
        if status == "start":
            markerValue += 1
        elif status == "stop":
            markerValue += 2
        else:
            raise ValueError("incorrect status value")

        markerValue += 10 * label

        markerValue += 100 * index

        return markerValue

    @staticmethod
    def decode_marker(marker_value: int) -> (str, int, int):
        """
        Decode the marker and return a tuple with the status, label and index.
        Look for the encoder docs for explanation for each argument in the marker.
        :param marker_value:
        :return:
        """
        if marker_value % 10 == 1:
            status = "start"
            marker_value -= 1
        elif marker_value % 10 == 2:
            status = "stop"
            marker_value -= 2
        else:
            raise ValueError("incorrect status value. Use start or stop.")

        label = ((marker_value % 100) - (marker_value % 10)) / 10

        index = (marker_value - (marker_value % 100)) / 100

        return status, int(label), int(index)

    @staticmethod
    def laplacian(data: NDArray, channels: List[str]):
        """
        The method execute laplacian on the raw data.
        The laplacian was computed as follows:
            1. C3 = C3 - mean(Cz + F3 + P3 + T3)
            2. C4 = C4 - mean(Cz + F4 + P4 + T4)

        The data need to be (n_channel, n_samples)
        :return:
        """

        # Dict with all the indices of the channels
        idx = {ch: channels.index(ch) for ch in channels}

        # C3
        data[idx['C3']] -= (data[idx['Cz']] + data[idx['FC5']] +
                            data[idx['FC1']] + data[idx['CP5']] +
                            data[idx['CP1']]) / 5

        # C4
        data[idx['C4']] -= (data[idx['Cz']] + data[idx['FC2']] +
                            data[idx['FC6']] + data[idx['CP2']] +
                            data[idx['CP6']]) / 5

        return data[[idx['C3'], idx['C4']]]
Пример #21
0
    def run(self):  # 线程执行函数
        params = BrainFlowInputParams()
        board_id = self.board_set[0]
        self.c_value = []

        params.serial_port = self.board_set[1]
        self.board = BoardShim(board_id, params)
        # 在线数据

        #一导联数据和量导联数据

        self.board.prepare_session()
        self.board.start_stream()
        time.sleep(3)
        n = 0
        m = np.zeros(2)
        while self.is_on:

            time.sleep(1)
            data = self.board.get_current_board_data(self.board_set[3])
            data = data[1:9]
            mean_data = np.tile(
                data.mean(axis=1).reshape(8, 1), (1, self.board_set[3]))
            # print(data.shape)
            data = data - mean_data

            if self.puanduan1:
                self.org_signal.emit(data)
            filter1_data = self.processing_step1.step_1_list[
                self.pre_set[0][0]](data, self.pre_set[0])
            filter2_data = self.processing_step2.step_2_list[
                self.pre_set[1][0]](filter1_data, self.pre_set[1])
            if self.puanduan2:
                # print(self.pre_set)
                self.pre_signal.emit(filter2_data)
            feature_data = self.feature.feature_list[self.class_set[0]](
                filter2_data, self.class_set)
            # print(np.argmax(feature_data))
            if self.puanduan3:
                self.feature_signal.emit(feature_data)
                # print(feature_data)
            result = np.argmax(feature_data)

            r = feature_data[result]

            # 更改部分(将程序中2s读取一次改为1s读取一次,每次512采样点改为256采样点)
            if result == 5:
                r = r + 0.1
            elif result == 6:
                r = r + 0.05

            if r > 0.5:
                n = n + 1
                p = result + 1
                print("分类结果:", p, " n = ", n)
                m = np.append(m, p)
                m = m[1:]
                if m[0] == m[1]:
                    m[1] = 0
                else:
                    b = str(p)
                    self.command_signal.emit(b)
                    print("发送指令:", p)
Пример #22
0
class steadyStateEvokedPotentials:
    def __init__(self, paradigm='ssvep'):
        self.paradigm = paradigm
        self.board_id = None
        self.params = None
        self.board = None
        self.max_trials = 500
        self._setup_trials()

    def initialize_eeg(self,
                       board_type='synthetic',
                       usb_port=None,
                       ip_addr=None,
                       ip_port=None,
                       serial_num=None):
        BoardShim.enable_dev_board_logger()
        self.board_id, self.params = get_board_info(board_type, usb_port,
                                                    ip_addr, ip_port,
                                                    serial_num)
        self.board = BoardShim(self.board_id, self.params)
        self.board.prepare_session()

    def _setup_trials(self):
        self.stim_freq = np.random.binomial(1, 0.5, self.max_trials)
        self.trials = DataFrame(
            dict(stim_freq=self.stim_freq,
                 timestamp=np.zeros(self.max_trials)))

    def _setup_graphics(self):
        soa = 3.0
        self.mywin = visual.Window([3440, 1440],
                                   monitor='testMonitor',
                                   units="deg",
                                   wintype='pygame')
        if self.paradigm == 'ssvep':
            grating = visual.GratingStim(win=self.mywin,
                                         mask='circle',
                                         size=80,
                                         sf=0.2)
            grating_neg = visual.GratingStim(win=self.mywin,
                                             mask='circle',
                                             size=80,
                                             sf=0.2,
                                             phase=0.5)
            frame_rate = np.round(self.mywin.getActualFrameRate())
            stim_patterns = [
                init_flicker_stim(frame_rate, 2, soa),
                init_flicker_stim(frame_rate, 3, soa)
            ]
            print(stim_patterns)

        return grating, grating_neg, stim_patterns

    def _load_image(self, fn):
        return visual.ImageStim(win=self.mywin, image=fn)

    def run_trial(self, duration, subject, run):
        # session information
        iti = 0.5
        soa = 3.0
        jitter = 0.2
        record_duration = np.float32(duration)
        print(
            "Beginning EEG Stream; Wait 5 seconds for signal to settle... \n")
        self.board.start_stream()
        sleep(5)

        # Get starting time-stamp by pulling the last sample from the board and using its time stamp
        last_sample = self.board.get_current_board_data(1)
        start = last_sample[-1][0]

        # setup graphics
        grating, grating_neg, stim_patterns = self._setup_graphics()

        # iterate through events
        for ii, trial in self.trials.iterrows():
            # inter trial interval
            core.wait(iti + np.random.rand() * jitter)
            label = self.trials['stim_freq'].iloc[ii]
            last_sample = self.board.get_current_board_data(1)
            timestamp = last_sample[-1][0]
            self.trials.loc[ii, 'timestamp'] = timestamp

            for _ in range(int(stim_patterns[label]['n_cycles'])):
                grating.setAutoDraw(True)
                for _ in range(int(stim_patterns[label]['cycle'][0])):
                    self.mywin.flip()
                grating.setAutoDraw(False)
                grating_neg.setAutoDraw(True)
                for _ in range(stim_patterns[label]['cycle'][1]):
                    self.mywin.flip()
                grating_neg.setAutoDraw(False)

            # Offset
            self.mywin.flip()
            if len(event.getKeys()) > 0 or (time() - start) > record_duration:
                break

            event.clearEvents()

        # cleanup the session
        self.board.stop_stream()
        data = self.board.get_board_data()
        data_fn, event_fn = get_fns(subject, run, self.paradigm)
        print(event_fn)
        DataFilter.write_file(data, data_fn, 'w')
        self.mywin.close()
        self.trials.to_csv(event_fn)
Пример #23
0
import numpy as np
import socket
import platform

from brainflow import BoardShim, BoardIds

# Default channel names for the various brainflow devices.
EEG_CHANNELS = {
    'ganglion': ['fp1', 'fp2', 'tp7', 'tp8'],
    'cyton': BoardShim.get_eeg_names(BoardIds.CYTON_BOARD.value),
    'cyton_daisy': BoardShim.get_eeg_names(BoardIds.CYTON_DAISY_BOARD.value),
    'brainbit': BoardShim.get_eeg_names(BoardIds.BRAINBIT_BOARD.value),
    'unicorn': BoardShim.get_eeg_names(BoardIds.UNICORN_BOARD.value),
    'synthetic': BoardShim.get_eeg_names(BoardIds.SYNTHETIC_BOARD.value),
    'notion1': BoardShim.get_eeg_names(BoardIds.NOTION_1_BOARD.value),
    'notion2': BoardShim.get_eeg_names(BoardIds.NOTION_2_BOARD.value),
}

BRAINFLOW_CHANNELS = {
    'ganglion': [],
    'cyton': EEG_CHANNELS['cyton'] + ['accel_0', 'accel_1', 'accel_2'],
    'cyton_daisy':
    EEG_CHANNELS['cyton_daisy'] + ['accel_0', 'accel_1', 'accel_2'],
    'synthetic': EEG_CHANNELS['synthetic'],
}

EEG_INDICES = {
    'muse2016': [1, 2, 3, 4],
    'muse2': [1, 2, 3, 4],
    'museS': [1, 2, 3, 4],
    'ganglion': BoardShim.get_eeg_channels(BoardIds.GANGLION_BOARD.value),
Пример #24
0
    def _init_brainflow(self):
        """ This function initializes the brainflow backend based on the input device name. It calls
        a utility function to determine the appropriate USB port to use based on the current operating system.
        Additionally, the system allows for passing a serial number in the case that they want to use either
        the BraintBit or the Unicorn EEG devices from the brainflow family.

        Parameters:
             serial_num (str or int): serial number for either the BrainBit or Unicorn devices.
        """

        # Initialize brainflow parameters
        self.brainflow_params = BrainFlowInputParams()

        if self.device_name == 'ganglion':
	    self.brainflow_id = BoardIds.GANGLION_BOARD.value
            if self.serial_port == None:
	        self.brainflow_params.serial_port = get_openbci_usb()
            # set mac address parameter in case
            if self.mac_address is not None:
                self.brainflow_params.mac_address = self.mac_address
            else:
                print("No MAC address provided, attempting to connect without one")

        elif self.device_name == 'ganglion_wifi':
            brainflow_id = BoardIds.GANGLION_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip()

        elif self.device_name == 'cyton':
            self.brainflow_id = BoardIds.CYTON_BOARD.value
            if self.serial_port == None: 
            	self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == 'cyton_wifi':
            self.brainflow_id = BoardIds.CYTON_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip()

        elif self.device_name == 'cyton_daisy':
            self.brainflow_id = BoardIds.CYTON_DAISY_BOARD.value
            if self.serial_port == None:
		self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == 'cyton_daisy_wifi':
            self.brainflow_id = BoardIds.CYTON_DAISY_WIFI_BOARD.value
            self.brainflow_params.ip_address, self.brainflow_params.ip_port = get_openbci_ip()

        elif self.device_name == 'brainbit':
            self.brainflow_id = BoardIds.BRAINBIT_BOARD.value

        elif self.device_name == 'unicorn':
            self.brainflow_id = BoardIds.UNICORN_BOARD.value

        elif self.device_name == 'synthetic':
            self.brainflow_id = BoardIds.SYNTHETIC_BOARD.value


        if self.serial_num:
            serial_num = str(self.serial_num)
            self.brainflow_params.other_info = serial_num

        if self.serial_port:
            serial_port=str(self.serial_port)
            self.brainflow_params.serial_port = serial_port


        # Initialize board_shim
        self.sfreq = BoardShim.get_sampling_rate(self.brainflow_id)
        self.board = BoardShim(self.brainflow_id, self.brainflow_params)
        self.board.prepare_session()
Пример #25
0
    def window_size(self):
        """"
			Returns the window size in samples
		"""
        return self.visible_seconds * BoardShim.get_sampling_rate(
            self.board_id)
Пример #26
0
def samples_to_seconds(samples: np.ndarray, board_id: int) -> np.ndarray:
    """"
		Same as sample to second but with an array
	"""
    return samples / BoardShim.get_sampling_rate(board_id)
Пример #27
0
class eventRelatedPotential:
    def __init__(self, erp='n170'):
        self.erp = erp
        self.board_prepared = False
        self.board_id = None
        self.params = None
        self.board = None
        self.max_trials = 500
        self._setup_trial()

    def initialize_eeg(self,
                       board_type='synthetic',
                       usb_port=None,
                       ip_addr=None,
                       ip_port=None,
                       serial_num=None):
        self.board_id, self.params = get_board_info(board_type, usb_port,
                                                    ip_addr, ip_port,
                                                    serial_num)
        self.board = BoardShim(self.board_id, self.params)
        self.board.prepare_session()
        self.board_prepared = True

    def _setup_trial(self):
        if self.erp == 'n170':
            self.image_type = np.random.binomial(1, 0.5, self.max_trials)
        if self.erp == 'p300':
            self.image_type = np.random.binomial(1, 0.5, self.max_trials)

        self.trials = DataFrame(
            dict(image_type=self.image_type,
                 timestamp=np.zeros(self.max_trials)))

    def _setup_task(self):
        if self.erp == 'n170':
            self.markernames = ['houses', 'faces']
            self.markers = [1, 2]
        if self.erp == 'p300':
            self.markernames = ['nontargets', 'targets']
            self.markers = [1, 2]

    def _setup_graphics(self):
        self.mywin = visual.Window([3440, 1440],
                                   monitor='testMonitor',
                                   units="deg")
        if self.erp == 'n170':
            faces = list(
                map(self._load_image, glob('stim/face_house/faces/*_3.jpg')))
            houses = list(
                map(self._load_image, glob('stim/face_house/houses/*.3.jpg')))
            self.stim = [houses, faces]
        if self.erp == 'p300':
            targets = list(
                map(self._load_image, glob('stim/cats_dogs/target-*.jpg')))
            nontargets = list(
                map(self._load_image, glob('stim/cats_dogs/nontarget-*.jpg')))
            self.stim = [nontargets, targets]

    def _load_image(self, fn):
        return visual.ImageStim(win=self.mywin, image=fn)

    def run_trial(self, duration, subject, run):
        if self.board_prepared == False:
            self.board.prepare_session()
            self.board_prepared = True
        # session information
        iti = 0.4
        soa = 0.3
        jitter = 0.2
        record_duration = np.float32(duration)
        print(
            "Beginning EEG Stream; Wait 5 seconds for signal to settle... \n")
        self.board.start_stream()
        sleep(5)

        # Get starting time-stamp by pulling the last sample from the board and using its time stamp
        last_sample = self.board.get_current_board_data(1)
        start = last_sample[-1][0]

        # setup graphics
        self._setup_graphics()

        # iterate through events
        for ii, trial in self.trials.iterrows():
            # inter trial interval
            core.wait(iti + np.random.rand() * jitter)
            label = self.trials['image_type'].iloc[ii]
            image = choice(self.stim[label])
            image.draw()

            last_sample = self.board.get_current_board_data(1)
            timestamp = last_sample[-1][0]
            self.trials.loc[ii, 'timestamp'] = timestamp
            self.mywin.flip()

            # offset (Off-SET!)
            core.wait(soa)
            self.mywin.flip()
            if len(event.getKeys()) > 0 or (time() - start) > record_duration:
                break

            event.clearEvents()

        # cleanup the session
        self.board.stop_stream()
        #self.board_prepared = False
        data = self.board.get_board_data()
        data_fn, event_fn = get_fns(subject, run, self.erp)
        DataFilter.write_file(data, data_fn, 'w')
        self.mywin.close()
        self.trials.to_csv(event_fn)
Пример #28
0
    'cyton': [0, 1, 2, 3, 4, 5, 6, 7],
    'cyton_daisy': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
    'brainbit': [],
}

STIM_INDICES = {
    'muse2016': 5,
    'muse2': 4,
    'cyton': 11,
    'cyton_daisy': 19,
}

SAMPLE_FREQS = {
    'muse2016': 256,
    'muse2': 256,
    'cyton': BoardShim.get_sampling_rate(BoardIds.CYTON_BOARD.value),
    'cyton_daisy':
    BoardShim.get_sampling_rate(BoardIds.CYTON_DAISY_BOARD.value),
}


def get_openbci_ip(address, port):
    """ Gets the default IP address for connecting to the OpenBCI wifi shield but also allows
    users to pass their own values to override the defaults.

    Parameters:
        address (str): ip address
        port (str or int): ip port
    """
    if address == None:
        address = '192.168.4.1'
Пример #29
0
class BrainflowDevice(EEGDevice):
    # list of brainflow devices
    devices: List[str] = [
        "ganglion",
        "ganglion_wifi",
        "cyton",
        "cyton_wifi",
        "cyton_daisy",
        "cyton_daisy_wifi",
        "brainbit",
        "unicorn",
        "synthetic",
        "brainbit",
        "notion1",
        "notion2",
    ]

    def __init__(
        self,
        device_name: str,
        serial_num=None,
        serial_port=None,
        mac_addr=None,
        other=None,
        ip_addr=None,
    ):
        EEGDevice.__init__(self, device_name)
        self.serial_num = serial_num
        self.serial_port = serial_port
        self.mac_address = mac_addr
        self.other = other
        self.ip_addr = ip_addr
        self.markers: List[Tuple[List[int], float]] = []
        self._init_brainflow()

    def start(self,
              filename: str = None,
              duration=None,
              extras: dict = None) -> None:
        self.save_fn = filename

        def record():
            sleep(duration)
            self._stop_brainflow()

        self.board.start_stream()
        if duration:
            logger.info(
                "Starting background recording process, will save to file: %s"
                % self.save_fn)
            self.recording = Process(target=lambda: record())
            self.recording.start()

    def stop(self) -> None:
        self._stop_brainflow()

    def push_sample(self, marker: List[int], timestamp: float):
        last_timestamp = self.board.get_current_board_data(1)[-1][0]
        self.markers.append((marker, last_timestamp))

    def check(self, max_uv_abs=200) -> List[str]:
        data = self.board.get_board_data()  # will clear board buffer
        # print(data)
        channel_names = BoardShim.get_eeg_names(self.brainflow_id)
        # FIXME: _check_samples expects different (Muse) inputs
        checked = _check_samples(data.T, channel_names,
                                 max_uv_abs=max_uv_abs)  # type: ignore
        bads = [ch for ch, ok in checked.items() if not ok]
        return bads

    def _init_brainflow(self) -> None:
        """
        This function initializes the brainflow backend based on the input device name. It calls
        a utility function to determine the appropriate USB port to use based on the current operating system.
        Additionally, the system allows for passing a serial number in the case that they want to use either
        the BrainBit or the Unicorn EEG devices from the brainflow family.

        Parameters:
             serial_num (str or int): serial number for either the BrainBit or Unicorn devices.
        """
        from eegnb.devices.utils import get_openbci_usb

        # Initialize brainflow parameters
        self.brainflow_params = BrainFlowInputParams()

        device_name_to_id = {
            "ganglion": BoardIds.GANGLION_BOARD.value,
            "ganglion_wifi": BoardIds.GANGLION_WIFI_BOARD.value,
            "cyton": BoardIds.CYTON_BOARD.value,
            "cyton_wifi": BoardIds.CYTON_WIFI_BOARD.value,
            "cyton_daisy": BoardIds.CYTON_DAISY_BOARD.value,
            "cyton_daisy_wifi": BoardIds.CYTON_DAISY_WIFI_BOARD.value,
            "brainbit": BoardIds.BRAINBIT_BOARD.value,
            "unicorn": BoardIds.UNICORN_BOARD.value,
            "callibri_eeg": BoardIds.CALLIBRI_EEG_BOARD.value,
            "notion1": BoardIds.NOTION_1_BOARD.value,
            "notion2": BoardIds.NOTION_2_BOARD.value,
            "synthetic": BoardIds.SYNTHETIC_BOARD.value,
        }

        # validate mapping
        assert all(name in device_name_to_id for name in self.devices)

        self.brainflow_id = device_name_to_id[self.device_name]

        if self.device_name == "ganglion":
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()
            # set mac address parameter in case
            if self.mac_address is None:
                logger.info(
                    "No MAC address provided, attempting to connect without one"
                )
            else:
                self.brainflow_params.mac_address = self.mac_address

        elif self.device_name in [
                "ganglion_wifi", "cyton_wifi", "cyton_daisy_wifi"
        ]:
            if self.ip_addr is not None:
                self.brainflow_params.ip_address = self.ip_addr

        elif self.device_name in ["cyton", "cyton_daisy"]:
            if self.serial_port is None:
                self.brainflow_params.serial_port = get_openbci_usb()

        elif self.device_name == "callibri_eeg":
            if self.other:
                self.brainflow_params.other_info = str(self.other)

        # some devices allow for an optional serial number parameter for better connection
        if self.serial_num:
            self.brainflow_params.serial_number = str(self.serial_num)

        if self.serial_port:
            self.brainflow_params.serial_port = str(self.serial_port)

        # Initialize board_shim
        self.sfreq = BoardShim.get_sampling_rate(self.brainflow_id)
        self.board = BoardShim(self.brainflow_id, self.brainflow_params)
        self.board.prepare_session()

    def get_data(self) -> pd.DataFrame:
        from eegnb.devices.utils import create_stim_array

        data = self.board.get_board_data()  # will clear board buffer

        # transform data for saving
        data = data.T  # transpose data
        print(data)

        # get the channel names for EEG data
        if self.brainflow_id == BoardIds.GANGLION_BOARD.value:
            # if a ganglion is used, use recommended default EEG channel names
            ch_names = ["fp1", "fp2", "tp7", "tp8"]
        else:
            # otherwise select eeg channel names via brainflow API
            ch_names = BoardShim.get_eeg_names(self.brainflow_id)

        # pull EEG channel data via brainflow API
        eeg_data = data[:, BoardShim.get_eeg_channels(self.brainflow_id)]
        timestamps = data[:,
                          BoardShim.get_timestamp_channel(self.brainflow_id)]

        # Create a column for the stimuli to append to the EEG data
        stim_array = create_stim_array(timestamps, self.markers)
        timestamps = timestamps[
            ..., None]  # Add an additional dimension so that shapes match
        total_data = np.append(timestamps, eeg_data, 1)
        total_data = np.append(total_data, stim_array,
                               1)  # Append the stim array to data.

        # Subtract five seconds of settling time from beginning
        # total_data = total_data[5 * self.sfreq :]
        df = pd.DataFrame(total_data,
                          columns=["timestamps"] + ch_names + ["stim"])
        return df

    def _save(self) -> None:
        """Saves the data to a CSV file."""
        assert self.save_fn
        df = self.get_data()
        df.to_csv(self.save_fn, index=False)

    def _stop_brainflow(self) -> None:
        """This functions kills the brainflow backend and saves the data to a CSV file."""
        # Collect session data and kill session
        if self.save_fn:
            self._save()
        self.board.stop_stream()
        self.board.release_session()
Пример #30
0
class EEG:

    def __init__(self, board_id=BoardIds.CYTON_DAISY_BOARD.value, ip_port=6677, serial_port="COM3"):

        # Board params
        self.board_id = board_id
        self.params = BrainFlowInputParams()
        self.params.ip_port = ip_port
        self.params.serial_port = serial_port
        self.board = BoardShim(board_id, self.params)
        self.sfreq = self.board.get_sampling_rate(board_id)
        self.marker_row = self.board.get_marker_channel(self.board_id)
        self.eeg_names = self.board.get_eeg_names(board_id)

        # Features params
        # todo: get as arg
        self.features_params = {'channels': ['C03', 'C04']}

    def extract_trials(self, data: NDArray) -> [List[Tuple], List[int]]:
        """
        The method get ndarray and extract the labels and durations from the data.
        :param data: the data from the board.
        :return:
        """

        # Init params
        durations, labels = [], []

        # Get marker indices
        markers_idx = np.where(data[self.marker_row, :] != 0)[0]

        # For each marker
        for idx in markers_idx:

            # Decode the marker
            status, label, _ = self.decode_marker(data[self.marker_row, idx])

            if status == 'start':

                labels.append(label)
                durations.append((idx,))

            elif status == 'stop':

                durations[-1] += (idx,)

        return durations, labels

    def on(self):
        """Turn EEG On"""
        self.board.prepare_session()
        self.board.start_stream()

    def off(self):
        """Turn EEG Off"""
        self.board.stop_stream()
        self.board.release_session()

    def insert_marker(self, status: str, label: int, index: int):
        """Insert an encoded marker into EEG data"""

        marker = self.encode_marker(status, label, index)  # encode marker
        self.board.insert_marker(marker)  # insert the marker to the stream

        # print(f'Status: { status }, Marker: { marker }')  # debug
        # print(f'Count: { self.board.get_board_data_count() }')  # debug

    def _numpy_to_df(self, board_data: NDArray):
        """
        gets a Brainflow-style matrix and returns a Pandas Dataframe
        :param board_data: NDAarray retrieved from the board
        :returns df: a dataframe with the data
        """
        # create dictionary of <col index,col name> for renaming DF
        eeg_channels = self.board.get_eeg_channels(self.board_id)
        eeg_names = self.board.get_eeg_names(self.board_id)
        timestamp_channel = self.board.get_timestamp_channel(self.board_id)
        acceleration_channels = self.board.get_accel_channels(self.board_id)
        marker_channel = self.board.get_marker_channel(self.board_id)

        column_names = {}
        column_names.update(zip(eeg_channels, eeg_names))
        column_names.update(zip(acceleration_channels, ['X', 'Y', 'Z']))
        column_names.update({timestamp_channel: "timestamp",
                             marker_channel: "marker"})

        df = pd.DataFrame(board_data.T)
        df.rename(columns=column_names)

        # drop unused channels
        df = df[column_names]

        # decode int markers
        df['marker'] = df['marker'].apply(self.decode_marker)
        df[['marker_status', 'marker_label', 'marker_index']] = pd.DataFrame(df['marker'].tolist(), index=df.index)
        return df

    def _board_to_mne(self, board_data: NDArray) -> mne.io.RawArray:
        """
        Convert the ndarray board data to mne object
        :param board_data: raw ndarray from board
        :return:
        """
        eeg_data = board_data / 1000000  # BrainFlow returns uV, convert to V for MNE

        # Creating MNE objects from BrainFlow data arrays
        ch_types = ['eeg'] * len(board_data)
        info = mne.create_info(ch_names=self.eeg_names, sfreq=self.sfreq, ch_types=ch_types)
        raw = mne.io.RawArray(eeg_data, info)

        return raw

    def get_raw_data(self, ch_names: List[str]) -> mne.io.RawArray:
        """
        The method returns dataframe with all the raw data, and empties the buffer

        :param ch_names: list[str] of channels to select
        :return: mne_raw data
        """

        indices = [self.eeg_names.index(ch) for ch in ch_names]

        data = self.board.get_board_data()[indices]

        return self._board_to_mne(data)

    def get_features(self, channels: List[str], selected_funcs: List[str],
                     notch: float = 50, low_pass: float = 4, high_pass: float = 48) -> NDArray:
        """
        Returns features of all data since last call to get_board_data method.
        :return features: NDArray of shape (1, n_features)
        """

        # Get the raw data
        data = self.get_raw_data(ch_names=channels)

        # Filter
        data = self.filter_data(data, notch, low_pass, high_pass)

        # Extract features
        features = extract_features(data.get_data()[0][np.newaxis], self.sfreq, selected_funcs)

        return features

    def clear_board(self):
        """Clear all data from the EEG board"""

        # Get the data and don't save it
        self.board.get_board_data()

    def get_board_data(self) -> NDArray:
        """The method returns the data from board and remove it"""
        return self.board.get_board_data()

    def get_board_names(self) -> List[str]:
        """The method returns the board's channels"""
        return self.board.get_eeg_names(self.board_id)

    def get_board_channels(self) -> List[int]:
        """Get list with the channels locations as list of int"""
        return self.board.get_eeg_channels(self.board_id)

    @staticmethod
    def filter_data(data: mne.io.RawArray,
                    notch: float, low_pass: float, high_pass: float) -> mne.io.RawArray:

        data.notch_filter(freqs=notch)
        data.filter(l_freq=low_pass, h_freq=None)
        data.filter(l_freq=None, h_freq=high_pass)

        return data

    @staticmethod
    def encode_marker(status: str, label: int, index: int):
        """
        Encode a marker for the EEG data.
        :param status: status of the stim (start/end)
        :param label: the label of the stim (right -> 0, left -> 1, idle -> 2)
        :param index: index of the current label
        :return:
        """
        markerValue = 0
        if status == "start":
            markerValue += 1
        elif status == "stop":
            markerValue += 2
        else:
            raise ValueError("incorrect status value")

        markerValue += 10 * label

        markerValue += 100 * index

        return markerValue

    @staticmethod
    def decode_marker(marker_value: int):
        """
        Decode the marker and return a tuple with the status, label and index.
        Look for the encoder docs for explanation for each argument in the marker.
        :param marker_value:
        :return:
        """
        if marker_value % 10 == 1:
            status = "start"
            marker_value -= 1
        elif marker_value % 10 == 2:
            status = "stop"
            marker_value -= 2
        else:
            raise ValueError("incorrect status value")

        label = ((marker_value % 100) - (marker_value % 10)) / 10

        index = (marker_value - (marker_value % 100)) / 100

        return status, int(label), int(index)