Skip to main content

delsys

src PyPI - Version Documentation Status GitHub license

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, 1 all 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/C for left/right/center). Anything else still loads but won't match lf.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

Praneeth Namburi

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

delsys-0.5.1.tar.gz (12.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

delsys-0.5.1-py3-none-any.whl (136.1 kB view details)

Uploaded Python 3

File details

Details for the file delsys-0.5.1.tar.gz.

File metadata

  • Download URL: delsys-0.5.1.tar.gz
  • Upload date:
  • Size: 12.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.31.0

File hashes

Hashes for delsys-0.5.1.tar.gz
Algorithm Hash digest
SHA256 ec9382c98789052b65f1259ab5dd96f3aac08ac924d4b748986e271f32fd5cdf
MD5 0ef2898cb015c90dc621aa85f5c63b1a
BLAKE2b-256 2a40f94276035913564bef1875d579d0c0cec30093058a335ef2678d7ed0e952

See more details on using hashes here.

File details

Details for the file delsys-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: delsys-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 136.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.31.0

File hashes

Hashes for delsys-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 19102dc5fe70f84fcd315a4ea852c1026fda199089ff7a64e74ffe35d6f675dc
MD5 dab139ef43f38b2b85a311f243c59a46
BLAKE2b-256 50cec918c14b87e37f2a0418ebbf4169084e2f7239d96ad781d246eedc33954a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.1 This release

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page