miRPNI: A dataset of intramuscular electromyography from Regenerative Peripheral Nerve Interfaces and residual muscles
收藏资源简介:
miRPNI: A dataset of intramuscular electromyography from regenerative peripheral nerve interfaces (RPNIs) and residual muscles Dataset Contacts: Chinwendu Nwokeabia [cnwoke@umich.edu], Cynthia Chestek [chestek@umich.edu], Deanna Gates [gatesd@umich.edu] Funding: Research reported in this publication was supported by the National Institute of Neurological Disorders and Stroke of the National Institutes of Health under Award Numbers R01NS105132 and T32NS115724.Dataset is licensed under [[https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en|CC BY-NC-SA 4.0]] Ethical Approvals: Approval of all ethical and experimental procedures and protocols was granted by the University of Michigan's Medical School IRB (IRB-MED) under Application No. HUM00124839 and performed in line with the Declaration of Helsinki. This is also described on clinicaltrials.gov under NCT0326040. Conflicts of Interest: P. Cederna and A. Vaskov are employed in leadership roles and hold equity in Blue Arbor Technologies, Inc., a company that makes prosthetic control systems. P. Cederna and C. Chestek are inventors of patents US10314725 and US10779963 that are related to this work. This intellectual property is held by the University of Michigan and has been optioned by Blue Arbor Technologies, Inc. These interests have been reviewed and are managed by the University of Michigan in accordance with its Conflict of Interest policy. OverviewWe collected data from four people with transradial limb loss who had regenerative peripheral nerve interfaces (RPNIs) created on their median, ulnar, and/or radial nerves. Up to 12 bipolar electrodes (Synapse Biomedical, Oberlin OH, USA) were placed in RPNIs and residual muscles (Table 1). Data were collected monthly while participants were enrolled in the study (up to 6.5 years to date). This dataset includes data from up to twelve sessions per participant (42 total) during their study involvement. During each session, participants mirrored a series of hand movements displayed on a computer screen with their phantom limb while intramuscular electromyographic signals (imEMG) were recorded at 30 kHz using a neural processor (Cerberus, Blackrock Microsystems, Salt Lake City, UT, USA). Each movement was repeated up to 5 times. More detailed description of methods used for data collection/generation of can be found in [1]. Data were collected between June 2018 and May 2024 at the University of Michigan, Ann Arbor, MI, United States. Necessary Software: - Access to MATLAB and below packages- Signal Processing Toolbox- Curve Fitting Toolbox- The dataset can also be accessed via python by importing the corresponding .txt files. The below packages are used in the plotting code - json - ggplot (via lets-plot) - numpy - pandas - h5py Data OverviewThere are up to twelve evenly spaced sessions per participant (42 files). Files are named according to the convention:Participant_ Session Number_ EMG.matExample: Participant 1’s data for session 8 is in ‘P1_S8_EMG.mat’A series of scripts are included to interactively explore and plot the data in MATLAB (miRPNI_plot_EMG.m) and in python (plot_emg.ipynb). Conversion from .mat to a pandas DataFrame in python can be done using mat_to_dataframe.ipynb.Data were originally sampled at 30KHz but downsampled for space to 1kHz. The 30kHz data is provided for each participant for the last two sessions available for each participant (Sessions 8 and 9 for P1 and P2, Sessions 11 and 12 for P3 and P4). Data StructureEach .mat data file contains:1. A single struct variable, named miDB, with the following fields, which describe the trial information: Fieldname Description trialID Identification number for an individual trial in a recording session. Included for mapping of EMG data to metadata found in the session’s corresponding metadata files. TaskNumber Specific movement that was completed during a given trial. The name of the corresponding movement task can be found in movements.json TrialNumber Repetition number for the movement completed during a given trial. RestTime Time in trial when movement was not executed (in ms). HoldTime Time in trial when movement was cued (in ms). EMG30k Raw imEMG data sampled at 30,000 Hz. This field is present in two sessions for each participant. EMG1k Raw imEMG data downsampled to 1000Hz. Raw EMG data were band-pass filtered using a 4th order Butterworth filter with a frequency band of 100-499 Hz. Data were notch filtered to remove noise at 60 Hz and its harmonics (i.e., 60, 120, 180, 240, 300, 360, 420, 480 Hz). This processed data is used to populate the following fields in the miDB structure: Fieldname Description EMG30kf Filtered EMG data at 30,000 Hz. This field is present in two sessions for each participant. EMG1kf Filtered EMG data at 1000Hz. MAVs Mean absolute value data calculated on the 30kHz data over 1 ms windows. onset_idx Movement cue start frame based on thresholding. EMG data fields (EMG30k(f)f, EMG1k(f), MAVs) are matrices where each column represents a channel or muscle, and each row is a frame of data. The EMG channel names for each participant are listed in order within each participants metadata file (PX_metadata.json), as well as in miRPNIreadme.docx and here: Channel Number 1 2 3 4 5 6 7 8 9 10 11 12 P1 EPL EDC FPL FDPI Med Uln1 Uln2 FCR P2 FDPI FCR Uln Med EDC EPL FDPS FPL P3 EDC EPL Sup Rad Pro Med2 Med4 FDPS FDPI FPL Med3 Med1 P4 EPL Sup EDC ECRL FCR Pro FDPI FPL Med2 Med1 Uln2 Uln1 Locations for intramuscular EMG electrodes for each participant. FDPI: flexor digitorum profundus index finger; FCR: flexor carpi radialis; Uln (1,2): Ulnar RPNI (1,2); Med (1,2,3,4): Median RPNI (1,2,3,4); EDC: extensor digitorum communis; EPL: extensor pollicis longus; FDPS: flexor digitorum profundus small finger; FPL: flexor pollicis longus; Sup: supinator; ECRL: extensor carpi radialis longus; Pro: pronator; Radial: Radial RPNI 2. A string array, movements, which includes the names and corresponding code number (TaskNumber) for all movements available in the entire dataset. This array is also represented as a .json file called movements.json. The miDB MATLAB structs were additionally converted into tall matrices and exported as a series of .txt files for use when analyzing the data in programs outside of MATLAB. Those .txt files are:- PX_SY_MAVs.txt: an array of MAVs that were calculated for all channels over every available trial- PX_SY_EMG1kHz.txt: the downsampled EMG data for all channels over every available trial. Included in each matrix is a column called MovementCue, a logical variable that shows the nominal rest and cue times described in the miDB fields RestTime and HoldTimeThe .txt files and .mat files can be mapped to the corresponding session’s metadata (PX_SY_meta.json) using the shared field trialID. References1. Vu, P. P., Vaskov, A. K., Lee, C., Jillala, R. R., Wallace, D. M., Davis, A. J., ... & Cederna, P. S. (2023). Long-term upper-extremity prosthetic control using regenerative peripheral nerve interfaces and implanted EMG electrodes. Journal of Neural Engineering, 20(2), 026039. ---------- Explanation of data processing code: The following excerpts of MATLAB code illustrate the process of filtering the data and the process of calculating MAVs Filtering and downsampling 30kHz data:numsamp = 30000; %starting out with 30k data [b(1,:), a(1,:)] = butter(2, [100, 500]/15e3, 'bandpass');[b(2,:), a(2,:)] = butter(2, [59, 61]/15e3, 'stop');[b(3,:), a(3,:)] = butter(2, [119, 121]/15e3, 'stop'); [d(1,:), c(1,:)] = butter(2, [119, 121]/15e3, 'stop');[d(2,:), c(2,:)] = butter(2, [179, 181]/15e3, 'stop');[d(3,:), c(3,:)] = butter(2, [239, 241]/15e3, 'stop');[d(4,:), c(4,:)] = butter(2, [299, 301]/15e3, 'stop');[d(5,:), c(5,:)] = butter(2, [359, 361]/15e3, 'stop');[d(6,:), c(6,:)] = butter(2, [419, 421]/15e3, 'stop');[d(7,:), c(7,:)] = butter(2, [479, 481]/15e3, 'stop'); disp('bandpass filtering 30k data')for i = 1:length(miDB) disp(['filtering for task i = ', num2str(i)]) miDB(i).EMG30kf = filter(b(1,:), a(1,:), miDB(i).EMG30k); for j = 2:3 miDB(i).EMG30kf = filter(b(j,:), a(j,:), miDB(i).EMG30kf); end for j = 1:7 miDB(i).EMG30kf = filter(d(j,:), c(j,:), miDB(i).EMG30kf); endend disp('downsampling 30k data')for i = 1:length(miDB) disp(['downsampling for task i = ', num2str(i)]) miDB(i).EMG1kf = downsample(miDB(i).EMG30kf, 30); %downsampling down all channel columns miDB(i).EMG1k = downsample(miDB(i).EMG30k, 30); %downsampling raw data, tooend Calculating MAVs from 30kHz EMG data: for i = 1:numel(inDB) %input miDB struct emg_filt = inDB(i).EMG1kf; n_channels = size(emg_filt, 2); mav_all = []; window_size = round(fs * window_ms / 1000); step_size = round(window_size * (1 - overlap_pct)); starts = 1 : step_size : (size(emg_filt,1) - window_size + 1); for ch = 1:n_channels frames = buffer(emg_filt(:,ch), window_size, ... window_size - step_size, 'nodelay'); mav_all(:, ch) = mean(abs(frames), 1)'; end inDB(i).MAVs = mav_all; mav_composite = mean(mav_all, 2); ... end Calculating movement onset time based on MAVs (onset_idx)%% Baseline stats from a known rest period (e.g. last second in rest cue) %grab rest cue time period for averaging bl_start_ms = 1000; % baseline start (ms) bl_end_ms = 2000; % baseline end (ms) t = (0:length(inDB(i).EMG1kf)-1)/fs * 1000; % time in ms n_sd = 5; % threshold multiplier (usually for 3-5 std devs above mean) bl_idx = t >= bl_start_ms & t <= bl_end_ms; bl_mean = mean(mav_composite(bl_idx)); bl_sd = std(mav_composite(bl_idx)); threshold = bl_mean + n_sd * bl_sd; %% Detect onset: first window exceeding threshold (sustained N windows) % first segmenting only the second (cue) half of the task og_mav_comp = mav_composite; %just in case mav_composite = og_mav_comp(inDB(i).HoldTime+1:end); n_sustained = 5; % must exceed threshold for N consecutive windows above = mav_composite > threshold; onset_idx = inDB(i).HoldTime; %in case onset wasn’t found, default to nominal rest cue time for k = 1 : length(above) - n_sustained if all(above(k:k + n_sustained - 1)) onset_idx = k + inDB(i).RestTime; %be sure to add rest cue time back to get accurate stamp break end end if inDB(i).RestTime == 0 onset_idx = 1; %to address the non rest trials in some of the sessions end



