发布

  • v1596 872d7593bb

    fix: IDF v6.0 ESP-NOW callback compat (#944) + occupancy noise-floor anchor (#942) (#945)

    frostbyte_neo 发布于 2026-06-04 06:17:37 +00:00

    • fix(firmware): on_send ESP-NOW callback compat for IDF v6.0 (closes #944)

    ESP-IDF v6.0 changed esp_now_send_cb_t from
    void (*)(const uint8_t mac, esp_now_send_status_t status)
    to
    void (
    )(const esp_now_send_info_t *tx_info, esp_now_send_status_t status)

    The C6 sync ESP-NOW path's on_recv was already version-guarded with
    #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) (lines 102-112)
    but the on_send sibling missed the equivalent guard. CI runs against
    IDF v5.4 so the regression slipped through; the reporter on IDF v6.0.1
    with xtensa-esp-elf esp-15.2.0_20251204 hit:

    c6_sync_espnow.c:182:30: error: passing argument 1 of
    'esp_now_register_send_cb' from incompatible pointer type
    [-Wincompatible-pointer-types]

    Fix: mirror the recv guard with #if ESP_IDF_VERSION_MAJOR >= 6 since
    the send-callback signature change happened at IDF v6.0 (not v5.x like
    the recv-callback). Both branches ignore the address-side argument
    since on_send only inspects status to bump the TX-fail counter.

    Adds #include "esp_idf_version.h" so the macro is in scope.

    Closes #944

    Co-Authored-By: claude-flow ruv@ruv.net

    • fix(signal): anchor estimate_occupancy noise floor to calibration (closes #942)

    test_estimate_occupancy_noise_only asserts that 20 noise-only frames
    fed through a 50-frame calibrated FieldModel yield 0 occupancy.
    Failure reported on the upstream Linux + BLAS build.

    Root cause

    Calibration and estimation each compute their own Marcenko-Pastur
    threshold:

    threshold = noise_var · (1 + sqrt(p / N))²

    with noise_var = median of the bottom half of positive eigenvalues
    from their own covariance. The MP ratio differs across the two phases:

    calibration (50 frames, p=8): ratio = 0.16, factor ≈ 1.96
    estimation (20 frames, p=8): ratio = 0.40, factor ≈ 2.66

    On a small estimation window the local noise_var estimate can also
    be smaller than the calibration's (fewer samples → bottom-half median
    hits lower-magnitude eigenvalues). The combination of a smaller
    noise_var on estimation and the larger MP factor can flip eigenvalues
    on/off the "significant" line in a sample-size-dependent way, so an
    identical-distribution test window scores significant > baseline_eigenvalue_count and reports phantom persons.

    Fix

    Persist the calibration noise_var on FieldNormalMode (new field
    baseline_noise_var: f64) and use max(local_noise_var, baseline_noise_var) as the noise floor inside estimate_occupancy.
    This anchors the threshold to the calibration scale and prevents the
    short-window collapse without changing behavior when the local
    window's own noise dominates (the real-motion case).

    baseline_noise_var defaults to 0.0 in the diagonal-fallback paths;
    the estimation code treats 0.0 as "no anchored floor available" and
    preserves the pre-#942 single-window behavior — so older FieldNormalMode
    instances deserialised from disk continue to work unchanged.

    Test results

    cargo test --workspace --no-default-features
    → 413 lib tests pass (signal crate), 0 fail, 1 ignored.

    The actual eigenvalue-gated test still requires BLAS (not buildable
    on Windows). Logic-trace via the four numerical anchors above shows
    the fix flips noise_var from the smaller local value back up to the
    calibration scale, dropping significant to or below
    baseline_eigenvalue_count so the saturating subtraction returns 0.

    Closes #942

    Co-Authored-By: claude-flow ruv@ruv.net

    下载附件