Skip to main content

Betaflight closed-loop chirp / blackbox analysis core — decoder, FRF/Bode, step response, spectral, HTML report.

Project description

betaflight-chirp-core

PyPI Python License

The compute core for Betaflight closed-loop chirp / blackbox analysis: decode a .bbl/.bfl, estimate the frequency response (FRF/Bode), step response and noise spectrum, and render a self-contained HTML report.

betaflight-chirp-core knows nothing about MCP, HTTP, Docker, the CLI or the filesystem. Input: bytes. Output: objects + HTML.

Install

pip install betaflight-chirp-core

Or pin an exact commit straight from git:

pip install "betaflight-chirp-core @ git+https://github.com/SebGalina/betaflight-chirp-core@v0.1.5"

Usage

from betaflight_chirp_core import decode, analyse_log, build_report, run

# low-level: decode -> analyse -> render, step by step
df, fs, config = decode(open("log.bbl", "rb").read())
# df: decoded frames (pandas)   fs: loop/log rate (Hz)   config: PID/filter settings
a_pass = analyse_log(df, fs, config)        # one log  -> one self-contained pass dict
html   = build_report([a_pass])             # passes   -> self-contained HTML report

# single call: decode + analyse + report in one shot
result = run(open("log.bbl", "rb").read())
result.metrics       # == result.raw["axes"] — per-axis indicators, render as-is
result.report_html   # the self-contained HTML report (a full <html> string)
result.raw           # the complete pass dict (see Output below)

Importing the package is light: numpy/scipy/pandas load lazily, only when an analysis runs. from betaflight_chirp_core import decoder stays stdlib-only, so decode-only callers pull no heavy deps.

Output

Four return surfaces, from raw to ready-to-render:

Call Returns Is
decode(bytes) (df, fs, config) pandas frames, log rate (Hz), header tune dict
analyse_log(df,…) pass dict one log → all indicators (below)
build_report(passes) str one self-contained <html> page
run(bytes) AnalysisResult .metrics (= raw["axes"]), .report_html, .raw (pass dict)

The pass dict

analyse_log() / result.raw — one self-contained analysis of one log:

{
  "timestamp":   "2026-06-12T09:00:00",   # ISO, when analysed
  "file":        "log.bbl",
  "sample_rate_hz": 8000,                  # loop/log rate
  "input_col":   "debug[3]",               # FRF input column (chirp setpoint channel)
  "band_hz":     [1.0, 1000.0],            # analysed frequency band [fmin, fmax]
  "throttle_max": 1850,                    # peak flying throttle (or None)
  "config":      {},                      # PID / filter settings parsed from the header
  "axes":        {"roll": {}, "pitch": {}, "yaw": {}},   # per-axis, see below
  "tune_score":  {"overall": 76.0, "grade": "B", "axes": {"roll": {"score": , "subs": {}}}},
  "throttle_map":   {},                   # resonance vs throttle (heatmap payload)
  "noise_spectrum": {},                   # gyro PSD raw vs filtered (see below)
  "spectrogram":    {},                   # chirp sweep time×freq (heatmap payload)
  "synthesis":      [{"fr": "...", "en": "..."}, ],   # plain-language read, bilingual
  "filter_suggestions": [  ],             # filter change hints (only when config present)
  "noise_suggestions":  [  ],             # noise/peak hints
}

Per axis (axes["roll"] etc.) — the Bode + step + verdict for one axis:

{
  "band_hz": [1.0, 1000.0], "n_samples": 48000,
  "freq": [...], "gain_db": [...], "phase_deg": [...], "coherence": [...],  # Bode curves
  "peaks": [  ],                          # gain-resonance peaks in band
  "crossover_hz": 32.0,                    # 0 dB crossover
  "phase_margin_deg": 41.0, "phase_margin_unc_deg": 6.0,
  "ms": 4.8, "f_ms_hz": 70.0, "pm_guaranteed_deg": 34.0,   # peak sensitivity (robustness)
  "step": {                                # setpoint→gyro step response
    "t_ms": [...], "y": [...], "y_lo": [...], "y_hi": [...],
    "metrics": {"overshoot_pct": 12.0, "rise_ms": 18.0, "delay_ms": 3.0,
                "settle_ms": 60.0, "peak": 1.12},
  },
  "diagnosis": [  ], "step_diagnosis": [  ],   # short verdict strings
}

tune_score.grade is an A–F letter (A ≥ 85 … F < 40); overall is the mean of the per-axis scores. noise_spectrum carries freqs, raw_db/filt_db curves (0 dB = raw broadband floor) and a peaks list with above_floor_db / resid_db (filtered residual) / atten_db (raw→filtered cut) per peak.

Array fields (freq, gain_db, *_db, …) are JSON-ready (rounded floats), so the whole pass dict serialises straight to a front-end or a history store. For the exact nested fields, read analysis/chirp.py:build_pass.

Layout

Module Role
decoder.py pure-Python .bbl frame decoder (stdlib only)
signal.py decode_dataframe (bytes → frames), sample_rate, active_mask
config.py PID / filter settings parsed from the header
analysis/ chirp (FRF/Bode), spectral, step response
report.py self-contained HTML report (inlines the renderer assets)
report_assets/ shared report renderer (chirp_report.{js,css} + glossary/strings JSON) — inlined by report.py, mountable by a web front

Develop

pip install -e ".[test]"
pytest

Tests run on .bbl fixtures in tests/data/. One GPS-free log (8.bbl) ships so the suite runs out of the box; drop your own logs there for more coverage. Every other .bbl/.bfl is git-ignored — never commit a real flight log, it carries GPS home-point coordinates (only 8.bbl is whitelisted, after verifying it has no GPS frame).

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

betaflight_chirp_core-0.1.7.tar.gz (96.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

betaflight_chirp_core-0.1.7-py3-none-any.whl (99.0 kB view details)

Uploaded Python 3

File details

Details for the file betaflight_chirp_core-0.1.7.tar.gz.

File metadata

  • Download URL: betaflight_chirp_core-0.1.7.tar.gz
  • Upload date:
  • Size: 96.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for betaflight_chirp_core-0.1.7.tar.gz
Algorithm Hash digest
SHA256 89721c75bc15db1bd95d525ad7e842bb26cfc8051053baf0a99a827662a4e770
MD5 f6d7b45f249544b78b76d268b7904bf1
BLAKE2b-256 bc93ebe84d19836670c6432758195709a21a13f2f4e559c810e87979b95cef3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for betaflight_chirp_core-0.1.7.tar.gz:

Publisher: publish.yml on SebGalina/betaflight-chirp-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file betaflight_chirp_core-0.1.7-py3-none-any.whl.

File metadata

File hashes

Hashes for betaflight_chirp_core-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 b94763b4e82bf4fa3bebe2c127b7dfac7f29dfa672e5642404ed7c644ad16109
MD5 a5f1a40266a8018e5ec7eabdbe1721ae
BLAKE2b-256 d60eb2f052897c19adaf78b71d05b017f3afd38ba35c04d71e71fdff2cc94d34

See more details on using hashes here.

Provenance

The following attestation bundles were made for betaflight_chirp_core-0.1.7-py3-none-any.whl:

Publisher: publish.yml on SebGalina/betaflight-chirp-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page