Metadata-Version: 2.4
Name: dfjimu
Version: 0.4.0
Summary: Drift-free IMU-based joint kinematics estimation (Weygers & Kok, 2020)
Author: Daniel Oliver Martin Weber
License-Expression: MIT
Project-URL: Homepage, https://github.com/daniel-om-weber/dfjimu
Project-URL: Repository, https://github.com/daniel-om-weber/dfjimu
Project-URL: Issues, https://github.com/daniel-om-weber/dfjimu/issues
Keywords: IMU,joint-kinematics,MEKF,quaternion,inertial-sensors
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Cython
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: scipy
Provides-Extra: examples
Requires-Dist: jupyter; extra == "examples"
Requires-Dist: matplotlib; extra == "examples"
Provides-Extra: dev
Requires-Dist: cython>=3.0; extra == "dev"
Requires-Dist: setuptools; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# Drift-Free Joint Kinematics from Dual IMUs

High-performance Python/Cython implementation of the drift-free joint kinematics estimation method from [Weygers & Kok (2020), "Drift-Free Inertial Sensor-Based Joint Kinematics for Long-Term Arbitrary Movements"](https://ieeexplore.ieee.org/document/9044292/).

Two algorithms are provided:

- **MEKF-acc** — online Multiplicative Extended Kalman Filter
- **MAP-acc** — offline Gauss-Newton optimizer for higher accuracy

## Installation

Pre-built wheels with the fast Cython backend are available for Linux, macOS, and Windows (Python 3.10+):

```bash
pip install dfjimu
```

When installing from the source distribution (no matching wheel), a C compiler is required for the Cython extension. If compilation fails, the package falls back to a pure Python backend automatically.

## Usage

```python
from dfjimu import mekf_acc, map_acc

# MEKF-acc — lever arms r1, r2 are auto-estimated when omitted
q1, q2 = mekf_acc(gyr1, gyr2, acc1, acc2, Fs=Fs, q_init=q_init)

# Or provide lever arms explicitly
q1, q2 = mekf_acc(gyr1, gyr2, acc1, acc2, r1, r2, Fs, q_init)

# MAP-acc (optimization-based smoothing)
q1, q2 = map_acc(gyr1, gyr2, acc1, acc2, Fs=Fs, q_init=q_init,
                 cov_w=cov_w, cov_i=cov_i, cov_lnk=cov_lnk)

# Gyroscope bias: only if the recording starts at rest, remove the bias
# estimated over the first 5 s, as in the paper ...
q1, q2 = mekf_acc(gyr1, gyr2, acc1, acc2, Fs=Fs, q_init=q_init, gyr_bias=True)

# ... or pass known biases (rad/s), e.g. from a separate rest recording
q1, q2 = mekf_acc(gyr1, gyr2, acc1, acc2, Fs=Fs, q_init=q_init, gyr_bias=(b1, b2))
```

See [`examples/demo.ipynb`](examples/demo.ipynb) for a full walkthrough with plots.

## API

| Function | Description |
|---|---|
| `mekf_acc()` / `MekfAcc` | MEKF-acc filter (online) |
| `map_acc()` / `MapAcc` | MAP-acc optimizer (offline, higher accuracy) |
| `estimate_lever_arms()` | Lever arm estimation from dual-IMU data |
| `estimate_gyro_bias()` | Gyroscope bias as the mean over a static period |
| `map_acc_stable()` / `MapAccStable` | MAP-acc with a numerically stable quaternion logarithm |
| `ConvergenceWarning` | Issued when MAP-acc stops at its iteration limit before converging |

Both `mekf_acc` and `map_acc` accept optional `r1`, `r2` lever arm vectors. When omitted (`None`), they are auto-estimated via `estimate_lever_arms()`.

## Relation to the paper

The defaults do not reproduce every setting described in Weygers & Kok (2020, Sec. IV-A; Opt.-algorithm 2 in
Sec. III-B for the iterations):

| | Paper | This package (default) |
|---|---|---|
| Gyroscope bias | estimated over a 5 s static period at the start and removed | not removed (`gyr_bias=True` removes it as in the paper) |
| Gyroscope noise | one variance σω² over the same 5 s period (Σω = σω² I₃) | `mekf_acc`: per-axis variance of the first 50 samples; `map_acc`: `cov_w` must be given |
| Measurement / link noise | R = Σlink = I₃ | `R_diag = 0.011552`; `cov_lnk` must be given |
| Initial covariance | P = I₆ | `P_init_diag = 0.35²` |
| MAP-acc iterations | until a termination condition is met | at most 1000, stopping when the update norm is below `tol` |

The bias removal assumes that the sensors are at rest during the first 5 s. If a recording starts in motion, the
mean over that period is not a bias, and subtracting it makes the estimate worse; pass known biases instead, or
leave `gyr_bias` unset.

MAP-acc stops when the norm of the whole update vector falls below `tol` (an absolute threshold over all samples).
A solve that does not converge runs all `iterations` steps, returns the last iterate and issues a
`dfjimu.ConvergenceWarning`; on long recordings that can take long, so lower `iterations` or raise `tol` if needed.
The paper reports convergence after a couple of iterations; with this absolute threshold the bundled recordings
need about 100–500.

## Development

```bash
# Install in editable mode with dev tools
pip install -e ".[dev]"

# Build Cython extensions in-place
python setup.py build_ext --inplace

# Run tests
pytest tests/

# Install with Jupyter and matplotlib for the example notebook
pip install -e ".[examples]"
```

## Benchmarks

Evaluate accuracy and speed of the solvers across all datasets:

```bash
python tests/evaluate_package.py
```

## Reference

Weygers, I., & Kok, M. (2020). Drift-Free Inertial Sensor-Based Joint Kinematics for Long-Term Arbitrary Movements. *IEEE Sensors Journal*, 20(14), 7969-7979.
