{
  "id": "kalman2d_filter",
  "title": "Recursive 2-D Kalman filter \u2014 whole filter, 32 DSPs, 100 MHz on silicon",
  "blurb": "The capstone: measurement update + Joseph covariance update, looped with (x,P) state feedback, all through shared MACs + one reciprocal. It tracks a target with the covariance shrinking, and the WHOLE recursive filter closes 100 MHz on a real Arty A7-100T in 32 DSP48s \u2014 13% of the device, less than a third of what the unrolled measurement update alone cost. Scope (graded honestly): the two halves are machine-checked (forward-error bound + MMSE-optimality + Joseph PSD); the composition into 'implemented \u2248 optimal' is ARGUED, not yet a Lean theorem; and the shared scheduler/control is verified BIT-EXACT (301 silicon frames, Verilator shared==unrolled), not proven.",
  "emit_targets": 15,
  "proofs": [
    {
      "theorem": "kalman2_state_update_fxerr",
      "claim": "the fixed-point measurement update x'=x+K(z-x) is forward-error bounded through the inverse",
      "clean": true,
      "trail": "kalman2_state_update_fxerr.axioms.txt"
    },
    {
      "theorem": "matrix2_posterior_mean_mmse",
      "claim": "the posterior-mean estimate is MMSE-optimal (trace loss, per-component)",
      "clean": true,
      "trail": "matrix2_posterior_mean_mmse.axioms.txt"
    },
    {
      "theorem": "kalman2_joseph_psd",
      "claim": "the Joseph covariance step keeps P symmetric PSD for any gain \u2014 so recursing it is safe",
      "clean": true,
      "trail": "kalman2_joseph_psd.axioms.txt"
    }
  ],
  "checks": [
    {
      "quantity": "estimate converges to target",
      "value": "|err| = 0.0532",
      "relation": "<",
      "bound": "0.10",
      "holds": true
    },
    {
      "quantity": "covariance trace shrinks monotonically",
      "value": "0.4000 \u2192 0.0244",
      "relation": "monotone \u2193",
      "bound": "yes",
      "holds": true
    },
    {
      "quantity": "final trace(P) vs initial",
      "value": "0.0244 / 0.4000",
      "relation": "<",
      "bound": "0.1000",
      "holds": true
    }
  ],
  "silicon": [
    "kalman2d_filter",
    "kalman2d_gain_update",
    "joseph2_update",
    "seq_mac",
    "seq_mac_fw",
    "eml_reciprocal"
  ],
  "silicon_hw": {
    "board": "Arty A7-100T",
    "clock_mhz": 100,
    "anchors": [
      [
        "kalman2d_filter",
        "+0.715"
      ]
    ],
    "summary": "32 DSP48s for the WHOLE recursive filter (24 reciprocal + two shared MACs) = 13% of the device, vs 100 for the unrolled measurement update ALONE; 8/8 trajectory steps bit-exact, 247 cycles/step, trace(P) 0.39 \u2192 0.06.",
    "evidence_ref": "monogate-research/electronics_intake/kalman_filter_streaming_arty/evidence/FINDINGS.md"
  },
  "closing": "**Proved, simulated, and on silicon \u2014 graded honestly.** The pieces are machine-checked (forward-error bound `kalman2_state_update_fxerr` + MMSE-optimality `matrix2_posterior_mean_mmse` + Joseph PSD `kalman2_joseph_psd`, all sorryAx-free); the fixed-point bounds apply because the emitted per-product arithmetic is bit-identical (TESTED) to the unrolled dataflow they were proven for. Two links are honestly graded, not proven: the composition into 'implemented \u2248 optimal' is ARGUED (needs a gain=posterior-mean bridge lemma), and the shared scheduler/control is verified BIT-EXACT (301 silicon frames + Verilator), not proven. See docs/streaming_kalman_filter.md \u00a74b."
}