Skill Tracer
Skills › Scientific Agent Skills › neurokit2 › emg.md

emg.md

173 lines · skills/neurokit2/references/emg.md at 5f2bc03

Open on GitHub
1# Electromyography
2
3Checked **2026-10-01** against NeuroKit2 0.2.13 stable runtime/source,
4the official EMG API, and human surface-EMG guidance.
5

Electromyography

Checked 2026-10-01 against NeuroKit2 0.2.13 stable runtime/source, the official EMG API, and human surface-EMG guidance.

Raw lines 1 to 5
6## Acquisition contract
7
8Record muscle and task, electrode type/size/orientation/inter-electrode distance,
9reference, skin preparation, amplifier gain/range, hardware filters, unit, sampling
10rate, synchronization, posture/contraction, and artifact annotations. Follow a
11muscle-specific placement protocol such as SENIAM when applicable.
13EMG amplitude depends on geometry, subcutaneous tissue, cross-talk, electrode contact,
14hardware, and contraction history. It is not a direct universal force scale.

Acquisition contract

Record muscle and task, electrode type/size/orientation/inter-electrode distance, reference, skin preparation, amplifier gain/range, hardware filters, unit, sampling rate, synchronization, posture/contraction, and artifact annotations. Follow a muscle-specific placement protocol such as SENIAM when applicable.

EMG amplitude depends on geometry, subcutaneous tissue, cross-talk, electrode contact, hardware, and contraction history. It is not a direct universal force scale.

Raw lines 6 to 15
16## Stable processing pipeline
18```python
19signals, info = nk.emg_process(emg, sampling_rate=1000)
20```
22Pinned 0.2.13 default columns:
24```text
25EMG_Raw, EMG_Clean, EMG_Amplitude,
26EMG_Activity, EMG_Onsets, EMG_Offsets
27```
29`info` contained event-level `EMG_Activity`, `EMG_Onsets`, `EMG_Offsets`, and
30`sampling_rate`. This is a default observation, not a universal schema.

Stable processing pipeline

signals, info = nk.emg_process(emg, sampling_rate=1000)

Pinned 0.2.13 default columns:

EMG_Raw, EMG_Clean, EMG_Amplitude,
EMG_Activity, EMG_Onsets, EMG_Offsets

info contained event-level EMG_Activity, EMG_Onsets, EMG_Offsets, and sampling_rate. This is a default observation, not a universal schema.

Raw lines 16 to 31
32## Cleaning and amplitude
34```python
35clean = nk.emg_clean(emg, sampling_rate=1000, method="biosppy")
36amplitude = nk.emg_amplitude(clean)
37```
39Important stable details:
41- `emg_clean()` currently offers `biosppy` and `none`.
42- The BioSPPy path uses a fourth-order 100 Hz high-pass Butterworth filter followed by
43 constant detrending.
44- `emg_amplitude()` takes only the cleaned vector; it has no `sampling_rate` argument
45 in 0.2.13.
47The last point is a scientific constraint: its private envelope routine defaults to
481000 Hz (10–400 Hz band-pass, rectification, 8 Hz low-pass), and the public wrapper
49does not forward the acquisition rate. `emg_process(..., sampling_rate=500)` changes
50cleaning/detection timing but still computes that envelope as if sampled at 1000 Hz.
51The example above uses 1000 Hz. At other rates, implement and validate an explicit
52envelope with the actual rate or use a justified resampling workflow; do not report
53the hard-coded nominal cutoffs as the physical cutoffs of that recording.
55A 100 Hz high-pass may be unsuitable for some surface-EMG endpoints and impossible at
56low sampling rates. Do not treat the package default as a universal acquisition
57standard. Set sampling rate above twice the highest retained frequency with transition
58band margin; surface EMG is commonly acquired around 1000–2000 Hz, but the study,
59hardware, muscle, and endpoint determine requirements.

Cleaning and amplitude

clean = nk.emg_clean(emg, sampling_rate=1000, method="biosppy")
amplitude = nk.emg_amplitude(clean)

Important stable details:

  • emg_clean() currently offers biosppy and none.
  • The BioSPPy path uses a fourth-order 100 Hz high-pass Butterworth filter followed by constant detrending.
  • emg_amplitude() takes only the cleaned vector; it has no sampling_rate argument in 0.2.13.

The last point is a scientific constraint: its private envelope routine defaults to 1000 Hz (10–400 Hz band-pass, rectification, 8 Hz low-pass), and the public wrapper does not forward the acquisition rate. emg_process(..., sampling_rate=500) changes cleaning/detection timing but still computes that envelope as if sampled at 1000 Hz. The example above uses 1000 Hz. At other rates, implement and validate an explicit envelope with the actual rate or use a justified resampling workflow; do not report the hard-coded nominal cutoffs as the physical cutoffs of that recording.

A 100 Hz high-pass may be unsuitable for some surface-EMG endpoints and impossible at low sampling rates. Do not treat the package default as a universal acquisition standard. Set sampling rate above twice the highest retained frequency with transition band margin; surface EMG is commonly acquired around 1000–2000 Hz, but the study, hardware, muscle, and endpoint determine requirements.

Raw lines 32 to 60
61## Activation detection
63Stable signature:
65```text
66emg_activation(
67 emg_amplitude=None, emg_cleaned=None, sampling_rate=1000,
68 method="threshold", threshold="default", duration_min="default",
69 size=None, threshold_size=None, **kwargs
71```
73Use the correct input for the method:
75- `threshold` or `mixture`: pass `emg_amplitude`;
76- `pelt`, `biosppy`, or `silva`: pass `emg_cleaned`.
78```python
79activity_signals, activity_info = nk.emg_activation(
80 emg_amplitude=amplitude,
81 sampling_rate=1000,
82 method="threshold",
83 threshold="default",
84 duration_min=50, # samples: 50 ms at 1000 Hz in stable 0.2.13
86```
88Return order is `(activity_signals, info)`. The DataFrame has same-length
89`EMG_Activity`, `EMG_Onsets`, and `EMG_Offsets`; the dict contains event indices.
90An explicit `duration_min` is passed to sample-count event filtering in stable
910.2.13; the docstring incorrectly says seconds. Only `"default"` converts 0.05 seconds
92using the supplied rate. Pass `round(minimum_seconds * sampling_rate)` for an explicit
93minimum. `size` is seconds for `biosppy`, but samples for `silva`; Silva's
94`threshold_size` is also samples. Verify detected run lengths at the chosen rate.
96Automatic thresholds are hypotheses, not ground truth. Tune/validate on independent
97labeled contractions or a prespecified baseline. Report threshold, window, smoothing,
98minimum duration, and false/missed activation performance.

Activation detection

Stable signature:

emg_activation(
  emg_amplitude=None, emg_cleaned=None, sampling_rate=1000,
  method="threshold", threshold="default", duration_min="default",
  size=None, threshold_size=None, **kwargs
)

Use the correct input for the method:

  • threshold or mixture: pass emg_amplitude;
  • pelt, biosppy, or silva: pass emg_cleaned.
activity_signals, activity_info = nk.emg_activation(
    emg_amplitude=amplitude,
    sampling_rate=1000,
    method="threshold",
    threshold="default",
    duration_min=50,  # samples: 50 ms at 1000 Hz in stable 0.2.13
)

Return order is (activity_signals, info). The DataFrame has same-length EMG_Activity, EMG_Onsets, and EMG_Offsets; the dict contains event indices. An explicit duration_min is passed to sample-count event filtering in stable 0.2.13; the docstring incorrectly says seconds. Only "default" converts 0.05 seconds using the supplied rate. Pass round(minimum_seconds * sampling_rate) for an explicit minimum. size is seconds for biosppy, but samples for silva; Silva's threshold_size is also samples. Verify detected run lengths at the chosen rate.

Automatic thresholds are hypotheses, not ground truth. Tune/validate on independent labeled contractions or a prespecified baseline. Report threshold, window, smoothing, minimum duration, and false/missed activation performance.

Raw lines 61 to 99
100## Missing data and artifacts
102Inspect and annotate:
104- clipping/saturation and disconnected/flat channels;
105- motion/cable artifacts and low-frequency transients;
106- powerline interference;
107- ECG contamination, especially trunk/proximal sites;
108- cross-talk from adjacent muscles; and
109- baseline changes from contact/sweat.
111Do not interpolate across a burst or activation onset. Segment long gaps, preserve a
112validity mask, and reject affected trials/windows under prespecified rules. Filtering
113cannot establish that a deflection came from the target muscle.

Missing data and artifacts

Inspect and annotate:

  • clipping/saturation and disconnected/flat channels;
  • motion/cable artifacts and low-frequency transients;
  • powerline interference;
  • ECG contamination, especially trunk/proximal sites;
  • cross-talk from adjacent muscles; and
  • baseline changes from contact/sweat.

Do not interpolate across a burst or activation onset. Segment long gaps, preserve a validity mask, and reject affected trials/windows under prespecified rules. Filtering cannot establish that a deflection came from the target muscle.

Raw lines 100 to 114
115## Event and interval features
117```python
118epochs = nk.epochs_create(
119 signals,
120 events,
121 sampling_rate=1000,
122 epochs_start=-0.1,
123 epochs_end=1.0,
124 baseline_correction=False,
126event_features = nk.emg_eventrelated(epochs)
127interval_features = nk.emg_intervalrelated(signals)
128```
130Documented event-related features include `EMG_Activation`,
131`EMG_Amplitude_Mean`, `EMG_Amplitude_Max`, `EMG_Amplitude_SD`,
132`EMG_Amplitude_Max_Time`, and `EMG_Bursts`. Interval analysis returns
133`EMG_Activation_N` and `EMG_Amplitude_Mean` in the pinned official example.
134Columns are conditional; inspect output.
136For startle or rapid onset work, hardware latency, synchronization, filter group delay,
137rectification/smoothing, and onset-definition error can dominate the result.

Event and interval features

epochs = nk.epochs_create(
    signals,
    events,
    sampling_rate=1000,
    epochs_start=-0.1,
    epochs_end=1.0,
    baseline_correction=False,
)
event_features = nk.emg_eventrelated(epochs)
interval_features = nk.emg_intervalrelated(signals)

Documented event-related features include EMG_Activation, EMG_Amplitude_Mean, EMG_Amplitude_Max, EMG_Amplitude_SD, EMG_Amplitude_Max_Time, and EMG_Bursts. Interval analysis returns EMG_Activation_N and EMG_Amplitude_Mean in the pinned official example. Columns are conditional; inspect output.

For startle or rapid onset work, hardware latency, synchronization, filter group delay, rectification/smoothing, and onset-definition error can dominate the result.

Raw lines 115 to 138
139## Normalization
141Raw/envelope amplitude is usually not comparable across participants or sessions.
142Possible denominators include MVC, reference contraction, or within-participant
143standardization, but each changes the estimand.
145If using MVC:
147- acquire it with a validated, safe protocol;
148- inspect fatigue, pain, effort, clipping, and target/cross-talk;
149- define which statistic and window represent MVC;
150- report repetitions and reliability; and
151- never divide by a near-zero/invalid reference.
153Normalization does not make electrode/site differences disappear.

Normalization

Raw/envelope amplitude is usually not comparable across participants or sessions. Possible denominators include MVC, reference contraction, or within-participant standardization, but each changes the estimand.

If using MVC:

  • acquire it with a validated, safe protocol;
  • inspect fatigue, pain, effort, clipping, and target/cross-talk;
  • define which statistic and window represent MVC;
  • report repetitions and reliability; and
  • never divide by a near-zero/invalid reference.

Normalization does not make electrode/site differences disappear.

Raw lines 139 to 154
155## Interpretation boundary
157NeuroKit2 EMG can support research on amplitude and detected activity. It does not
158provide validated motor-unit decomposition, neuromuscular diagnosis, fatigue
159monitoring, prosthetic control safety, rehabilitation decisions, or sleep scoring.
160Those require endpoint-specific acquisition, algorithms, standards, and independent
161validation.

Interpretation boundary

NeuroKit2 EMG can support research on amplitude and detected activity. It does not provide validated motor-unit decomposition, neuromuscular diagnosis, fatigue monitoring, prosthetic control safety, rehabilitation decisions, or sleep scoring. Those require endpoint-specific acquisition, algorithms, standards, and independent validation.

Raw lines 155 to 162
163## Sources checked 2026-10-01
165- [Official EMG API](https://neuropsychology.github.io/NeuroKit/functions/emg.html)
166- [Stable v0.2.13 EMG source](https://github.com/neuropsychology/NeuroKit/tree/v0.2.13/neurokit2/emg)
167- [Fridlund & Cacioppo (1986), human EMG guidelines](https://pubmed.ncbi.nlm.nih.gov/3809364/)
168- [Hermens et al. (2000), SENIAM sensor/placement recommendations](https://doi.org/10.1016/S1050-6411(00)00027-4)
169- [Blumenthal et al. (2005), startle eyeblink EMG guidelines](https://doi.org/10.1111/j.1469-8986.2005.00271.x)
171- [Stable `emg_activation.py` implementation](https://github.com/neuropsychology/NeuroKit/blob/v0.2.13/neurokit2/emg/emg_activation.py)
173- [Stable `emg_amplitude.py` implementation](https://github.com/neuropsychology/NeuroKit/blob/v0.2.13/neurokit2/emg/emg_amplitude.py)

Sources checked 2026-10-01

  • [Stable emg_activation.py implementation](https://github.com/neuropsychology/NeuroKit/blob/v0.2.13/neurokit2/emg/emg_activation.py)
  • [Stable emg_amplitude.py implementation](https://github.com/neuropsychology/NeuroKit/blob/v0.2.13/neurokit2/emg/emg_amplitude.py)
Raw lines 163 to 173