Summary of Changes:
- Can be a breaking change: Add support for multiple internal buffers
- Add an option to use 5th channel for Muse 2 and Muse S
- Add method
add_streamer
- Update SimpleBLE and Muse stability fixes
- Streaming and Playback boards now get master board id from master_board field. Before it was encoded as a string in other_info field.
What was changed and why?
Some devices have multiple different sensors and do not align data from these sensors. For example Muse S has 4 EEG channels with sampling rate 256, it also has accelerometer and gyroscope sensors with sampling rate around 52 and PPG sensors sampled at 64. And all these types of data are sent from its own BLE characteristics in different time moments. And unfortunately it’s not a unique case, there are other devices like this.
Until this release inside BrainFlow there was a single ring buffer for data packages, so we supported only one data format per device. But such variety of sampling rates and different BLE transactions for different data types make it really complicated to group data together and assemble a single array. We did that until this release but code was much more complicated and I even not sure that it was done 100% correctly. Also, we expect more boards like this in the future(e.g. Emotibit)
To solve the issue above we’ve added support for multiple internal buffers and called them BrainFlowPresets. Possible presets are:
- DEFAULT_PRESET
- AUXILIARY_PRESET
- ANCILLARY_PRESET
For all currently supported devices except Muse boards there is only DEFAULT_PRESET and there are no changes in data format for them. For Muse boards we’ve added EEG data to DEFAULT_PRESET, Accelerometer and Gyroscope data to AUXILIARY_PRESET and PPG data to ANCILLARY_PRESET(PPG not available for Muse 2016, so Muse 2016 has only two presets). Also, each preset has it’s own sampling rate, timestamp and package counter.
But in addition to multiple internal buffers we need an API which allow you to get data from particular buffer, so all methods like:
- get_board_data
- get_current_board_data
- insert_marker
- get_sampling_rate
- get_timestamp_channel
- get_eeg_channels
- get_ppg_channels
- etc
Have an optional argument to specify preset, in majority of languages it’s possible to add default value for function arguments, and we added DEFAULT_PRESET as a default function argument, but not for all bindings it’s possible(e.g Matlab, Rust). So, for these languages it’s a breaking change, because now you need to specify preset manually even if your board has only one preset available.
Let’s take a look at example for Muse S board using Julia programming language.
using BrainFlow
BrainFlow.enable_dev_logger(BrainFlow.BOARD_CONTROLLER)
params = BrainFlowInputParams()
board_shim = BrainFlow.BoardShim(BrainFlow.MUSE_S_BOARD, params)
BrainFlow.prepare_session(board_shim)
BrainFlow.config_board("p50", board_shim) # to enable ppg only use p61, p50 enables aux(5th eeg) channel, ppg and smth else
BrainFlow.start_stream(board_shim)
sleep(10)
BrainFlow.stop_stream(board_shim)
# For default preset you dont need to specify it
data_default = BrainFlow.get_board_data(board_shim) # with eeg data
data_aux = BrainFlow.get_board_data(board_shim, BrainFlow.AUXILIARY_PRESET) # with accel and gyro data
data_anc = BrainFlow.get_board_data(board_shim, BrainFlow.ANCILLARY_PRESET) # with ppg data
BrainFlow.release_session(board_shim)
BrainFlow.write_file(data_default, "default.csv", "w")
BrainFlow.write_file(data_aux, "aux.csv", "w")
BrainFlow.write_file(data_anc, "anc.csv", "w")
If you need only EEG data you can run exactly the same code as for previous version, this will also work just fine.
using BrainFlow
# specify logging library to use
BrainFlow.enable_dev_logger(BrainFlow.BOARD_CONTROLLER)
params = BrainFlowInputParams()
board_shim = BrainFlow.BoardShim(BrainFlow.MUSE_S_BOARD, params)
BrainFlow.prepare_session(board_shim)
BrainFlow.start_stream(board_shim)
sleep(5)
BrainFlow.stop_stream(board_shim)
data = BrainFlow.get_current_board_data(256, board_shim)
BrainFlow.release_session(board_shim)
eeg_channels = BrainFlow.get_eeg_channels(BrainFlow.MUSE_S_BOARD)
eeg_data_first_channel = data[eeg_channels[1], :]
To get accelerometer and ppg data you will need to call something like:
data_aux = BrainFlow.get_board_data(board_shim, BrainFlow.AUXILIARY_PRESET)
accel_channels = BrainFlow.get_accel_channels(BrainFlow.MUSE_S_BOARD, BrainFlow.AUXILIARY_PRESET)
accel_x = data_aux[accel_channels[1], :]
data_anc = BrainFlow.get_board_data(board_shim, BrainFlow.ANCILLARY_PRESET)
ppg_channels = BrainFlow.get_ppg_channels(BrainFlow.MUSE_S_BOARD, BrainFlow.ANCILLARY_PRESET)
first_ppg = data_anc[ppg_channels[1], :]
To get all available presets for your device you can use get_board_presets(int board_id)
or check Supported Boards page.
The primary goal of this change to add support for new types of devices and go beyond EEG headsets.