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.6.tar.gz (92.3 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.6-py3-none-any.whl (94.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: betaflight_chirp_core-0.1.6.tar.gz
  • Upload date:
  • Size: 92.3 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.6.tar.gz
Algorithm Hash digest
SHA256 a7f3090d70192e40ea589a3301dcd60c2d849f3e936d734cbc6da09c51bc8655
MD5 65d47f317731a836a9363d2fa122ecdc
BLAKE2b-256 3138a34bbc5d1d6da2f03eb410064a4940c9c34b5c089005b65eaf54c22a2d6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for betaflight_chirp_core-0.1.6.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.6-py3-none-any.whl.

File metadata

File hashes

Hashes for betaflight_chirp_core-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 11035a09afcfef62262e48c1fae92b3a3d4377665cd491a2df5e4dfcfbdc9165
MD5 dfe5678c294e2c8c2847d0808131c67e
BLAKE2b-256 b73ce81c558f76cfc1d6e7bdd935cf8a6b8b44eb2609f4e805b6b918681854a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for betaflight_chirp_core-0.1.6-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