This document presents the numerical comparison between gait-dynamics-features and PyRQA (v8.1.0), a well-established Python RQA library.
Parameters:
- Embedding dimension: 3
- Time delay: 5
- Threshold: 0.5 (fixed)
- Theiler window: 1
- Min diagonal length: 2
- Min vertical length: 2
- Distance metric: Euclidean
Test signals:
- Sine - Simple sine wave (300 points)
- Harmonics - Sine + 2nd/3rd harmonics (300 points)
- Lorenz - Lorenz attractor x-component (300 points, chaotic)
- Noise - White Gaussian noise (300 points)
| Measure | gait-dynamics-features | PyRQA | Diff |
|---|---|---|---|
| RR | 0.204923 | 0.204923 | 0.000000 |
| DET | 0.999056 | 0.999056 | 0.000000 |
| L | 24.748538 | 24.748538 | 0.000000 |
| Lmax | 289 | 289 | 0 |
| ENTR | 3.642857 | 3.642856 | 0.000001 |
| LAM | 0.999884 | 0.999884 | 0.000000 |
| TT | 25.119534 | 25.119534 | 0.000000 |
| Vmax | 49 | 49 | 0 |
| Measure | gait-dynamics-features | PyRQA | Diff |
|---|---|---|---|
| RR | 0.167872 | 0.167872 | 0.000000 |
| DET | 0.999132 | 0.999132 | 0.000000 |
| L | 38.592179 | 38.592179 | 0.000000 |
| Lmax | 289 | 289 | 0 |
| ENTR | 3.509815 | 3.509815 | 0.000000 |
| LAM | 0.999858 | 0.999858 | 0.000000 |
| TT | 23.844595 | 23.844595 | 0.000000 |
| Vmax | 40 | 40 | 0 |
| Measure | gait-dynamics-features | PyRQA | Diff | Note |
|---|---|---|---|---|
| RR | 0.004495 | 0.004495 | 0.000000 | |
| DET | 0.886364 | 0.886364 | 0.000000 | |
| L | 13.000000 | 13.000000 | 0.000000 | |
| Lmax | 21 | 21 | 0 | |
| ENTR | 1.098612 | 1.098612 | 0.000000 | |
| LAM | 0.000000 | 0.000000 | 0.000000 | |
| TT | 0.000000 | nan | - | See note 1 |
| Vmax | 0 | 1 | 1 | See note 2 |
Note 1 (TT): When no vertical lines meet min_vert_length >= 2, we return 0.0 while PyRQA returns NaN. Both are valid representations of an undefined mean over an empty set.
Note 2 (Vmax): PyRQA reports Vmax=1 (length of isolated vertical points), while we report 0 because no vertical lines meet the minimum length threshold of 2. This is a difference in how min_vert_length is applied to the Vmax output.
| Measure | gait-dynamics-features | PyRQA | Diff |
|---|---|---|---|
| RR | 0.014602 | 0.014602 | 0.000000 |
| DET | 0.012793 | 0.012793 | 0.000000 |
| L | 2.000000 | 2.000000 | 0.000000 |
| Lmax | 2 | 2 | 0 |
| ENTR | 0.000000 | 0.000000 | 0.000000 |
| LAM | 0.048860 | 0.048860 | 0.000000 |
| TT | 2.068966 | 2.068966 | 0.000000 |
| Vmax | 3 | 3 | 0 |
30 out of 32 measure comparisons show exact numerical agreement (within floating-point precision).
The 2 remaining differences occur only for the Lorenz system under extremely sparse recurrence (RR = 0.45%), where no vertical lines of length >= 2 exist. These are edge-case definitional differences, not computational errors.
| Signal | gait-dynamics-features | PyRQA | Speedup |
|---|---|---|---|
| Sine (N=300) | 0.007s | 0.091s | 13.9x |
| Harmonics (N=300) | 0.006s | 0.020s | 3.2x |
| Lorenz (N=300) | 0.006s | 0.019s | 3.1x |
| Noise (N=300) | 0.006s | 0.021s | 3.3x |
Our pure NumPy/SciPy implementation is 3-14x faster than PyRQA (which uses OpenCL) for typical gait-sized data (N < 1000). PyRQA's OpenCL backend may be advantageous for very large N (> 10000).
| N | Time |
|---|---|
| 100 | 0.001s |
| 300 | 0.006s |
| 500 | 0.017s |
| 1000 | 0.066s |
Scaling is approximately O(N^2), dominated by distance matrix computation.
The following table documents the key implementation details that were aligned during validation:
| Aspect | gait-dynamics-features | PyRQA |
|---|---|---|
| RR denominator | N*N (configurable via rr_exclude_theiler) |
N*N (always) |
| DET denominator | Sum of all diagonal line points (>=1) | Same |
| LAM denominator | Sum of all vertical line points (>=1) | Same |
| Theiler window in RM | Not applied to stored matrix; applied internally for diagonal analysis | Applied in matrix construction kernel |
| Vertical lines and Theiler | Full RM used (not broken by Theiler) | Same |
pip install PyRQA
python examples/validate_against_pyrqa.py