Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fit-align

Collection of scripts for BEStie ride data quality analysis

Problem statement

BEStie acts as a protocol translator between Bosch LDI and Bluetooth FTMS. This adds an extra radio hop between Bosch ebike and fitness data recording device (cycling computer, watch, etc.). Bluetooth Low Energy works in discrete connection windows which for multi hop solution introduces jitter.

As a result existing data quality analysis tools such as Compare the watts or Quantified Self do not know how to align ground truth file from Bosch ebike with ride recorded using BEStie and falsely indicate bad data quality (<80% correlation). This is result of strict assumption that there's no jitter and each analyzed file is coming from a single hop system.

We needed a better solution.

How the data alignment works

fit_align.py on the other hand knows exactly how FTMS message is constructed. It scans for random jitter within set time window for ech power sample and applies that to power and cadence data. This reflects power and cadence being updated atomically. Separate jitter scan is done for speed data because speed is sent in a separate time interval and acts as 'no more data' packet for power and cadence.

As a result typical correlation is around 99%. Remaining 1% accounts for situations where multiple samples arrive within a single 1s sampling window (.fit file limitation).

AI generated code disclosure

This project's code was generated by Deepseek v4 fed with statistical knowledge primer. Results were verified by adversary expert agent, comparing against manually aligned data set and artificial data runs.

Usage

Install dependencies

python3 -m venv ./.venv
./.venv/bin/pip3 install -r requirements.txt
. ./.venv/bin/activate

Run fit_align.py - align and compare data from .fit files

Usage: ./fit_align.py --output-dir out_fit --global-shift 1 --jitter 2 bosch.fit bestie.fit

This will compare ground truth data from Bosch Flow app in bosch.fit against a ride recorded via BEStie in bestie.fit and store output in out_fit/ folder. BEStie data will have a global shift of 1s and alignment will be done within 2s jitter window.

Resulting output looks like:

Reading Bosch .fit: bosch.fit
Reading comparison .fit: bestie.fit
  Bosch records:     10582 raw rows
  Bosch CSV:         out_fit/bosch_converted.csv  (10582 rows)
  Comparison CSV:    out_fit/comparison_converted.csv  (6252 rows)
  Bosch collapsed:   5566 unique timestamps
  Comparison:        6252 rows (2026-07-03 13:05:04+00:00 .. 2026-07-03 15:04:04+00:00)

  Global shift: +1s (manual)
  Running per-sample jitter correction (power: ±2s, speed: ±2s) ...

============================================================
FIT ALIGN — Correlation Summary
============================================================
  Global shift:     +1s  (mean ρ = 0.0000)
  Matched samples:  5566

  Param             ρ        MAE  Samples
  ────────────────────────────────────
  Power        0.9956     0.3W     3930
  Cadence      0.9879     0.2rpm     1787
  Speed        0.9936     0.3m/s     5045
============================================================

  Metric               |Δ|≤1         1<|Δ|≤2         2<|Δ|≤3           |Δ|>3
  ─────────────────────────────────────────────────────────────────
  Power        3909 ( 99.2%)     33 (  0.8%)      0 (  0.0%)      0 (  0.0%)
  Cadence      1774 ( 98.3%)     30 (  1.7%)      0 (  0.0%)      0 (  0.0%)
  Speed        4553 ( 90.2%)    492 (  9.8%)      0 (  0.0%)      0 (  0.0%)

============================================================

  Summary: out_fit/correlation_summary.txt

  Matched CSV: out_fit/matched_output.csv  (5566 rows)
  Saved: alignment_zoom.png
  Saved: alignment_full.png

  Done. Output directory: out_fit

most important part is correlation table:

Param             ρ        MAE  Samples
  ────────────────────────────────────
  Power        0.9956     0.3W     3930
  Cadence      0.9879     0.2rpm     1787
  Speed        0.9936     0.3m/s     5045

showing 99.56% correlation for power, 98.79% for cadence and 99.36% for speed. Values are also translated into error estimates (0.3W, 0.2RPM, 0.3m/s)

Artifacts in output folder:

  • correlation_summary.txt - correlation data tables
  • bosch_converted.csv and comparison_converted.csv - input .fit data converted to CSV
  • matched_output.csv aligned data set
  • alignment_zoom.png and alignment_full.png charts showing both data sets on top of one another

About

Collection of scripts for BEStie (https://github.com/bestie-org/BEStie) ride data quality analysis

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages