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.8.tar.gz (101.5 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.8-py3-none-any.whl (103.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: betaflight_chirp_core-0.1.8.tar.gz
  • Upload date:
  • Size: 101.5 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.8.tar.gz
Algorithm Hash digest
SHA256 013771da2212e1d67625bd8831cda7532060617158bbec7330d2f0b396207e1b
MD5 9344a09463b93a863fe1049d28cc823f
BLAKE2b-256 fdf606ce58d719f5811db1cd1df7121241ff26a9df33d23c80d1b3fd37465fcf

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for betaflight_chirp_core-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 61ab79744734ca7aac8c739fda45fd57960b218e2b647beb7994053de2538d79
MD5 b8ee3add823f86ab9da690379b9bb477
BLAKE2b-256 16a6fd219dda134e6ce3b9b47f69ff669b1bb9ec0928ffb03fd6faa53580f6df

See more details on using hashes here.

Provenance

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