Data

This module has three data-related functions: (1) Datasets, (2) Offline Data Handling, and (3) Online Data Handling. The dataset functionality has built-in support for downloading and exploring a variety of validated datasets. The OfflineDataHandler is responsible for parsing through previously collected (offline) datasets and preparing data to be passed through the pipeline. Finally, the OnlineDataHandler is responsible for accumulating, storing, and processing real-time data.

Datasets

Several validated datasets consisting of different gestures and recording technology are included in this library. These datasets can be used for exploring the library’s capabilities and for future research. When using the packaged datasets for research purposes, we ask that you reference the original dataset contribution and not just this toolkit (the original dataset contributions might not be obvious since they are included for download with this toolkit).

OneSubjectMyoDataset

Attribute

Description

Num Subjects:

1

Num Reps:

12 Reps (i.e., 6 Trials x 2 Reps)

Time Per Rep:

3s

Classes:

  • 0 - Hand Open
  • 1 - Hand Close
  • 2 - No Movement
  • 3 - Wrist Extension
  • 4 - Wrist Flexion

Device:

Myo

Sampling Rates:

EMG (200 Hz)

Using the Dataset:

from libemg.datasets import OneSubjectMyoDataset
dataset = OneSubjectMyoDataset(redownload=False)
odh = dataset.prepare_data()

References:

Work to be published...


3DCDatset

Attribute

Description

Num Subjects:

22

Num Reps:

4 Training, 4 Testing

Time Per Rep:

5s

Classes:

  • 0 - No Motion
  • 1 - Radial Deviaton
  • 2 - Wrist Flexion
  • 3 - Ulnar Deviaton
  • 4 - Wrist Extension
  • 5 - Supination
  • 6 - Pronation
  • 7 - Power Grip
  • 8- Open Hand
  • 9 - Chuck Grip
  • 10 - Pinch Grip

Device:

Delsys

Sampling Rates:

EMG (1000 Hz)

Using the Dataset:

from libemg.datasets import _3DCDataset
dataset = _3DCDataset(redownload=False)
odh = dataset.prepare_data()

References:

@article{cote2019deep, title={Deep learning for electromyographic hand gesture signal classification using transfer learning}, author={C{^o}t{'e}-Allard, Ulysse and Fall, Cheikh Latyr and Drouin, Alexandre and Campeau-Lecours, Alexandre and Gosselin, Cl{'e}ment and Glette, Kyrre and Laviolette, Fran{\c{c}}ois and Gosselin, Benoit}, journal={IEEE transactions on neural systems and rehabilitation engineering}, volume={27}, number={4}, pages={760--771}, year={2019}, publisher={IEEE} }

@article{cote2020interpreting, title={Interpreting deep learning features for myoelectric control: A comparison with handcrafted features}, author={C{^o}t{'e}-Allard, Ulysse and Campbell, Evan and Phinyomark, Angkoon and Laviolette, Fran{\c{c}}ois and Gosselin, Benoit and Scheme, Erik}, journal={Frontiers in Bioengineering and Biotechnology}, volume={8}, pages={158}, year={2020}, publisher={Frontiers Media SA} }


Nina Pro DB2
The Ninapro DB2 is a dataset that can be used to test how algorithms perform for large gesture sets. The dataset contains 6 repetitions of 50 motion classes (plus optional rest) that were recorded using 12 Delsys Trigno electrodes around the forearm.

Note, this dataset will not be automatically downloaded. To download this dataset, please see Nina DB2. Simply download the ZIPs and place them in a folder and LibEMG will handle the rest. All credit for this dataset should be given to the original authors.


Attribute

Description

Num Subjects:

40

Num Reps:

6

Time Per Rep:

5s

Classes:

50 Nina Pro DB2

Device:

Delsys

Sampling Rates:

EMG (2000 Hz)

Using the Dataset:

from libemg.datasets import NinaproDB2
dataset = NinaproDB2("data/NinaDB2") #The loacation of Nina DB2 is downloaded
odh = dataset.prepare_data()

References:

Atzori, M., Gijsberts, A., Castellini, C. et al.
Electromyography data for non-invasive naturally-controlled robotic hand prostheses.
Sci Data 1, 140053 (2014).
https://doi.org/10.1038/sdata.2014.53


Nina Pro DB8

Note, this dataset will not be automatically downloaded. To download this dataset, please see Nina DB8. Simply download the ZIPs and place them in a folder and LibEMG will handle the rest. All credit for this dataset should be given to the original authors.


Attribute

Description

Num Subjects:

12

Num Reps:

20 Training, 2 Testing

Time Per Rep:

6-9s

Classes:

9 Nina Pro DB8

Device:

Delsys

Sampling Rates:

EMG (1111 Hz)

Using the Dataset:

from libemg.datasets import NinaproDB8
dataset = NinaproDB8("data/NinaDB8") #The loacation of Nina DB8 is downloaded
odh = dataset.prepare_data()

References:

AUTHOR=Krasoulis Agamemnon, Vijayakumar Sethu, Nazarpour Kianoush
TITLE=Effect of User Practice on Prosthetic Finger Control With an Intuitive Myoelectric Decoder
JOURNAL=Frontiers in Neuroscience
VOLUME=13
YEAR=2019
URL=https://www.frontiersin.org/articles/10.3389/fnins.2019.00891
DOI=10.3389/fnins.2019.00891
ISSN=1662-453X


Offline Data Handler

One overhead for most EMG projects is interfacing with a particular dataset since they often have different folder and file structures. LibEMG provides a means to quickly interface datasets so you can focus on using them with minimal setup time. Assuming the files in the dataset are well formatted (i.e., they include all metadata such as rep, class, and subject) and are either .csv or .txt files, the OfflineDataHandler does all accumulation and processing. To do this, LibEMG relies on regular expressions to define a dataset’s file and folder structure. These expressions can be used to create a dictionary that is passed to the OfflineDataHandler. Once the data handler has collected all the files that satisfy the regexes, the dataset can be sliced using the metadata tags (e.g., by rep, subjects, classes, etc.). After extracting the data it is ready to be passed through the rest of the pipeline. The following code snippet exemplifies how to process a dataset with testing/training, rep, and class metadata. In this case the file format is: dataset/train/R_1_C_1_EMG.csv where R is the rep and C is the class.

Example Code
dataset_folder = 'dataset'
sets_values = ["training", "testing"]
sets_regex = make_regex(left_bound = "dataset/", right_bound="/", values = sets_values)
classes_values = ["0","1","2","3","4"]
classes_regex = make_regex(left_bound = "_C_", right_bound="_EMG.csv", values = classes_values)
reps_values = ["0","1","2","3"]
reps_regex = make_regex(left_bound = "R_", right_bound="_C_", values = reps_values)
dic = {
    "sets": sets_values,
    "sets_regex": sets_regex,
    "reps": reps_values,
    "reps_regex": reps_regex,
    "classes": classes_values,
    "classes_regex": classes_regex
}
odh = OfflineDataHandler()
odh.get_data(folder_location=dataset_folder, filename_dic=dic, delimiter=",")

# Extract training data:
train_odh = odh.isolate_data(key="sets", values=[0])
train_windows, train_metadata = train_odh.parse_windows(50,25)

# Extract features
fe = FeatureExtractor()
feature_list = fe.get_feature_list()
training_features = fe.extract_features(feature_list, train_windows)

Online Data Handler

One complication when using EMG devices is the lack of standardization, meaning that interfacing with hardware is a new undertaking for each device. A goal of LibEMG is to abstract these differences and enable a hardware-agnostic framework. Therefore, this module acts as a middle layer for processing real-time data streaming from any device. In this architecture - exemplified in Figure 1 - the OnlineDataHandler reads data from a UDP port, then passes these data to the system. The system then buffers, stores, and processes these data for use within the pipeline. In turn, the UDP Streamer and OnlineDataHandler are mutually independent as they communicate over a pre-specified UDP port. Both run in their processes, so the main thread is never blocked.

alt text

Figure 1: OnlineDataHandler Architecture

The typical setup to read data in real-time from a device is exemplified in the code snipped below. The order in which the OnlineDataHandler and the streamer get created does not matter (as they are independent). However, they must both be initialized before you can do anything with the data.

# Create Online Data Handler - This listens for data
odh = OnlineDataHandler()
odh.start_listening()
# Create UDP Streamer - This streams data
[preferred]_streamer()
# Proceed with the rest of the pipeline...

For more information on the default streamers and creating your own, please reference the Supported Hardware section.