BanterLab

Acoustic communication testing and parameter tuning tool

BanterLab

BanterLab is an interactive testing and parameter tuning tool for the acoustic communication system. It provides a multi-node bus for digital loopback testing, over-the-air testing with real audio hardware, automated parameter sweeps, and result recording to a database.

Launching

From the hub application:

# Open BanterLab activity
hub --activity BanterLabActivity

# Load a test specification
hub --activity BanterLabActivity --open test/testBanter/specs/tier1_smoke/smoke_fsk_bus.json

# Load and run with auto-close
hub --activity BanterLabActivity --open spec.json --close-on-completion

# Override project name for database grouping
hub --activity BanterLabActivity --open spec.json --project my-experiment

Bus widget

The main interface shows a horizontally scrollable row of node widgets. Each node represents a BanterClient instance that can transmit and receive on a shared digital bus.

Node modes

Mode Description
Bus only TX output mixed into shared bus, bus fed to RX. No audio hardware.
Audio out TX output goes to a real speaker. Bus still feeds RX.
Audio in Real microphone feeds RX. TX goes to bus.
Audio both Full over-the-air: speaker out, microphone in.

Bus audio flow

Each TX node generates audio -> mixed into bus buffer
Bus buffer -> fed to each RX node's processRx()
Mixed output -> Speaker (if any node has audio out)

Thread safety: the bus audio callback runs on AudioPump's thread. All parameter changes from the UI are protected by mNodeMutex.

Device presence as a first-class invariant

Per the internal audio-device-presence spec, every TX or RX node that names a real hardware device must resolve to a present device before a run starts and for every iter that is dispatched. If the device is missing:

  • Pre-run: the test is refused. aborted("DEVICE_MISSING") is emitted on the BanterAutoTest signal bus, the per-node banner turns red with reason DEVICE_MISSING, and the queued-runner skips the offending row and continues to the next row in a test set.
  • Mid-run: the iter scheduler is paused (multi-reason pause; the existing AUDIO_UNHEALTHY reason continues to use the same atomic). The banner turns red. On replug, the node calls syncAudioDevices() to recreate the audio node, the pause clears, and the next iter fires fresh.

The bus and off route sentinels never require a device; they are first-class operator choices. See diagnose-missing-audio-device for the recovery procedure.

Test specifications

Test specs are JSON files that define parameter configurations and test execution settings. Two formats are supported.

Version 2 (single test)

A single test configuration with one set of parameters and one auto-test run:

{
    "version": 2,
    "nodes": {
        "tx": { "name": "Alice", "audioMode": true },
        "rx": { "name": "Bob", "audioMode": true }
    },
    "parameters": [
        { "id": "fsk_baudRate", "current": 300, "sweepMode": "fixed" },
        { "id": "fsk_baseFreq", "current": 2000, "min": 1000, "max": 3000,
          "sweepMode": "stepped", "numSteps": 10 }
    ],
    "autoTest": {
        "testName": "my_test",
        "connectionString": "results.db",
        "codec": "FSK",
        "payload": "Hello World",
        "maxIterations": 100,
        "ncores": 4,
        "settleTimeMs": 1000,
        "timeoutPerTestMs": 60000,
        "quitOnComplete": false
    }
}

Version 3 (test set)

Multiple named configurations that run sequentially, each with their own parameters and iteration counts:

{
    "version": 3,
    "name": "AGC Characterization",
    "description": "Sweep AGC parameters over air",
    "configs": [
        {
            "name": "baseline_no_agc",
            "iterations": 20,
            "payload": "HELLO WORLD",
            "codec": "FSK",
            "parameters": [
                { "id": "agcMode", "current": 0, "sweepMode": "fixed" }
            ]
        },
        {
            "name": "agc_maxgain_sweep",
            "iterations": 50,
            "payload": "HELLO WORLD",
            "codec": "FSK",
            "parameters": [
                { "id": "agcMode", "current": 2, "sweepMode": "fixed" },
                { "id": "agcMaxGain", "current": 500, "min": 10, "max": 2000,
                  "sweepMode": "stepped", "numSteps": 9 }
            ]
        }
    ]
}

When loaded via --open, the test set table shows all configs with status indicators (pending, running, completed).

Parameter sweep modes

Mode Description Example
fixed Single value, no variation baudRate = 300
stepped Grid of evenly-spaced values baudRate = [25, 89, 153, ..., 600] (10 steps)
random Uniform random within range agcMaxGain in [10, 2000]

When multiple parameters use stepped mode, the total iteration count is the product of all step counts.

Available test specs

Located in test/testBanter/:

Tiered spec corpus

Specs live under test/testBanter/specs/ in four tiers. See test/testBanter/specs/README.md for the full convention.

Tier Directory Purpose
1 — smoke tier1_smoke/ Build-gate. Per-codec bus loopback at validated baseline. Should always pass at near-100% decode.
2 — codec sweep tier2_codec_sweep/ Per-codec parameter ranges over bus. Detects codec regressions.
3 — OTA ablation tier3_ota_ablation/ Feature on/off matrix, real audio, static mic rig. Drives the OTA decode-rate ceiling work.
4 — RL training tier4_rl_training/ Search spaces for BanterRLController. Not pass/fail; measure reward over iterations. Reserves a physicalAxis block for robot-controlled axes.

Tier 1 ships with one smoke spec per codec (smoke_fsk_bus.json, smoke_ofdm_bus.json, smoke_dpsk_bus.json, smoke_css_bus.json, smoke_mcfsk_bus.json). Higher tiers are populated as work progresses.

Test execution engine

Interactive mode

BanterAutoTest runs tests with settle time between iterations. Connected to the UI for real-time feedback.

Headless mode

BanterTestEngine runs batch tests without UI. Supports multi-threaded execution:

  • Each thread creates independent BanterBus + 2 BanterClients
  • Zero shared state between threads
  • Linear speedup with core count
  • Deterministic via master seed

Results database

Test results are stored in SQLite (or PostgreSQL) via BanterTestDB. Both interactive and headless tests write to the same unified schema:

Table Purpose
test_sets Collection metadata
test_configs Per-config parameters and iteration count
sessions Session: config + code version + git info + seed
runs Individual iterations: score, decode success, stats, parameter values

The runs table includes 72 parameter columns (one per parameterRegistry() entry, e.g. fsk_baseFreq, txAmplitude, agcMode) added automatically via ALTER TABLE ADD COLUMN. Interactive tests populate these from the parameter table; headless tests leave them NULL (parameters are reconstructable from sweep + seed). An optional diagnostics_json TEXT column stores extended RX diagnostics (chirp detection, channel response, audio health) from interactive tests.

Connection string format: sqlite:///path/to/file.db or bare file.db.

Headless CLI testing

To run a test set headless, use banter-bench test-set. It loads a test set or test JSON, runs every config on all cores, and writes the runs to a results database in the lab's schema:

# Run every config of a test set; the results go to fsk_results.db next to the file
banter-bench test-set --file test/testBanter/specs/tier1_smoke/smoke_fsk_bus.json

# Write the results somewhere else
banter-bench test-set --file my_sweep.json --db /tmp/sweep.db

# Run specific test functions
./testBanter testBanterBusRoundTrip testBanterBusFEC testBanterBusParamSweep

# Run an OTA ablation set through the lab (the shell runner that used to
# do this is gone; the specs it named are, too)
hub --activity BanterLab --open test/testBanter/specs/tier3_ota_ablation/ablation_dsp_features.json --close-on-completion

Key parameters

FSK codec parameters

Parameter Range Default Description
fsk_baseFreq 500-4000 2000 Center frequency (Hz)
fsk_freqSeparation 400-2000 800 Mark-space gap (Hz)
fsk_baudRate 10-600 300 Symbol rate
fsk_toneShaping 0-0.5 0.1 Raised cosine ramp fraction
fsk_goertzelWindow 0.3-1.0 0.85 Detection integration window
fecEnabled 0/1 0 Convolutional FEC + interleaver
diffEncoding 0/1 0 Differential encoding

AGC parameters

Parameter Range Default Description
agcMode 0-4 0 0=off, 1=normal, 2=freeze, 3=blockRms, 4=primerLocked
agcMaxGain 1-2000 500 Maximum gain multiplier
agcTargetPeak 0.1-1.0 0.8 Target peak amplitude
agcPrimer 0/1 0 Enable 300ms noise primer
agcPrimerMs 50-1000 300 Primer duration

Pipeline feature flags

Parameter Default Description
bandpass 0 Post-chirp bandpass filter
coherentSumming 0 N-chirp coherent summing
chirpSequenceDetector 0 False positive rejection
adaptiveChirpThreshold 0 Dynamic detection threshold
subSampleChirpTiming 0 Parabolic peak interpolation
adaptiveEQ 0 NLMS-trained equalization
noiseReduction 0 FFT spectral subtraction
cfoCorrection 0 Clock offset correction
txRepeatCount 1 Repeat-and-vote transmissions

Source files

Component Location
BanterBusWidget src/libs/libbanter/banter/lab/BanterBusWidget.hpp/.cpp
BanterNodeWidget src/libs/libbanter/banter/lab/BanterNodeWidget.hpp/.cpp
BanterAutoTest src/libs/libbanter/banter/lab/BanterAutoTest.hpp/.cpp
BanterTestEngine src/libs/libbanter/banter/lab/BanterTestEngine.hpp/.cpp
BanterTestDB src/libs/libbanter/banter/lab/BanterTestDB.hpp/.cpp
BanterTestSpec src/libs/libbanter/banter/lab/BanterTestSpec.hpp/.cpp
BanterParamSet src/libs/libbanter/banter/lab/BanterParamSet.hpp/.cpp
BanterTransport src/libs/libbanter/banter/BanterTransport.hpp/.cpp
BanterLinkStats src/libs/libbanter/banter/BanterLinkStats.hpp
BanterMcsTable src/libs/libbanter/banter/BanterMcsTable.hpp
Test specs test/testBanter/specs/tier{1,2,3,4}_*/*.json
In this section
Topics
reference communications testing banter banter-lab