delsys
Load Delsys CSV exports into Python as pysampled.Data time series.
delsys reads CSV files exported from EMGworks and Trigno Discover, normalizes their
many per-format quirks (header layouts, sub-channel orderings, link-device
asynchrony), resamples each channel to a configurable per-modality target
rate, and groups the result into per-sensor modality bundles (EMG, EKG,
IMU, FSR, VO2 Master, HR Strap, Analog) ready for analysis.
Installation
pip install delsys
For local development:
git clone https://github.com/praneethnamburi/delsys
pip install -e "./delsys[dev]"
Quickstart
import delsys
lf = delsys.Log("path/to/Trial.csv", sensor_map="path/to/delsys_channelmap.txt")
# Direct accessors — each returns a single aggregated `pysampled.Data`
# per modality (channels stacked across every sensor that has it), or
# `None` if no sensor does.
lf.emg # aggregate EMG
lf.ekg # aggregate EKG
lf.acc, lf.gyro # aggregate IMU
lf.fsr # aggregate FSR
lf.analog # aggregate Analog
lf.vo2master # VO2 Master link device (8 channels)
lf.hrstrap # HR Strap link device
# Side accessors return whole Sensor objects.
lf.left, lf.right, lf.center
# Filtered queries.
lf.find(modality="EMG", side="R") # right-side EMG bundles
lf.find(location="Forearm") # any sensor at "Forearm"
lf.find(sensor_number=5)
lf.find(modality="EMG", as_="signal") # raw per-channel Signal objects
# A typical EMG envelope pipeline (operate per-sensor).
for emg in lf.emg.split_by_signal_name():
envelope = emg.process(amp_kind="envelope2")
rms = emg.rms(envelope_sr=240) # clean RMS amplitude pipeline
Cleaning ECG and motion artifact from EMG
Log.clean_emg_ekg_artifact() runs a three-stage pipeline
(preprocess → ICA-based ECG suppression → ACC-guided motion regression
with safety gates) over every EMG channel in the Log, splices the
cleaned matrix back into lf.signals, and writes a multi-page PDF
report next to the source CSV.
lf = delsys.Log("trial.csv")
# Default: in-place clean + PDF report.
result = lf.clean_emg_ekg_artifact()
# Inspect without mutating.
result = lf.clean_emg_ekg_artifact(in_place=False, generate_report=False)
# Splice only the ECG-cleaned variant back (e.g. when the motion stage
# is over-cleaning on this trial).
lf.clean_emg_ekg_artifact(splice_source="ekgonly")
Interactive cleaning — lf.clean():
One window to pick the ECG/ICA cleaning decision (the single-log counterpart to
the batch delsys.clean()). An all-components bar shows each IC's EKG
correlation — click a bar (or j/k) to inspect that IC, 1 toggles
its removal (red = removed) — with the inspected IC's detail beside it; a channel
reviewer shows raw vs cleaned (arrow keys / the channel dropdown step
channels), and a Motion auto/off toggle + splice selector finish the
decision. The three time-domain panels share an x-axis whose zoom persists across
redraws (so you can compare ICs/channels at the same window; Auto limits
resets), and each panel's y rescales to the data in the visible x-window. Save writes the decision to the sibling <stem>.delsys-artifact that
delsys.clean() replays (and clears the stale *_cleaned.h5). The ICA is fit
once on open and toggles recompute cheaply. Mark noise first with
lf.annotate_noise(); clean() consumes the sibling .delsys-noise sidecar
automatically.
lf = delsys.Log("Trial_5.h5") # a native checkpoint
lf.clean() # click ICs, preview, Save -> .delsys-artifact
See tutorials/cleaning_emg_ekg_artifact.md
for the full walkthrough.
See the full API reference at https://delsys.readthedocs.io.
Channelmap files (optional)
When you pass sensor_map="path/to/delsys_channelmap.txt" to Log(), that
file labels each sensor number with a sensor type and a body-location tag.
This lets you query by side (lf.find(side="R")) and by location
(lf.find(location="Forearm")).
The format is one sensor per line, three fields separated by " - ":
Ch 1 - EMG - LBicep
Ch 2 - EMG - RBicep
Ch 11 - EKG - Chest
Ch 12 - Sync - Optitrack Recording Gate
Ch 19 - Quattro - LForearmExtensors (A-Index, B-Middle, C-Ring, D-Little)
Ch 21 - FSR - LFoot (1-Heel, 2-OuterEdge, 3-Ball, 4-Toe)
- Field 1: any text whose last whitespace-token is the sensor's channel
number (
Ch 1,Channel 01,1all work). - Field 2: a type tag (free text — common values:
EMG,Quattro,Snap,EKG,FSR,Sync). - Field 3: a location label. Its first character is interpreted as the
side (
L/R/Cfor left/right/center). Anything else still loads but won't matchlf.find(side=...).
Trailing parenthetical notes are informational only — they remain in
location but the parser doesn't extract sub-channel labels from them.
Blank lines and lines without two " - " separators are silently skipped.
A more comprehensive reference file lives at
examples/delsys_channelmap.txt.
Supported export formats
- EMGworks
- Trigno Discover 1.4.2
- Trigno Discover 1.5.0
- Trigno Discover 1.6.4 (with and without link devices)
- Trigno Discover 1.7.0
Supported sensors
EMG (Avanti single, Duo, Quattro, Snap-Lead), EKG, ACC, GYRO, FSR, Analog, VO2 Master (link), HR Strap (link).
Scope and contributions
Supported sensor types are limited to those the maintainer has access to.
Delsys ships other hardware (e.g. SmO2/Thb appear as stubs in TARGET_SR
but are not exercised end-to-end). Contributions adding parsers and tests
for additional sensors are very welcome.
If you'd like to contribute, the dev install above pulls pytest, black,
and isort. Format with black and isort before opening a PR:
isort src/ tests/ scripts/
black src/ tests/ scripts/
pytest
License
Distributed under the MIT License. See LICENSE for details.
Contact
Project link: https://github.com/praneethnamburi/delsys
Acknowledgments
This package was developed as part of the ImmersionToolbox initiative at the MIT.nano Immersion Lab. Thanks to NCSOFT for supporting this initiative.
Metadata
Release files for delsys 0.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| delsys-0.5.1.tar.gz | 12.3 MB | Without provenance | Details for delsys-0.5.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| delsys-0.5.1-py3-none-any.whl | Python 3 | none | any | Details for delsys-0.5.1-py3-none-any.whl |
Total release size: 12.4 MB
Release files / delsys-0.5.1.tar.gz
| Download URL | delsys-0.5.1.tar.gz |
|---|---|
| Size | 12.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec9382c98789052b65f1259ab5dd96f3aac08ac924d4b748986e271f32fd5cdf
|
|
BLAKE2b-256 checksum How to use checksums |
2a40f94276035913564bef1875d579d0c0cec30093058a335ef2678d7ed0e952
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.31.0
|
Release files / delsys-0.5.1-py3-none-any.whl
| Download URL | delsys-0.5.1-py3-none-any.whl |
|---|---|
| Size | 136.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
19102dc5fe70f84fcd315a4ea852c1026fda199089ff7a64e74ffe35d6f675dc
|
|
BLAKE2b-256 checksum How to use checksums |
50cec918c14b87e37f2a0418ebbf4169084e2f7239d96ad781d246eedc33954a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.31.0
|
Security for delsys 0.5.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.