Source code for myoverse.datasets.presets.embc
"""EMBC 2022 paper configuration and transforms.
Pre-configured transform pipelines matching the EMBC 2022 paper:
Simpetru, R.C., et al., 2022. Accurate Continuous Prediction of
14 Degrees of Freedom of the Hand from Myoelectrical Signals
through Convolutive Deep Learning. EMBC 2022, pp. 702-706.
Example:
-------
>>> from myoverse.datasets import DatasetCreator, Modality
>>> from myoverse.datasets.presets.embc import embc_kinematics_transform
>>>
>>> creator = DatasetCreator(
... modalities={
... "emg": Modality(path="emg.pkl", dims=("channel", "time")),
... "kinematics": Modality(
... path="kinematics.pkl",
... dims=("dof", "time"),
... transform=embc_kinematics_transform(),
... ),
... },
... ...
... )
"""
from __future__ import annotations
from dataclasses import dataclass
from myoverse.transforms import (
Compose,
Flatten,
GaussianNoise,
Identity,
Index,
Lowpass,
MagnitudeWarp,
Mean,
Stack,
)
[docs]
@dataclass
class EMBCConfig:
"""Configuration matching EMBC 2022 paper.
References
----------
[1] Simpetru, R.C., et al., 2022. Accurate Continuous Prediction of
14 Degrees of Freedom of the Hand from Myoelectrical Signals
through Convolutive Deep Learning. EMBC 2022, pp. 702-706.
"""
sampling_frequency: float = 2048.0
window_size: int = 192
lowpass_cutoff: float = 20.0
lowpass_order: int = 4
n_electrode_grids: int = 5
test_ratio: float = 0.2
val_ratio: float = 0.2
[docs]
def embc_kinematics_transform() -> Compose:
"""Pre-storage transform for kinematics (EMBC paper).
Converts (21, 3, time) -> (60, time) by:
1. Flattening joints*xyz -> (63, time)
2. Removing wrist (first 3 values) -> (60, time)
Returns
-------
Compose
Transform to set as Modality.transform for kinematics.
"""
return Compose(
[
Flatten(start_dim=0, end_dim=1), # (21, 3, time) -> (63, time)
Index(slice(3, None), dim="channel"), # Remove wrist -> (60, time)
]
)
[docs]
def embc_train_transform(
config: EMBCConfig | None = None,
augmentation: str = "noise",
) -> Compose:
"""Training-time transform for EMG (EMBC paper).
Creates dual representation by stacking raw and filtered signals.
Parameters
----------
config : EMBCConfig | None
Configuration (uses defaults if None).
augmentation : str
Augmentation: "noise", "warp", or "none".
Returns
-------
Compose
Transform pipeline producing (representation, channel, time).
"""
cfg = config or EMBCConfig()
transforms = [
# Stack into (representation, channel, time)
Stack(
{
"raw": Identity(),
"filtered": Lowpass(
cfg.lowpass_cutoff, fs=cfg.sampling_frequency, dim="time"
),
},
dim="representation",
),
]
if augmentation == "noise":
transforms.append(GaussianNoise(std=0.1))
elif augmentation == "warp":
transforms.append(MagnitudeWarp(sigma=0.35, n_knots=6, dim="time"))
return Compose(transforms)
[docs]
def embc_eval_transform(config: EMBCConfig | None = None) -> Compose:
"""Evaluation-time transform for EMG (EMBC paper, no augmentation).
Parameters
----------
config : EMBCConfig | None
Configuration (uses defaults if None).
Returns
-------
Compose
Transform pipeline producing (representation, channel, time).
"""
cfg = config or EMBCConfig()
return Compose(
[
Stack(
{
"raw": Identity(),
"filtered": Lowpass(
cfg.lowpass_cutoff, fs=cfg.sampling_frequency, dim="time"
),
},
dim="representation",
),
]
)
[docs]
def embc_target_transform() -> Mean:
"""Target transform: average kinematics over window.
Returns
-------
Mean
Transform that averages over time: (60, time) -> (60,).
"""
return Mean(dim="time")