Usage
Command Line Interface
Command structure:
explorepy <command> [args]
Get help for a specific command using
explorepy <command> -h
For example to get help about the visualize command, run: explorepy push2lsl -h
Usage: explorepy push2lsl [OPTIONS]
Push data to lsl
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-d, --duration <integer> Streaming duration in seconds
-h, --help Show this message and exit.
Available Commands
acquire
Connects to a device with selected name or address. Only one input is necessary.
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-h, --help Show this message and exit.
Example:
explorepy acquire -n Explore_XXXX # Put your device Bluetooth name
record-data
Connects to a device and records ExG and orientation data into two separate files. In EDF mode, the data is actually recorded in BDF+ format (in 24-bit resolution). Note that in CSV mode there will be two extra files. One for the marker events, and one for the metadata.
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-f, --filename PATH Name of the file. [required]
-ow, --overwrite Overwrite existing file
-d, --duration <integer> Recording duration in seconds
--edf Write in EDF file
--csv Write in csv file (default type)
--imp-mode Enable impedance mode with real-time monitoring (CSV only)
-h, --help Show this message and exit.
Note
If you change your device’s sampling rate or channel mask during recording, explorepy will create a new CSV file for ExG data with the given file name plus the time the setting changed.
Note
You can Explore desktop to generate .set files for EEGLAB export
Note
Because environmental factors, like temperature, can affect your device’s sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and explorepy’s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
If you are setting markers, use CSV. Alternatively, push data to LSL and record with LabRecorder. Avoid EDF files here, as they cannot guarantee precise timing.
Example:
explorepy record-data -n Explore_XXXX -f test_file --edf -ow
push2lsl
Streams data to Lab Streaming Layer (LSL).
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-d, --duration <integer> Streaming duration in seconds
-h, --help Show this message and exit.
Example:
explorepy push2lsl -n Explore_XXXX
bin2csv
Takes a binary file and converts it to four CSV files (ExG, orientation, marker files and metadata).
Options:
-f, --filename PATH Name of (and path to) the binary file. [required]
-ow, --overwrite Overwrite existing file
-h, --help Show this message and exit.
Note
If you change your device’s sampling rate or channel mask during recording, explorepy will create a new CSV file for ExG data with the given file name plus the time the setting changed.
Example:
explorepy bin2csv -f input_file.BIN
bin2edf
Takes a binary file and converts it to two EDF files (ExG and orientation - markers will be written in ExG file). The data is actually recorded in BDF+ format (in 24-bit resolution).
Options:
-f, --filename PATH Name of (and path to) the binary file. [required]
-ow, --overwrite Overwrite existing file
-h, --help Show this message and exit.
Note
To load EDF files, you can use pyedflib or mne (for mne, you may need to change the file extension to bdf manually) in Python.
EEGLAB’s BIOSIG plugin has problems with some EDF files (see this issue). To resolve this, download a precompiled MATLAB file (mexSLOAD.mex) from BIOSIG here. Documentation is here.
Note
Because environmental factors, like temperature, can affect your device’s sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and explorepy’s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
If you are setting markers, use CSV. Alternatively, push data to LSL and record with LabRecorder. Avoid EDF files here, as they cannot guarantee precise timing.
Example (overwrite):
explorepy bin2edf -f input_file.BIN -ow
format-memory
Formats device memory.
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-h, --help Show this message and exit.
Example:
explorepy format-memory -n Explore_XXXX
set-sampling-rate
Sets a device’s ExG sampling rate. Acceptable values: 250, 500 or 1000 (beta). The default sampling rate is 250 Hz.
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-sr, --sampling-rate [250 | 500 | 1000]
Sampling rate of ExG channels, it can be 250,
500 or 1000 [required]
-h, --help Show this message and exit.
Example:
explorepy set-sampling-rate -n Explore_XXXX -sr 500
soft-reset
Soft resets a device. All settings (e.g. sampling rate, channel mask) return to default.
Options:
-a, --address TEXT Explore device's MAC address
-n, --name TEXT Name of the device
-h, --help Show this message and exit.
All commands:
To see the full list of commands
explorepy -h
Creating a Python project
To use explorepy in a Python project:
import explorepy
Note
Because explorepy uses multithreading, running Python scripts in some consoles, such as Ipython’s or Spyder’s, can cause strange behaviours.
Note
For an example project using explorepy, see this folder on GitHub.
Initialization
Before starting a session, ensure your device is paired to your computer. The device will display under the following: Explore_XXXX.
Be sure to initialize the Bluetooth connection before streaming:
explore = explorepy.Explore()
explore.connect(device_name="Explore_XXXX") # Put your device Bluetooth name
Alternatively, use your device’s MAC address.
explore.connect(mac_address="XX:XX:XX:XX:XX:XX")
If the device cannot be found, you will receive an error.
Streaming
After connecting to the device, you will be able to stream and print data to the console.
explore.acquire()
Recording
You can record data in realtime to EDF (BDF+) or CSV files using:
explore.record_data(file_name='test', duration=120, file_type='csv')
This will record data in three separate files: “test_ExG.csv”, “test_ORN.csv” and “test_marker.csv”, which contain ExG data, orientation data (accelerometer, gyroscope, magnetometer) and event markers respectively. It is also possible to add arguments to overwrite files.
Enable imp_mode argument to record impedance data as well:
explore.record_data(file_name='test', duration=120, file_type='csv', imp_mode=True)
Note
Impedance recording is only supported for CSV files!
Note
To load EDF files, you can use pyedflib or mne (for mne, you may need to change the file extension to bdf manually) in Python.
EEGLAB’s BIOSIG plugin has problems with some EDF files (see this issue). To resolve this, download a precompiled MATLAB file (mexSLOAD.mex) from BIOSIG here. Documentation is here.
Note
Because environmental factors, like temperature, can affect your device’s sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and explorepy’s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
If you are setting markers, use CSV. Alternatively, push data to LSL and record with LabRecorder. Avoid EDF, as it cannot guarantee precise timing.
Lab Streaming Layer (lsl)
You can push data to LSL using:
explore.push2lsl()
LSL allows you to stream data from your Explore device and third-parties, like OpenVibe or MATLAB, simultaneously. (See the LabStreaming Layer docs and OpenVibe docs for more).
push2lsl creates three LSL streams; one for each of ExG data, orientation data and marker events. If your device loses connection, explorepy will try to reconnect automatically.
Converter
It is possible to extract BIN files from a device via USB. To convert these binary files to CSV, use bin2csv. This function will create two CSV files (one for orientation, the other one for ExG data). A Bluetooth connection is not needed for this.
explore.convert_bin(bin_file='DATA001.BIN', file_type='csv', do_overwrite=False)
Note
If you change your device’s sampling rate or channel mask during recording, explorepy will create a new CSV file for ExG data with the given file name plus the time the setting changed.
Note
Because environmental factors, like temperature, can affect your device’s sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and explorepy’s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
If you are setting markers, use CSV. Alternatively, push data to LSL and record with LabRecorder. Avoid EDF, as it cannot guarantee precise timing.
Event markers
Event markers can be used to time synch data. The following table describes all types of event markers available for Explore device.
Type |
Code range |
Label in recordings |
|---|---|---|
Push button |
0-7 |
pb_<CODE> |
Software marker |
Any string between 1 and 7 characters |
sw_<marker_text> |
Trigger-in |
Only 0 |
in_0 |
In order to set markers programmatically, use:
explore.set_marker(code='marker_1')
A simple example of software markers used in a script can be found here.
Device configuration
You can programmatically change a device’s settings.
To change a device’s sampling rate:
explore.set_sampling_rate(sampling_rate=500)
To format a device’s memory:
explore.format_memory()
To reset a device’s settings:
explore.reset_soft()
Sensor data acquisition in real-time
"""An example code for data acquisition from Explore device
import time
import explorepy
from explorepy.stream_processor import TOPICS
import argparse
def my_exg_function(packet):
"""A function that receives ExG packets and does some operations on the data"""
t_vector, exg_data = packet.get_data()
print("Received an ExG packet with data shape: ", exg_data.shape)
#############
# YOUR CODE #
#############
def my_env_function(packet):
"""A function that receives env packets(temperature, light, battery) and does some operations on the data"""
print("Received an environment packet: ", packet)
#############
# YOUR CODE #
#############
def my_orn_function(packet):
"""A function that receives orientation packets and does some operations on the data"""
timestamp, orn_data = packet.get_data()
print("Received an orientation packet: ", orn_data)
#############
# YOUR CODE #
#############
def main():
parser = argparse.ArgumentParser(description="Example code for data acquisition")
parser.add_argument("-n", "--name", dest="name", type=str, help="Name of the device.")
args = parser.parse_args()
# Create an Explore object
exp_device = explorepy.Explore()
# Connect to the Explore device using device bluetooth name or mac address
exp_device.connect(device_name=args.name)
# Subscribe your function to the stream publisher
exp_device.stream_processor.subscribe(callback=my_exg_function, topic=TOPICS.raw_ExG)
exp_device.stream_processor.subscribe(callback=my_orn_function, topic=TOPICS.raw_orn)
exp_device.stream_processor.subscribe(callback=my_env_function, topic=TOPICS.env)
try:
while True:
time.sleep(.5)
except KeyboardInterrupt:
return
if __name__ == "__main__":
main()
"""
Impedance data acquisition in real-time
import argparse
import csv
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import signal
import explorepy
from explorepy.stream_processor import TOPICS
# ----------------------------- Argument Parsing ----------------------------- #
parser = argparse.ArgumentParser(description="Acquire and filter impedance-mode ExG data from an Explore device.")
parser.add_argument("--device-name", required=True, help="Name of the Explore device (e.g., Explore_AAXX)")
args = parser.parse_args()
# ----------------------------- Configuration ----------------------------- #
FS = 250 # Sampling rate in Hz
CHANNEL_LABELS = [f"ch{i}" for i in range(1, 33)]
OUTPUT_FILENAME = "exg_data_imp_mode.csv"
RECORD_SECONDS = 40
# ----------------------------- CSV Setup ----------------------------- #
csv_file = open(OUTPUT_FILENAME, 'w', newline='\n')
csv_writer = csv.writer(csv_file, delimiter=",")
csv_writer.writerow(['Timestamp'] + CHANNEL_LABELS[:8]) # Log only first 8 channels
# ----------------------------- Packet Handlers ----------------------------- #
def handle_exg_packet(packet):
"""Callback to handle incoming ExG data packets."""
timestamps, signals = packet.get_data(FS)
data = np.concatenate((np.array(timestamps)[:, np.newaxis].T, np.array(signals)), axis=0)
np.savetxt(csv_file, np.round(data.T, 4), fmt='%4f', delimiter=',')
def handle_impedance_packet(packet):
"""Callback to handle incoming impedance packets."""
impedance_values = packet.get_impedances()
print("Impedance:", impedance_values)
# ----------------------------- Device Initialization ----------------------------- #
device = explorepy.Explore()
device.connect(args.device_name)
device.stream_processor.subscribe(callback=handle_impedance_packet, topic=TOPICS.imp)
device.stream_processor.subscribe(callback=handle_exg_packet, topic=TOPICS.raw_ExG)
device.stream_processor.imp_initialize(notch_freq=50)
# ----------------------------- Data Acquisition Loop ----------------------------- #
for _ in range(RECORD_SECONDS):
time.sleep(1)
# ----------------------------- Cleanup ----------------------------- #
device.stream_processor.disable_imp()
device.stream_processor.unsubscribe(callback=handle_impedance_packet, topic=TOPICS.imp)
device.stream_processor.unsubscribe(callback=handle_exg_packet, topic=TOPICS.raw_ExG)
csv_file.close()
# ----------------------------- Signal Processing ----------------------------- #
def apply_bandpass_filter(signal_data, low_freq, high_freq, fs, order=3):
"""Apply a Butterworth bandpass filter to the signal."""
b, a = signal.butter(order, [low_freq / fs, high_freq / fs], btype='bandpass')
return signal.filtfilt(b, a, signal_data)
def apply_notch_filter(signal_data, fs, freq=50, quality_factor=30.0):
"""Apply a notch filter at the specified frequency."""
b, a = signal.iirnotch(freq, quality_factor, fs)
return signal.filtfilt(b, a, signal_data)
# ----------------------------- Load and Filter Data ----------------------------- #
df = pd.read_csv(OUTPUT_FILENAME, delimiter=',', dtype=np.float64)
raw_ch1 = df['ch1']
filtered = apply_notch_filter(raw_ch1, FS, freq=62.5)
filtered = apply_notch_filter(filtered, FS, freq=50)
filtered = apply_bandpass_filter(filtered, low_freq=0.5, high_freq=30, fs=FS)
# ----------------------------- Plot Filtered Signal ----------------------------- #
plt.figure(figsize=(10, 4))
plt.plot(df['Timestamp'], filtered, label='Filtered ch1')
plt.xlabel("Time (s)")
plt.ylabel("Amplitude (µV)")
plt.title("Filtered EEG Signal - Channel 1")
plt.grid(True)
plt.tight_layout()
plt.show()