Source code for dimep.algo.zewdie

"""

To objectively quantify significant ipsilateral responses, 20 TMS stimulations of nonlesioned M1 at 120% RMT were examined for ipsilateral MEP. Participants with ≥5/20 ipsilateral MEP >50 μV in amplitude  were  classified  as  ipsilateral  (IP)  while  those without were considered nonipsilateral (NI). Latencies were calculated as the aver-age time from the TMS artifact (t = 0 ms) to MEP onset  at  120%  RMT.  MEPs  were  recorded  at  rest. Average MEP latency was calculated from 20 MEPs at  120%  RMT.  A  MATLAB  script  identified  MEP  onset as the time point when the EMG exceeded 3 standard deviations from mean background EMG

A custom MATLAB script calculated
peak-to-peak MEP values from un-rectified EMG by setting
a time window of 15 to 80 ms from the TMS pulse.

"""
import numpy as np
from numpy import ndarray
from typing import Tuple
from math import ceil


[docs]def zewdie( trace: ndarray, tms_sampleidx: int, fs: float = 1000, discernible_only: bool = False, ) -> float: """Estimate the peak-to-peak amplitude of an iMEP based on Zewdie 2017 Returns the Peak-to-Peak amplitude of the iMEP within 15 to 80ms after stimulus, if it is 'discernable' i.e. at least 50µV in amplitude and exceeds 3 SD of the background EMG. args ---- trace:ndarray the one-dimensional (samples,) EMG signal with units in µV tms_sampleidx: int the sample at which the TMS pulse was applied fs:float the sampling rate of the signal discernible_only: bool whether to report only discernible MEPS (i.e. amplitude >= 50 µV). defaults to False returns ------- iMEP: float the peak-to-peak amplitude of the iMEP .. admonition:: Reference Zewdie, E.; Damji, O.; Ciechanski, P.; Seeger, T. & Kirton, A. Contralesional Corticomotor Neurophysiology in Hemiparetic Children With Perinatal Stroke. Neurorehabilitation and neural repair, 2017, 31, 261-271 .. seealso:: :func:`~.odergren` also uses a threshold with absolute units, but 100µV instead of 50µV. :func:`.lewis` is very similar, but uses stricter criterio for discernibility. """ # different to :func:`~.lewis`, the duration of the baseline period is not # specified, therefore we include the whole trace until the TMS pulse # NOTE: Paper does not specify formula for SD baseline = trace[:tms_sampleidx] bl_m = baseline.mean() bl_s = baseline.std(ddof=1) # identified MEP onset as the time point when the EMG exceeded 3 # standard deviations from mean background EMG # The paper does not clarify whether this was an additional threshold # besides the 50µV, but it seems reasonable threshold = bl_m + 3 * bl_s mep_window_in_ms: Tuple[float, float] = (15, 80) minlatency = ceil(mep_window_in_ms[0] * fs / 1000) maxlatency = mep_window_in_ms[1] * fs / 1000 maxlatency = ceil(min(maxlatency, len(trace) - tms_sampleidx)) response = trace[tms_sampleidx + minlatency : tms_sampleidx + maxlatency] # exceed 3 standard deviations (SD) of background EMG. # ipsilateral MEP >50 μV in amplitude # NOTE: we take the abs because otherwise, orientiation of the bipolar # recording can mess things up if np.max(np.abs(response)) > threshold: amp = np.ptp(response) else: amp = 0.0 if discernible_only: return amp if amp >= 50.0 else 0.0 else: return amp