ibo-biomech
Python tools for motion-capture workflows: load C3D and the institute's HDF5
format, process markers and signals, export OpenSim inputs, and inspect IK/ID
results. Both file handlers return a TrialData containing named channels.
The package is in alpha. See the current limitations and development priorities for the status of HDF5 saving, force resampling, and coordinate assumptions.
Install
python -m pip install ibo-biomech
For this checkout, including the latest local changes:
python -m pip install -e .
Plotting methods require matplotlib, installed separately:
python -m pip install matplotlib
OpenSim is only required to run scaling, inverse kinematics, or inverse dynamics.
File conversion and result containers work without it. Follow the
OpenSim Python setup instructions
and verify import opensim in the same Python environment.
Try a complete example without a data file
This example creates a marker sampled at 100 Hz, filters it, crops a copy, and exports a DataFrame with timestamps. The cutoff is illustrative; choose processing parameters for your recording and analysis.
from copy import deepcopy
import numpy as np
from ibo_biomech import MarkerData, TrialData
time = np.arange(300) / 100.0
marker = MarkerData(
name="R_Ankle",
x=1000.0 + 50.0 * np.sin(2 * np.pi * time),
y=np.zeros_like(time),
z=np.full_like(time, 100.0),
unit="mm",
sampling_rate=100.0,
time=time,
)
trial = TrialData(name="demo", markers={marker.name: marker})
processed = deepcopy(trial)
processed.lowpass_filter_markers(cutoff_freq=6.0, order=4)
processed.crop("markers", start_idx=50, end_idx=200)
frame = processed.as_df(processed.markers)
frame.insert(0, "time", processed.markers["R_Ankle"].time)
print(processed.name, frame.shape) # demo (150, 4)
# processed.markers["R_Ankle"].plot() # requires matplotlib
Filtering, cropping, rotation, and unit conversion modify containers in place.
Use deepcopy() to keep a raw trial. Marker arithmetic returns a new marker;
EMGData.process_emg() returns an envelope, while also cleaning NaNs in raw data.
Load a recording
Replace the paths with your files. HDF5 support is specific to the institute's
schema, not arbitrary .h5 files.
from ibo_biomech import C3DHandler, H5Handler
trial = C3DHandler("walking.c3d").load_data()
# Alternatively:
# trial = H5Handler("walking.h5").load_data()
print(trial.name)
print(trial.get_marker_names())
print(trial.get_force_names())
print(trial.get_analog_names())
print(trial.marker_rate, trial.analog_rate, trial.force_rate)
# Use labels present in your recording:
# marker = trial.markers["R_Ankle"]
# plate = trial.forces["forceplate_0"]
# analog = trial.get_analog_by_channel(3)
A C3D handler shares its processed containers with the returned trial. Use
handler.write_c3d(path, trial) for supported marker/analog edits, or
handler.write_raw_c3d(path) for the original structure. Derived force edits
belong in HDF5/MOT; see the export tutorial.
Current processing API
| Operation | Method | Notes |
|---|---|---|
| Filter markers | trial.lowpass_filter_markers(cutoff_freq=6.0) |
Frequency in Hz; no automatic gap filling. |
| Filter analogs | trial.lowpass_filter_analogs(cutoff_freq=100.0) |
Cutoff must be below every affected channel's Nyquist frequency. |
| Filter forces | trial.lowpass_filter_forces(cutoff_freq=20.0) |
Processes vector Tz; plate geometry stays unchanged. |
| Filter EMG channels | trial.lowpass_filter_emgs(cutoff_freq=10.0) |
Filters raw EMG; this is not the envelope pipeline. |
| Filter one channel | marker.lowpass_filter(cutoff=6.0) |
Channel methods use cutoff; trial methods use cutoff_freq. |
| Fill marker gaps | marker.clean_nan() |
Linear interpolation of interior NaNs; inspect gaps first. |
| Crop one data type | trial.crop("markers", 100, 200) |
End index excluded; indices belong to the selected data type. |
| Rotate markers | trial.rotate_markers(axis="x", angle_deg=-90) |
Requires the correct lab-to-model transform. |
| Rotate forces | trial.rotate_forces(axis="x", angle_deg=-90) |
Rotates vectors and geometry in the declared frame. |
| Convert units | trial.convert_units("m") |
Supports mm ↔ m; force magnitudes remain unchanged. |
| Select EMG channels | trial.parse_EMG_data([3]) |
Channel indices are zero-based for C3D imports. |
| Attach results | trial.attach_IK_results("ik.mot") / trial.attach_ID_results("id.sto") |
Results have named Data columns. |
There is no single trial-wide lowpass_filter(), rotate_data(), or
convert_to_meters() method. To crop the same interval across sampling rates,
select indices using each channel's time vector; see the processing tutorial.
File conversion and results
FileConverter.c3d_to_h5(c3d_path, h5_path, **metadata) writes an HDF5 file in
acquisition coordinates and units, including marker-only recordings. Only the
current HDF5 force schema is supported; regenerate older files from C3D.
OpenSim converters are h5_to_trc, h5_to_mot, h5_to_opensim, c3d_to_trc,
c3d_to_mot, and c3d_to_opensim. Their defaults are axis="x", angle=-90,
and convert_to_meters=True. Those defaults describe one lab convention.
The combined converters accept (source_path, mot_path, trc_path).
The export tutorial shows a route from
a processed C3D trial to TRC/MOT using write_trc() and write_mot().
from ibo_biomech import IKResults, IDResults
ik = IKResults(filepath="walking_IK.mot")
ik.to_rad()
print(ik["hip_flexion_r"].data)
ik.write("walking_IK_radians.mot")
id_results = IDResults(filepath="walking_ID.sto")
print(id_results.columns)
Check per-column units when reading results: the current shared reader assigns angle units to all columns, including translations and ID forces/moments. See results and subjects for explicit units, DataFrames, normalization, and multi-trial organization.
Tutorials and reference
Start with the documentation overview:
- Load and organize trials: C3D, HDF5, metadata, ownership, and saving constraints.
- Process markers, forces, and EMG: synthetic examples, virtual markers, and time-aware cropping.
- Export OpenSim inputs: processed TRC/MOT output and converter signatures.
- Work with results and subjects:
Data, IK/ID, normalization, and tables. - Run OpenSim tools: scaling, IK, external loads, and ID.
- Detect gait events: an executable example and the detector's assumptions.
API reference pages are in docs/api/. To build the documentation locally:
python -m pip install -e ".[docs]"
python -m sphinx -b html docs docs/_build/html
Open docs/_build/html/index.html. To run the existing tests:
python -m pip install pytest
python -m pytest tests
Release files for ibo-biomech 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ibo_biomech-0.3.5.tar.gz | 190.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ibo_biomech-0.3.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 256.8 kB
Release files / ibo_biomech-0.3.5.tar.gz
| Download URL | ibo_biomech-0.3.5.tar.gz |
|---|---|
| Size | 190.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b301c5fd8398fbb77e81814eaddc41004b03f4f7d59e282064f28029019b2b12
|
|
BLAKE2b-256 checksum How to use checksums |
a186b6f1d0acefd4e5ce2d1def93ead095c0034d0accbe7f9bc5dbfc889afc7e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / ibo_biomech-0.3.5-py3-none-any.whl
| Download URL | ibo_biomech-0.3.5-py3-none-any.whl |
|---|---|
| Size | 66.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
553c6b34a62208f5bacae4100d5af7253186dc5c2c00908bfc2d34d6e0fc1bfc
|
|
BLAKE2b-256 checksum How to use checksums |
9901538c16834c3e9b35dbff8fe97f6b43db2ed4a7fa2caa8540645f1e80be03
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log