Skip to content

muap

Description

This module contains functions to produce and analyse MUs anction potentials (MUAPs).


diff(sorted_rawemg)

Calculate single differential (SD) of RAW_SIGNAL on matrix rows.

PARAMETER DESCRIPTION
sorted_rawemg

A dict containing the sorted electrodes. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame. Electrodes can be sorted with the function emg.sort_rawemg.

TYPE: dict

RETURNS DESCRIPTION
sd

A dict containing the double differential signal. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame.

TYPE: dict

See also
  • double_diff : calculate double differential of RAW_SIGNAL on matrix rows.
Notes

The returned sd will contain one less matrix row.

Examples:

Calculate single differential of a DEMUSE file with the channels already sorted.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="DEMUSE")
>>> sorted_rawemg = emg.sort_rawemg(
>>>     emgfile,
...     code="None",
...     orientation=180,
...     dividebycolumn=True,
...     n_rows=13,
...     n_cols=5,
... )
>>> sd = emg.diff(sorted_rawemg)
>>> sd["col0"]
             1         2         3  ...        10        11  12
0     -0.003052  0.005086 -0.009155 ...  0.001526  0.016785 NaN
1     -0.008647  0.008138 -0.010173 ... -0.001017 -0.015259 NaN
2     -0.005595  0.005595 -0.013733 ...  0.003560  0.007629 NaN
3     -0.010681  0.007121 -0.009664 ... -0.001526 -0.015259 NaN
4     -0.005595  0.005086 -0.011190 ...  0.001017  0.017293 NaN
...         ...       ...       ... ...       ...       ...  ..
63483 -0.000509  0.007121 -0.007629 ... -0.006612  0.022380 NaN
63484 -0.005086  0.005595 -0.004578 ... -0.005595 -0.045776 NaN
63485 -0.004069  0.001017 -0.003560 ... -0.005086 -0.005086 NaN
63486 -0.002035  0.006104 -0.010681 ... -0.007121  0.020345 NaN
63487 -0.008647  0.000000 -0.010681 ... -0.011190 -0.027466 NaN

Calculate single differential of an OTB file where the channels need to be sorted.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile,
...     code="GR08MM1305",
...     orientation=180,
... )
>>> sd = emg.diff(sorted_rawemg)


double_diff(sorted_rawemg)

Calculate double differential (DD) of RAW_SIGNAL on matrix rows.

PARAMETER DESCRIPTION
sorted_rawemg

A dict containing the sorted electrodes. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame. Electrodes can be sorted with the function emg.sort_rawemg.

TYPE: dict

RETURNS DESCRIPTION
dd

A dict containing the double differential signal. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame.

TYPE: dict

See also
  • diff : Calculate single differential of RAW_SIGNAL on matrix rows.
Notes

The returned dd will contain two less matrix rows.

Examples:

Calculate double differential of a DEMUSE file with the channels already sorted.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="DEMUSE")
>>> sorted_rawemg = emg.sort_rawemg(
>>>     emgfile,
...     code="None",
...     orientation=180,
...     dividebycolumn=True,
...     n_rows=13,
...     n_cols=5,
... )
>>> dd = emg.double_diff(sorted_rawemg)
>>> dd["col0"]
             2         3         4  ...            10        11  12
0      0.008138 -0.014242  0.012716 ...  4.577637e-03  0.015259 NaN
1      0.016785 -0.018311  0.022380 ...  8.138018e-03 -0.014242 NaN
2      0.011190 -0.019328  0.021362 ...  1.780192e-02  0.004069 NaN
3      0.017802 -0.016785  0.014750 ...  1.118978e-02 -0.013733 NaN
4      0.010681 -0.016276  0.017802 ...  4.577637e-03  0.016276 NaN
...         ...       ...       ... ...           ...       ...  ..
63483  0.007629 -0.014750  0.011698 ... -4.656613e-10  0.028992 NaN
63484  0.010681 -0.010173  0.011698 ... -2.543131e-03 -0.040181 NaN
63485  0.005086 -0.004578  0.004069 ... -6.612142e-03  0.000000 NaN
63486  0.008138 -0.016785  0.013733 ... -1.068115e-02  0.027466 NaN
63487  0.008647 -0.010681  0.019836 ... -1.068115e-02 -0.016276 NaN

Calculate single differential of an OTB file where the channels need to be sorted.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile=emgfile,
...     code="GR08MM1305",
...     orientation=180,
...     dividebycolumn=True,
... )
>>> dd = emg.double_diff(sorted_rawemg)


extract_delsys_muaps(emgfile)

Extract MUAPs obtained from Delsys decomposition.

The extracted MUAPs will be stored in the same structure of the MUAPs obtained with the sta funtion.

PARAMETER DESCRIPTION
emgfile

The dictionary containing the emgfile.

TYPE: dict

RETURNS DESCRIPTION
muaps_dict

dict containing a dict of MUAPs (pd.DataFrame) for every MUs.

TYPE: dict

See also
  • sta : Computes the spike-triggered average (STA) of every MUs.
Notes

The returned file can be used wherever MUAPs from spike triggered averaging are required.

Examples:

Visualise the MUAPs of the first MU.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="DELSYS")
>>> muaps = emg.extract_delsys_muaps(emgfile)
>>> emg.plot_muaps(muaps[0])

Visualise the MUAPs of the first 3 MUs.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="DELSYS")
>>> muaps = emg.extract_delsys_muaps(emgfile)
>>> emg.plot_muaps([muaps[0], muaps[1], muaps[2]])


sta(emgfile, sorted_rawemg, firings=[0, 50], timewindow=50)

Computes the spike-triggered average (STA) of every MUs.

PARAMETER DESCRIPTION
emgfile

The dictionary containing the emgfile.

TYPE: dict

sorted_rawemg

A dict containing the sorted electrodes. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame.

TYPE: dict

firings

The range of firings to be used for the STA. If a MU has less firings than the range, the upper limit is adjusted accordingly.

all The STA is calculated over all the firings.

TYPE: list or str {"all"} DEFAULT: [0, 50]

timewindow

Timewindow to compute STA in milliseconds.

TYPE: int DEFAULT: 50

RETURNS DESCRIPTION
sta_dict

dict containing a dict of STA (pd.DataFrame) for every MUs.

TYPE: dict

See also
  • unpack_sta : build a common pd.DataFrame from the sta dict containing all the channels.
  • pack_sta : pack the pd.DataFrame containing STA to a dict.
  • st_muap : generate spike triggered MUs action potentials over the entire spike train of every MUs.
Notes

The returned file is called sta_dict for convention.

Examples:

Calculate STA of all the MUs in the emgfile on the first 25 firings and in a 50 ms time-window. Access the STA of the column 0 of the first MU (number 0).

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile=emgfile,
...     code="GR08MM1305",
...     orientation=180,
... )
>>> sta = emg.sta(
...     emgfile=emgfile,
...     sorted_rawemg=sorted_rawemg,
...     firings=[0,25],
...     timewindow=50,
... )
>>> sta[0]["col0"]
     0          1          2  ...        10         11         12
0   NaN  -7.527668  -7.141111 ... -1.464846 -21.606445 -14.180500
1   NaN -16.662600 -14.038087 ...  2.868650 -19.246420 -15.218098
2   NaN -21.443687 -15.116375 ...  5.615236 -16.052244 -13.854978
3   NaN -17.822264  -9.989420 ...  6.876628 -12.451175 -12.268069
4   NaN -14.567060  -8.748373 ... -1.403812 -14.241538 -16.703283
..   ..        ...        ... ...       ...        ...        ...
97  NaN  19.388836  25.166826 ... 39.591473  23.681641  19.653318
98  NaN   8.870444  16.337074 ... 28.706865  20.548504   8.422853
99  NaN  -1.037601   7.446290 ... 18.086752  16.276041   0.040688
100 NaN  -2.766926   5.371094 ... 11.006674  14.261881  -0.712078
101 NaN   3.214517   9.562176 ...  4.475910  10.742184  -0.284828

Calculate STA of the differential signal on all the firings.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile=emgfile,
...     code="GR08MM1305",
...     orientation=180,
... )
>>> sd = emg.diff(sorted_rawemg=sorted_rawemg)
>>> sta = emg.sta(
...     emgfile=emgfile,
...     sorted_rawemg=sd,
...     firings="all",
...     timewindow=50,
... )
>>> sta[0]["col0"]
     1         2          3  ...         10         11         12
0   NaN -0.769545  11.807394 ...   3.388641  14.423187   1.420190
1   NaN -1.496154  11.146843 ...   4.637086  12.312718   3.408456
2   NaN -3.263135   9.660598 ...   6.258748   9.478946   5.974706
3   NaN -4.125159   9.257659 ...   6.532877   5.558562   7.708665
4   NaN -4.234151   9.379863 ...   6.034157   1.506064   8.722610
..   ..       ...        ... ...        ...        ...        ...
97  NaN -6.126635   1.225329 ... -10.050324   1.522576  -9.568117
98  NaN -6.565903   0.571378 ...  -8.669765   4.643692 -10.714180
99  NaN -6.153056  -0.105689 ...  -6.836730   7.272696 -12.623180
100 NaN -5.452869  -0.587892 ...  -7.411412   8.504627 -14.727043
101 NaN -4.587545  -0.855417 ... -10.549041   9.802613 -15.820260


st_muap(emgfile, sorted_rawemg, timewindow=50)

Generate spike triggered MUAPs of every MUs.

Generate single spike triggered (ST) MUs action potentials (MUAPs) over the entire spike train of every MUs.

PARAMETER DESCRIPTION
emgfile

The dictionary containing the emgfile.

TYPE: dict

sorted_rawemg

A dict containing the sorted electrodes. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame.

TYPE: dict

timewindow

Timewindow to compute ST MUAPs in milliseconds.

TYPE: int DEFAULT: 50

RETURNS DESCRIPTION
stmuap

dict containing a dict of ST MUAPs (pd.DataFrame) for every MUs. The pd.DataFrames containing the ST MUAPs are organised based on matrix rows (dict) and matrix channels. For example, the ST MUAPs of the first MU (0), in the second electrode of the first matrix column can be accessed as stmuap[0]["col0"][1].

TYPE: dict

See also
  • sta : computes the STA of every MUs.
Notes

The returned file is called stmuap for convention.

Examples:

Calculate the MUAPs of the differential signal. Access the MUAPs of the first MU (number 0), channel 15 that is contained in the second matrix column ("col1").

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile=emgfile,
...     code="GR08MM1305",
...     orientation=180,
... )
>>> sd = emg.diff(sorted_rawemg=sorted_rawemg)
>>> stmuap = emg.st_muap(emgfile=emgfile, sorted_rawemg=sd, timewindow=50)
>>> stmuap[0]["col1"][15]
           0          1          2   ...        151         152         153
0   -14.750162 -26.957193   6.103516 ...  23.905434    4.069008  150.553375
1    -9.155273 -22.379557  12.715660 ...   8.138023    0.000000  133.260086
2    -4.069010 -12.207031  17.293289 ...  -6.612144    6.612141   74.768066
3     1.525879  -6.612143  22.379562 ... -25.939949   21.362305  -14.750168
4     3.051758  -4.577637  24.414062 ... -35.603844   34.586590  -83.923347
..         ...        ...        ... ...        ...         ...         ...
97    9.155273 -24.922688  43.233238 ... -92.569984 -107.320145  -40.181477
98   -2.543133 -14.241535  28.483074 ...-102.233887  -68.155922  -19.836430
99  -23.905437 -13.732906  15.767414 ... -89.518234  -42.215984  -10.681152
100 -52.388512 -20.853680  14.241537 ... -71.716309  -26.448566    0.000000
101 -61.543785 -16.784668  21.362305 ... -52.388504   -3.560385    6.103516


unpack_sta(sta_mu)

Build a common pd.DataFrame from the sta_dict containing all the channels.

PARAMETER DESCRIPTION
sta_mu

A dict containing the STA of a single MU.

TYPE: dict

RETURNS DESCRIPTION
df1

A pd.DataFrame containing the STA of the MU (including the empty channel).

TYPE: DataFrame

keys

The matrix columns (dict keys) of the unpacked sta.

TYPE: list

See also
  • sta : computes the STA of every MUs.
  • pack_sta : pack the pd.DataFrame containing STA to a dict.


pack_sta(df_sta, keys)

Pack the pd.DataFrame containing STA to a dict.

PARAMETER DESCRIPTION
df_sta

(including the empty channel).

TYPE: A pd.DataFrame containing the STA of a single MU

keys

The matrix columns (dict keys) by which to pack the sta.

TYPE: list

RETURNS DESCRIPTION
packed_sta

dict containing STA of the input pd.DataFrame divided by matrix column. Dict columns are "col0", col1", "col2", "col3", "col4".

TYPE: dict

See also
  • sta : computes the STA of every MUs.
  • unpack_sta : build a common pd.DataFrame from the sta dict containing all the channels.


align_by_xcorr(sta_mu1, sta_mu2, finalduration=0.5)

Align the STA of 2 MUs by cross-correlation.

Any pre-processing of the RAW_SIGNAL (i.e., normal, differential or double differential) can be passed as long as the two inputs have same shape. Since the returned STA is cut based on finalduration, the input STA should account for this.

PARAMETER DESCRIPTION
sta_mu1

A dictionary containing the STA of the first MU.

TYPE: dict

sta_mu2

A dictionary containing the STA of the second MU.

TYPE: dict

finalduration

Duration of the aligned STA compared to the original in percent. (e.g., 0.5 corresponds to 50%).

TYPE: float DEFAULT: 0.5

RETURNS DESCRIPTION
aligned_sta1

A dictionary containing the aligned STA of the first MU with the final expected timewindow (duration of sta_mu * finalduration).

TYPE: dict

aligned_sta2

A dictionary containing the aligned STA of the second MU with the final expected timewindow (duration of sta_mu * finalduration).

TYPE: dict

See also
  • sta : computes the STA of every MUs.
  • norm_twod_xcorr : normalised 2-dimensional cross-correlation of STAs of two MUs.
Notes

STAs are aligned by a common lag/delay for the entire matrix and not channel by channel because this might lead to misleading results.

Examples:

Align two MUs with a final duration of 50% the original one.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile=emgfile,
...     code="GR08MM1305",
...     orientation=180,
... )
>>> sta = emg.sta(
...     emgfile=emgfile,
...     sorted_rawemg=sorted_rawemg,
...     timewindow=100,
... )
>>> aligned_sta1, aligned_sta2 = emg.align_by_xcorr(
...     sta_mu1=sta[0], sta_mu2=sta[1], finalduration=0.5,
... )
>>> aligned_sta1["col0"]
     0          1          2  ...        10         11         12
0   NaN -10.711670  -7.008868 ... 21.809900 -33.447262 -21.545408
1   NaN  -5.584714  -2.380372 ... 22.664387 -33.081059 -18.931072
2   NaN  -4.262290  -1.139323 ... 23.244226 -33.020020 -17.456057
3   NaN  -4.638671  -1.078290 ... 23.111980 -34.118645 -18.147787
4   NaN  -7.405599  -4.018145 ... 22.888189 -35.797115 -22.247314
..   ..        ...        ... ...       ...        ...        ...
97  NaN   6.764731  13.081865 ... 30.954998  39.672852  42.429604
98  NaN   4.455567  10.467529 ... 31.311037  41.280106  44.403072
99  NaN   0.356039   6.856283 ... 30.436195  43.701172  46.142574
100 NaN  -2.960206   4.872639 ... 30.008953  44.342041  46.366371
101 NaN  -7.008870   1.708984 ... 25.634764  40.100101  43.009445


tracking(emgfile1, emgfile2, firings='all', derivation='sd', timewindow=50, threshold=0.8, matrixcode='GR08MM1305', orientation=180, n_rows=None, n_cols=None, custom_sorting_order=None, custom_muaps=None, exclude_belowthreshold=True, filter=True, multiprocessing=True, show=False, gui=True, gui_addrefsig=True, gui_csv_separator='\t')

Track MUs across two files comparing the MUAPs' shape and distribution.

It is also possible to use a convenient GUI for the inspection of the obtained MU pairs.

PARAMETER DESCRIPTION
emgfile1

The dictionary containing the first emgfile.

TYPE: dict

emgfile2

The dictionary containing the second emgfile.

TYPE: dict

firings

The range of firings to be used for the STA. If a MU has less firings than the range, the upper limit is adjusted accordingly.

all The STA is calculated over all the firings.

A list can be passed as [start, stop] e.g., [0, 25] to compute the STA on the first 25 firings.

TYPE: list or str {"all"} DEFAULT: "all"

derivation

Whether to compute the sta on the monopolar signal, or on the single or double differential derivation.

TYPE: str {mono, sd, dd} DEFAULT: sd

timewindow

Timewindow to compute STA in milliseconds.

TYPE: int DEFAULT: 50

threshold

The 2-dimensional cross-correlation minimum value to consider two MUs to be the same. Ranges 0-1.

TYPE: float DEFAULT: 0.8

matrixcode

The code of the matrix used. It can be one of:

GR08MM1305

GR04MM1305

GR10MM0808

Custom order

None

This is necessary to sort the channels in the correct order. If matrixcode="None", the electrodes are not sorted. In this case, n_rows and n_cols must be specified. If "Custom order", the electrodes are sorted based on custom_sorting_order.

TYPE: str DEFAULT: "GR08MM1305"

orientation

Orientation in degree of the matrix (same as in OTBiolab). E.g. 180 corresponds to the matrix connection toward the user. This Parameter is ignored if code=="Custom order" or code=="None".

TYPE: int {0, 180} DEFAULT: 180

n_rows

The number of rows of the matrix. This parameter is used to divide the channels based on the matrix shape. These are normally inferred by the matrix code and must be specified only if code == None.

TYPE: None or int DEFAULT: None

n_cols

The number of columns of the matrix. This parameter is used to divide the channels based on the matrix shape. These are normally inferred by the matrix code and must be specified only if code == None.

TYPE: None or int DEFAULT: None

custom_sorting_order

If code=="Custom order", custom_sorting_order will be used for channels sorting. In this case, custom_sorting_order must be a list of lists containing the order of the matrix channels. Specifically, the number of columns are defined by len(custom_sorting_order) while the number of rows by len(custom_sorting_order[0]). np.nan can be used to specify empty channels. Please refer to the Examples section for the structure of the custom sorting order.

TYPE: None or list DEFAULT: None

custom_muaps

With this parameter, it is possible to perform MUs tracking on MUAPs computed with custom techniques. If this parameter is None (default), MUs tracking is performed on the MUAPs computed via spike triggered averaging. Otherwise, it is possible to pass a list of 2 dictionaries containing the MUAPs of the MUs from 2 different files. These dictionaries should be structured as the output of the sta function. If custom MUAPs are passed, all the previous parameters (except for emgfile1 and emgfile2 can be ignored). If custom MUAPs are provided, these are not aligned by the algorithm, contrary to what is done for MUAPs obtained via spike triggered averaging.

TYPE: None or list DEFAULT: None

exclude_belowthreshold

Whether to exclude results with XCC below threshold.

TYPE: bool DEFAULT: True

filter

If true, when the same MU has a match of XCC > threshold with multiple MUs, only the match with the highest XCC is returned.

TYPE: bool DEFAULT: True

multiprocessing

If True (default) parallel processing will be used to reduce execution time.

TYPE: bool DEFAULT: True

show

Whether to plot the STA of pairs of MUs with XCC above threshold. Set to False (default) when gui=True to avoid postponing the GUI execution. If show=True and gui=True, the GUI will be executed after closing all the figures.

TYPE: bool DEFAULT: False

gui

If True (default) a GUI for the visual inspection and manual selection of the tracking results will be called.

TYPE: bool DEFAULT: True

gui_addrefsig

If True, the REF_SIGNAL is plotted in front of the IDR with a separated y-axes. This is used only when gui=True.

TYPE: bool DEFAULT: True

gui_csv_separator

The field delimiter used by the GUI to create the .csv copied to the clipboard. This is used only when gui=True.

TYPE: str DEFAULT: " "

RETURNS DESCRIPTION
tracking_res

The results of the tracking including the MU from file 1, MU from file 2 and the normalised cross-correlation value (XCC). If gui=True, an additional column indicating the inclusion/exclusion of the MUs pairs will also be present in tracking_res.

TYPE: DataFrame

WARNS DESCRIPTION
UserWarning

If the number of plots to show exceeds that of available cores.

See also
  • sta : computes the STA of every MUs.
  • norm_twod_xcorr : normalised 2-dimensional cross-correlation of STAs of two MUs.
  • Tracking_gui : GUI for the visual inspection and manual selection of the tracking results (directly callable from the tracking function).
  • remove_duplicates_between : remove duplicated MUs across two different files based on STA.
Notes

Parallel processing can significantly improve performances compared to serial processing. In this function, parallel processing has been implemented for the tasks involving 2-dimensional cross-correlation.

Examples:

Track MUs between two OPENHDEMG (.json) files and inspect the results with a convenient GUI.

>>> import openhdemg.library as emg
>>> emgfile1 = emg.askopenfile(filesource="OPENHDEMG")
>>> emgfile2 = emg.askopenfile(filesource="OPENHDEMG")
>>> tracking_res = emg.tracking(
...     emgfile1=emgfile1,
...     emgfile2=emgfile2,
...     firings="all",
...     derivation="sd",
...     timewindow=50,
...     threshold=0.8,
...     matrixcode="GR08MM1305",
...     orientation=180,
...     filter=True,
...     show=False,
...     gui=True,
>>> )

Track MUs between two OTB files and show the filtered results.

>>> import openhdemg.library as emg
>>> emgfile1 = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> emgfile2 = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> tracking_res = emg.tracking(
...     emgfile1=emgfile1,
...     emgfile2=emgfile2,
...     firings="all",
...     derivation="sd",
...     timewindow=50,
...     threshold=0.8,
...     matrixcode="GR08MM1305",
...     orientation=180,
...     n_rows=None,
...     n_cols=None,
...     exclude_belowthreshold=True,
...     filter=True,
...     show=False,
...     gui=False,
... )
    MU_file1  MU_file2       XCC
0          0         3  0.820068
1          2         4  0.860272
2          4         8  0.857346
3          5         0  0.878373
4          6         9  0.877321
5          7         1  0.823371
6          9        13  0.873388
7         11         5  0.862537
8         19        10  0.802635
9         21        14  0.896419
10        22        16  0.836356

Track MUs between two files where channels are sorted with a custom order.

>>> import openhdemg.library as emg
>>> emgfile1 = emg.askopenfile(filesource="CUSTOMCSV")
>>> emgfile2 = emg.askopenfile(filesource="CUSTOMCSV")
>>> custom_sorting_order = [
...     [63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52,     51,],
...     [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,     50,],
...     [37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26,     25,],
...     [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,     24,],
...     [11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, np.nan,],
... ]  # 13 rows and 5 columns
>>> tracking_res = emg.tracking(
...     emgfile1=emgfile1,
...     emgfile2=emgfile2,
...     firings="all",
...     derivation="sd",
...     timewindow=50,
...     threshold=0.8,
...     matrixcode="Custom order",
...     orientation=180,
...     n_rows=None,
...     n_cols=None,
...     custom_sorting_order=custom_sorting_order,
...     exclude_belowthreshold=True,
...     filter=True,
...     show=False,
...     gui=False,
... )


Tracking_gui

GUI for the visual inspection and manual selection of the tracking results.

PARAMETER DESCRIPTION
emgfile1

The dictionary containing the first emgfile.

TYPE: dict

emgfile2

The dictionary containing the second emgfile.

TYPE: dict

tracking_res

The results of the tracking including the MU from file 1, MU from file 2 and the normalised cross-correlation value (XCC). This is obtained with the function tracking().

TYPE: DataFrame

sta_emgfile1

dict containing a dict of STA (pd.DataFrame) for every MUs from emgfile1. This is obtained with the function sta().

TYPE: dict

sta_emgfile2

dict containing a dict of STA (pd.DataFrame) for every MUs from emgfile2. This is obtained with the function sta().

TYPE: dict

align_muaps

Whether to align the MUAPs before plotting. If true, the visualised MUAPs time window will be ½ of the original (because the maximum allowed shift during MUAPs alignment is 50%).

TYPE: bool DEFAULT: True

addrefsig

If True, the REF_SIGNAL is plotted in front of the IDR with a separated y-axes.

TYPE: bool DEFAULT: True

csv_separator

The field delimiter used to create the .csv copied to the clipboard.

TYPE: str DEFAULT: " "

METHOD DESCRIPTION
get_results

Returns the results of the tracking including the MU from file 1, MU from file 2, the normalised cross-correlation value (XCC) and the inclusion or exclusion of the MUs pair. after the GUI is closed.

See also
  • tracking : Track MUs across two files comparing the MUAPs' shape and distribution.

Examples:

Track MUs between two files.

>>> import openhdemg.library as emg
>>> emgfile_1 = emg.askopenfile(filesource="OPENHDEMG")
>>> emgfile_2 = emg.askopenfile(filesource="OPENHDEMG")
>>> tracking_res = emg.tracking(emgfile_1, emgfile_2, timewindow=50)

Obtained required variables for Tracking_gui(). Pay attention to use the same derivation specified during tracking and to use an appropriate MUAPs timewindow, according to the align_muaps option in Tracking_gui().

>>> sorted_rawemg_1 = emg.sort_rawemg(emgfile_1)
>>> sorted_rawemg_1 = emg.diff(sorted_rawemg_1)
>>> sta_dict_1 = emg.sta(emgfile_1, sorted_rawemg_1, timewindow=100)
>>> sorted_rawemg_2 = emg.sort_rawemg(emgfile_2)
>>> sorted_rawemg_2 = emg.diff(sorted_rawemg_2)
>>> sta_dict_2 = emg.sta(emgfile_2, sorted_rawemg_2, timewindow=100)

Inspect the tracking results with a convenient GUI.

>>> tracking = emg.Tracking_gui(
...     emgfile1=emgfile_1,
...     emgfile2=emgfile_2,
...     tracking_res=tracking_res,
...     sta_emgfile1=sta_dict_1,
...     sta_emgfile2=sta_dict_2,
...     align_muaps=True,
...     addrefsig=True,
... )

Return the updated results for further use in the code.

>>> updated_results = tracking.get_results()
    MU_file1  MU_file2       XCC Inclusion
0          0         2  0.897364  Excluded
1          1         0  0.947486  Included
2          2         1  0.923901  Included
3          4         8  0.893922  Included


remove_duplicates_between(emgfile1, emgfile2, firings='all', derivation='sd', timewindow=50, threshold=0.9, matrixcode='GR08MM1305', orientation=180, n_rows=None, n_cols=None, custom_sorting_order=None, custom_muaps=None, filter=True, multiprocessing=True, show=False, gui=True, gui_addrefsig=True, gui_csv_separator='\t', which='munumber')

Remove duplicated MUs across two different files based on STA.

PARAMETER DESCRIPTION
emgfile1

The dictionary containing the first emgfile.

TYPE: dict

emgfile2

The dictionary containing the second emgfile.

TYPE: dict

firings

The range of firings to be used for the STA. If a MU has less firings than the range, the upper limit is adjusted accordingly.

all The STA is calculated over all the firings.

A list can be passed as [start, stop] e.g., [0, 25] to compute the STA on the first 25 firings.

TYPE: list or str {"all"} DEFAULT: "all"

derivation

Whether to compute the sta on the monopolar signal, or on the single or double differential derivation.

TYPE: str {mono, sd, dd} DEFAULT: sd

timewindow

Timewindow to compute STA in milliseconds.

TYPE: int DEFAULT: 50

threshold

The 2-dimensional cross-correlation minimum value to consider two MUs to be the same. Ranges 0-1.

TYPE: float DEFAULT: 0.9

matrixcode

The code of the matrix used. It can be one of:

GR08MM1305

GR04MM1305

GR10MM0808

Custom order

None

This is necessary to sort the channels in the correct order. If matrixcode="None", the electrodes are not sorted. In this case, n_rows and n_cols must be specified. If "Custom order", the electrodes are sorted based on custom_sorting_order.

TYPE: str DEFAULT: "GR08MM1305"

orientation

Orientation in degree of the matrix (same as in OTBiolab). E.g. 180 corresponds to the matrix connection toward the user. This Parameter is ignored if code=="Custom order" or code=="None".

TYPE: int {0, 180} DEFAULT: 180

n_rows

The number of rows of the matrix. This parameter is used to divide the channels based on the matrix shape. These are normally inferred by the matrix code and must be specified only if code == None.

TYPE: None or int DEFAULT: None

n_cols

The number of columns of the matrix. This parameter is used to divide the channels based on the matrix shape. These are normally inferred by the matrix code and must be specified only if code == None.

TYPE: None or int DEFAULT: None

custom_sorting_order

If code=="Custom order", custom_sorting_order will be used for channels sorting. In this case, custom_sorting_order must be a list of lists containing the order of the matrix channels. Specifically, the number of columns are defined by len(custom_sorting_order) while the number of rows by len(custom_sorting_order[0]). np.nan can be used to specify empty channels. Please refer to the Examples section for the structure of the custom sorting order.

TYPE: None or list DEFAULT: None

custom_muaps

With this parameter, it is possible to perform MUs tracking on MUAPs computed with custom techniques. If this parameter is None (default), MUs tracking is performed on the MUAPs computed via spike triggered averaging. Otherwise, it is possible to pass a list of 2 dictionaries containing the MUAPs of the MUs from 2 different files. These dictionaries should be structured as the output of the sta function. If custom MUAPs are passed, all the previous parameters (except for emgfile1 and emgfile2 can be ignored). If custom MUAPs are provided, these are not aligned by the algorithm, contrary to what is done for MUAPs obtained via spike triggered averaging.

TYPE: None or list DEFAULT: None

filter

If true, when the same MU has a match of XCC > threshold with multiple MUs, only the match with the highest XCC is returned.

TYPE: bool DEFAULT: True

multiprocessing

If True (default) parallel processing will be used to reduce execution time.

TYPE: bool DEFAULT: True

show

Whether to plot the STA of pairs of MUs with XCC above threshold.

TYPE: bool DEFAULT: False

gui

If True (default) a GUI for the visual inspection and manual selection of the tracking results will be called.

TYPE: bool DEFAULT: True

gui_addrefsig

If True, the REF_SIGNAL is plotted in front of the IDR with a separated y-axes. This is used only when gui=True.

TYPE: bool DEFAULT: True

gui_csv_separator

The field delimiter used by the GUI to create the .csv copied to the clipboard. This is used only when gui=True.

TYPE: str DEFAULT: " "

which

How to remove the duplicated MUs.

munumber Duplicated MUs are removed from the file with more MUs.

accuracy The MU with the lowest accuracy is removed.

TYPE: str {"munumber", "accuracy"} DEFAULT: "munumber"

RETURNS DESCRIPTION
emgfile1, emgfile2 : dict

The original emgfiles without the duplicated MUs.

tracking_res

The results of the tracking including the MU from file 1, MU from file 2 and the normalised cross-correlation value (XCC). If gui=True, an additional column indicating the inclusion/exclusion of the MUs pairs will also be present in tracking_res.

TYPE: DataFrame

See also
  • sta : computes the STA of every MUs.
  • norm_twod_xcorr : normalised 2-dimensional cross-correlation of STAs of two MUs.
  • tracking : track MUs across two different files.

Examples:

Remove duplicated MUs between two OPENHDEMG files and inspect the tracking outcome via a convenient GUI. Then Save the emgfiles without duplicates. Of the 2 duplicated MUs, the one with the lowest accuracy is removed.

>>> import openhdemg.library as emg
>>> emgfile1 = emg.askopenfile(filesource="OPENHDEMG")
>>> emgfile2 = emg.askopenfile(filesource="OPENHDEMG")
>>> emgfile1, emgfile2, tracking_res = emg.remove_duplicates_between(
...     emgfile1,
...     emgfile2,
...     firings="all",
...     derivation="mono",
...     timewindow=50,
...     threshold=0.9,
...     matrixcode="GR08MM1305",
...     orientation=180,
...     gui=True,
...     which="accuracy",
... )
>>> emg.asksavefile(emgfile1)
>>> emg.asksavefile(emgfile2)

Remove duplicated MUs between two OTB files and directly save the emgfiles without duplicates. The duplicates are removed from the file with more MUs.

>>> import openhdemg.library as emg
>>> emgfile1 = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> emgfile2 = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> emgfile1, emgfile2, tracking_res = emg.remove_duplicates_between(
...     emgfile1,
...     emgfile2,
...     firings="all",
...     derivation="mono",
...     timewindow=50,
...     threshold=0.9,
...     matrixcode="GR08MM1305",
...     orientation=180,
...     n_rows=None,
...     n_cols=None,
...     filter=True,
...     show=False,
...     gui=False,
...     which="munumber",
... )
>>> emg.asksavefile(emgfile1)
>>> emg.asksavefile(emgfile2)

Remove duplicated MUs between two files where channels are sorted with a custom order and directly save the emgfiles without duplicates. Of the 2 duplicated MUs, the one with the lowest accuracy is removed.

>>> import openhdemg.library as emg
>>> import numpy as np
>>> emgfile1 = emg.askopenfile(filesource="CUSTOMCSV")
>>> emgfile2 = emg.askopenfile(filesource="CUSTOMCSV")
>>> custom_sorting_order = [
...     [63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52,     51,],
...     [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,     50,],
...     [37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26,     25,],
...     [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,     24,],
...     [11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, np.nan,],
... ]  # 13 rows and 5 columns
>>> emgfile1, emgfile2, tracking_res = emg.remove_duplicates_between(
...     emgfile1,
...     emgfile2,
...     firings="all",
...     derivation="sd",
...     timewindow=50,
...     threshold=0.9,
...     matrixcode="Custom order",
...     orientation=180,
...     n_rows=None,
...     n_cols=None,
...     custom_sorting_order=custom_sorting_order,
...     filter=True,
...     show=False,
...     gui=False,
...     which="accuracy",
... )
>>> emg.asksavefile(emgfile1)
>>> emg.asksavefile(emgfile2)


xcc_sta(sta)

Cross-correlation between the STA of adjacent channels.

Calculate the normalised cross-correlation coefficient (XCC) between the MUs action potential shapes on adjacent channels. The XCC will be calculated for all the MUs and all the pairs of electrodes.

PARAMETER DESCRIPTION
sta

The dict containing the spike-triggered average (STA) of all the MUs computed with the function sta().

TYPE: dict

RETURNS DESCRIPTION
xcc_sta

A dict containing the XCC for all the pairs of channels and all the MUs. This dict is organised as the sta dict.

TYPE: dict

Examples:

Calculate the XCC of adjacent channels of the double differential derivation as done to calculate MUs conduction velocity.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile,
...     code="GR08MM1305",
...     orientation=180,
...     dividebycolumn=True
... )
>>> dd = emg.double_diff(sorted_rawemg)
>>> sta = emg.sta(
...     emgfile=emgfile,
...     sorted_rawemg=dd,
...     firings=[0, 50],
...     timewindow=50,
... )
>>> xcc_sta = emg.xcc_sta(sta)


estimate_cv_via_mle(emgfile, signal)

Estimate signal conduction velocity via maximum likelihood estimation.

This function can be used for the estimation of conduction velocity for 2 or more signals. These can be either MUAPs or global EMG signals.

PARAMETER DESCRIPTION
emgfile

The dictionary containing the emgfile from whic "signal" has been extracted. This is used to know IED and FSAMP.

TYPE: dict

signal

A dataframe containing the signals on which to estimate CV. The signals should be organised in colums.

TYPE: DataFrame

RETURNS DESCRIPTION
cv

The conduction velocity value in M/s.

TYPE: float

See also
  • MUcv_gui : Graphical user interface for the estimation of MUs conduction velocity.

Examples:

Calculate the CV for the first MU (number 0) on the channels 31, 32, 34, 34 that are contained in the second column ("col2") of the double differential representation of the MUAPs. First, obtain the spike- triggered average of the double differential derivation.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> emgfile = emg.filter_rawemg(emgfile)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile,
...     code="GR08MM1305",
...     orientation=180,
...     dividebycolumn=True
... )
>>> dd = emg.double_diff(sorted_rawemg=sorted_rawemg)
>>> sta = emg.sta(
...     emgfile=emgfile,
...     sorted_rawemg=sorted_rawemg,
...     firings=[0,50],
...     timewindow=50,
... )

Second, extract the channels of interest and estimate CV.

>>> signal = sta[0]["col2"].loc[:, 31:34]
>>> cv = estimate_cv_via_mle(emgfile=emgfile, signal=signal)


MUcv_gui(emgfile, sorted_rawemg, n_firings=[0, 50], muaps_timewindow=50, figsize=[25, 20], csv_separator='\t')

Graphical user interface for the estimation of MUs conduction velocity.

GUI for the estimation of MUs conduction velocity (CV) and amplitude of the action potentials (root mean square - RMS).

PARAMETER DESCRIPTION
emgfile

The dictionary containing the emgfile.

TYPE: dict

sorted_rawemg

A dict containing the sorted electrodes. Every key of the dictionary represents a different column of the matrix. Rows are stored in the dict as a pd.DataFrame.

TYPE: dict

n_firings

The range of firings to be used for the STA. If a MU has less firings than the range, the upper limit is adjusted accordingly.

all The STA is calculated over all the firings.

TYPE: list or str {"all"} DEFAULT: [0, 50]

muaps_timewindow

Timewindow to compute ST MUAPs in milliseconds.

TYPE: int DEFAULT: 50

figsize

Size of the initial MUAPs figure in centimeters [width, height].

TYPE: list DEFAULT: [20, 15]

csv_separator

The field delimiter used to create the .csv copied to the clipboard.

TYPE: str DEFAULT: " "

See also
  • estimate_cv_via_mle : Estimate signal conduction velocity via maximum likelihood estimation.

Examples:

Call the GUI.

>>> import openhdemg.library as emg
>>> emgfile = emg.askopenfile(filesource="OTB", otb_ext_factor=8)
>>> emgfile = emg.filter_rawemg(emgfile)
>>> sorted_rawemg = emg.sort_rawemg(
...     emgfile,
...     code="GR08MM1305",
...     orientation=180,
...     dividebycolumn=True
... )
>>> gui = emg.MUcv_gui(
...     emgfile=emgfile,
...     sorted_rawemg=sorted_rawemg,
...     n_firings=[0,50],
...     muaps_timewindow=50
... )