Skip to main content

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)
  "is_chirp":    True,                      # chirp excitation detected? gates step_flight (normal-log only)
  "frf_reliable": True,                     # is the FRF trustworthy? (coherent band fraction ≥ 0.10)
  "frf_coherent_frac": 0.30,                # fraction of the band clearing the coherence gate
  "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 + motor_orders)
  "noise_spectrum": {…},                   # gyro PSD raw vs filtered (see below)
  "filter_quality": {…},                   # empirical raw→filtered attenuation/preservation gauge
  "filter_model":   {…},                   # analytic filter response + group-delay budget (ms) from config
  "pid_balance":    {"roll": {"pct_p":…, "pct_i":…, "pct_d":…, "err_rms":…, "err_ratio":…}, …},
  "step_flight":    {"roll": {"small": {…}|None, "large": {…}|None}, …},  # amplitude-binned real-flight step
  "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)
  "mt": 1.2, "f_mt_hz": 28.0,              # peak complementary sensitivity max|T| (closed-loop resonance / delay 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.

Metadata

Release files for betaflight-chirp-core 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for betaflight-chirp-core 0.4.1
File Size Uploaded
betaflight_chirp_core-0.4.1.tar.gz 153.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for betaflight-chirp-core 0.4.1
File Interpreter ABI Platform
betaflight_chirp_core-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 301.8 kB

Release files / betaflight_chirp_core-0.4.1.tar.gz

Download URL betaflight_chirp_core-0.4.1.tar.gz
Size 153.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3ec3ab1ce45e147cf4454cf526fd7cc4c0c2fc379e86729bdfc5bdeaddd4f5cf
BLAKE2b-256 checksum
How to use checksums
a2f4d72fbf382176ee1eaa9fc398054c2ceb180016c3e9f1ae75735e1e480c7b
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 14, 2026.

Transparency log

Release files / betaflight_chirp_core-0.4.1-py3-none-any.whl

Download URL betaflight_chirp_core-0.4.1-py3-none-any.whl
Size 148.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
229ec46c57c428eda1fa071cdf216186638564f2b1a598277ab00e0bdc59a3ed
BLAKE2b-256 checksum
How to use checksums
01d0c9c5aecc4421d57998b5d5a5860c16da8b9aa34e49a4aab5395bd6dc7c4b
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 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.1 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page