Asking the fleet what it is doing…
monad-knowledge Wi-Fi sensing lab · FIIT STU
Campaign

The floorplan as a placement oracle — where do APs both cover the space and count the crowd, across 56 floors?

c-placement-oracle · sionna-csi-runner, walk-notebook

Archive snapshot, as of 18 h ago — the run corpus is rebuilt once a day, so this page is not a live reading. The fleet panel is the live one; it refreshes every 30 s.

Sessions

state
Session State Runs Synthesis Criticism Figures Verdict
98HDFER9 2026-07-13T15:49 finished 0 POWERED GO: across 57 real floors counting-optimal != coverage-optimal (divergence 0.718, CI[0.680,0.754], CI excludes 0.15), submodular+greedy-bound 57/57. Ray-traced I(C;Phi) discriminates anchors where occupancy varies (28.5 dB/person). Surrogate+dense-grid (C4/C5) is the remaining follow-on.
QBF585JX 2026-07-13T14:43 finished 7 6 GO on the go/no-go gate: counting-optimal != coverage-optimal on 6/6 topology-diverse floors (mean placement divergence 0.61 >> min_effect 0.15), coverage submodular + greedy beats 1-1/e everywhere. Stage-2 mechanism resolved; ray-traced I(C;Phi) (Stage 3-4) + powered 56-floor corpus deferred to /campaign-systematic.

Brief

Question

We own a generative twin that turns a floorplan + a crowd into ray-traced CSI (c-multifloor-fsm-observatory). Point it at a question about the building: given this floor, where do I place the access points so they (a) COVER the space, (b) SEE moving people well enough to COUNT them, and (c) ideally do both — and let the walking simulator generate the crowds that answer it. Output: a placement tool that ranks AP layouts for operation (deployable, cost-bounded), for experiment (maximally count-informative capture), or for the constrained both-worlds sweet spot. Run it across 56 ResPlan floors of different topology, with realistic persona-driven crowds, and compute the counting-vs-coverage Pareto per floor.

The novelty wedge (be precise). Placement-for-sensing is not virgin territory; wang2025_2c42 (IEEE IoT-J 2025) scores hand-designed layouts with a geometric surrogate (SSNR→RSQ) fit to static seated targets, and never optimises against exhaustive search because it has no generative crowd. The defensible contribution is the evaluation model: we score a layout by the count-estimation informativeness I(C;Φ) of CSI our twin actually ray-traces, marginalised over crowds the walking simulator actually generates — dynamic flows through doors and corridors, not seated grids. This is wang2025's Open Question 6 verbatim ("can RSQ extend from static-seated to dynamic/flowing crowds, and does the metric predict counting error for moving individuals?"), answered generatively. RSQ is the geometric baseline we beat — or honestly fail to beat, an outcome worth stating up front. Nobody couples pedestrian-dynamics → ray-traced CSI → placement optimisation in one loop over real multi-floor geometry with a dual operational/experimental deliverable and a computed counting-vs-coverage Pareto. That composite is the wedge.

Framing discipline. Sim-authored evidence, on the same knife-edge as every sim result in this project (campaign-rigor-audit). The tool RANKS placements; it is a hypothesis generator until one real-hardware floor confirms the ranking. Stage 2 coverage is first-order LOS; Stage 3+ coverage is ray-traced but clean-tensor (Sionna PHY has no impairment classes — the impaired path is a bolt-on, ip110-sionna-rt-upgrade). No measured detection-rate claim anywhere.

Why now — ~80% built, never wired into a placement loop

Piece Asset Gives us
Crowd generator walk-notebook + IP-107 agenda/FSM engine persona OD flows door↔room↔corridor on real geometry
CSI generator sionna-csi-runner (IP-110 Sionna-RT) ray-traced CSI and coverage/signal maps for arbitrary emitter placement
Coverage optimiser coverage_submodular.py greedy set-cover, 1−1/e bound, counting-vs-coverage Pareto
Placement kernel placement_oracle.py (this campaign) measured I(C;Φ) + surrogate + 3-variant constrained selection
Floor substrate 110 ResPlan floors in PostGIS walls, doors, occupiable, candidate grids
Visual surface monad_knowledge_qgis, /map/ atlas, walk trajectory.html render + replay the 5 decision layers

IP-110's unlock makes it cheap enough to attempt: Sionna-RT emits coverage/signal maps as native output, so the propagation-honest coverage layer comes for free per candidate set, replacing the LOS proxy coverage_submodular flags in its own docstring.

The formal object

Candidate site set V (a grid over occupiable space), placement S ⊆ V, |S| ≤ k. The walking simulator induces P(X) over crowd states X (positions + count C), driven by persona OD flows. Two objectives, one honest tension:

  • Coverage (breadth) F_cov(S) = footfall-weighted fraction of the floor with ≥1 propagation-covered link from S. Weighted set-cover → monotone submodular → greedy gets 1−1/e (Pillar 4b, spectral-count-and-submodular-coverage).
  • Counting (depth) F_cnt(S) = I(C ; Φ(H_S)), the mutual information between crowd count and the CSI feature at the chosen links, expectation over P(X), estimated by running the twin. Information is NOT submodular — a second link at a busy hub can be more-than-additively useful or redundant depending on multipath. So greedy is a heuristic here, checked against exhaustive k-subsets where feasible.

The clean guarantee lives on coverage; on counting the interesting science is where the two disagree — covering the corridors people walk (breadth) is a different placement from concentrating links on the busy hub for count SNR (depth). Three deliverables from one front: operational (front knee under deployment constraints + comms co-objective), experimental (count-informativeness maximiser under research constraints), both-worlds (the deployable-yet-scientific intersection).

What the supervisor does — five stages, multi-agentic

  1. Substrate & candidate grid — stage each floor's floor_geometry.json (envelope + wall WKT) from PostGIS; build the candidate grid V (auto-grid over occupiable, mountable flag = within reach of a wall). Topology-stratify the 56 floors by room count / area.
  2. Persona crowds (sim-runner fan-out, cheap ~6 s/floor) — walk-notebook kind: agendas with the five personas, seeds {0,1,2}. Honour walkable QC; drop hard-fails as geometry findings. Produces trajectory.parquet (→ footfall + per-frame count) + replayable trajectory.html.
  3. Cheap Pareto, corpus-wide (coverage_submodular, pure numpy) — coverage LOS proxy, counting-depth proxy, submodularity audit, greedy vs optimal, Pareto + corner Jaccard across all 56 floors. The go/no-go economics live here: if counting-optimal never tracks the flow, or the gap is nil everywhere, the expensive stages are not worth firing.
  4. Propagation-real kernel, SPARSE (sionna-csi-runner, expensive, verify floors only — test-lab-synth-floor-0, resplan-1374-floor-0, resplan-12439-floor-0) — ray-traced coverage/signal maps replace the LOS proxy; per-candidate CSI feeds the placement_oracle measured I(C;Φ) with bootstrap CIs. The diary's cheap gate: does the kernel separate good from bad links at all?
  5. Surrogate + verify — fit RSQ-style geometric surrogate + learned correction to the sampled I(C;Φ); report held-out rank fidelity; run greedy/Pareto over the full-grid surrogate; then re-run the top-k layouts with a full coupled ray-trace to confirm the ranking. Never trust the surrogate unverified.
  6. Deliverables + replay — the three placements per floor → placement_result.parquet; the five-panel figure per floor; the cross-floor operational-vs-experimental Jaccard; a /map/ 3-D replay of a chosen layout with agents walking through it (analysis-writer synthesis under the sim-storytelling-contract).

Personas (the realistic movement the counting objective needs)

Seven floor-agnostic archetypes — a cafeteria/library story over a busy period — each an IP-107 agenda that enters near a floor edge, does something, and leaves (after: leave), so the count ramps/spikes/drains. Configs:

  • exp_csi_crowd/config/oracle-agendas.yaml — CANONICAL coupled crowd (walk → CSI + BLE), with a seated → network_traffic hook so seated devices advertise/burst (emitters.parquet).
  • exp_csi_crowd/config/oracle-agendas-placement.yaml — the placement variant, hooks OFF (clean reference-Tx → candidate-Rx links; BLE still from the same CFR) — see the fork note under Execution.
  • walk_notebook/config/personas-placement-oracle.yaml — walk-only mirror for replay/inspection.
Persona Behaviour Traffic
long_stay_worker enter → claim desk → long focused session → leave seated ⇒ BLE + WiFi
study_group (cohesive) arrive together → adjacent seats at one table → study → leave together seated ⇒ traffic
cafeteria_patron queue → order area → sit + eat → leave seated ⇒ traffic
browser shelf → shelf → brief skim-seat → leave light/intermittent
through_busy cross floor edge-to-edge, never seats radio-quiet
through_quiet orthogonal passer-by stream radio-quiet
quick_visitor pop in to one area → straight back out none

The "with or without traffic" distinction falls out of behaviour, not a flag: only seated personas fire the network_traffic hook. The count MUST vary for I(C;Φ) to exist — a static full-occupancy cast pins the count (H(C)=0) and collapses the estimand to a silent-null zero; hence every persona has ingress + egress and staggered arrivals. Per-floor door-precise agendas (spawn_door + kind: room/door legs) are a crowd-choreographer refinement for the verify floors; the region/seat library is the corpus-wide default.

Figure render request

placement_oracle five-panel per floor: (1) candidate grid (mountable vs mid-room), (2) persona footfall surface, (3) coverage layer (LOS or Sionna signal map), (4) per-candidate I(C;Φ) heat, (5) chosen APs for operational/experimental/both. Cross-floor: the corner-Jaccard distribution and the blindspot/off-objective-sacrifice-vs-topology scatter.

Out of scope

  • Hardware detection rate — the field defeater is IP-106 / the IP-112 AX210-Pi5 anchor. This campaign licenses which floor to instrument, not the operational claim.
  • The flagship FIIT floorfiit-library-floor-0 is not sim-ready (fiit-library-floor-not-sim-ready); ResPlan + test-lab-synth only until the QGIS reconcile.
  • Full 56×full-grid ray-trace — combinatorial and deliberately never run; the surrogate+verify design is the tractability contract.

Expected interpretation

  1. Counting-optimal tracks the doors/corridors, coverage-optimal spreads to the geometric centre → the dynamic-flow answer to wang2025's static-seated result; the corner Jaccard is materially < 1 and the gap widens with corridor-heavy topology. Feeds the System-Design placement chain.
  2. The gap is nil / counting-optimal == coverage-optimal everywhere → a clarifying negative: placement is an area/anchor-budget problem, not a counting-geometry one; simplifies the story and kills the expensive stages cheap.
  3. A floor fails walkable QC → geometry-import finding for that ResPlan floor; report and drop.
  4. Surrogate held-out rho is poor → the loop is "expensive RSQ"; fall back to the measured sparse set and report the amortisation as not-yet-solved.

Risks / honest limits

  • Sim-authored evidence — hypothesis generator until one real-hardware floor confirms the ranking. Frame every claim that way (campaign-rigor-audit, synthetic-csi-sim-to-real-transfer).
  • Non-submodular counting — greedy guarantee is coverage-only; counting axis checked against exhaustion on small k.
  • Compute — ray-tracing is the cost; surrogate+verify is the tractability plan. Poor surrogate ⇒ degrade to expensive-RSQ, reported honestly.
  • Fidelity gap — Sionna PHY has no impairment classes; placement optimised on clean tensors may not match impaired hardware. The anchored floor tests exactly this.
  • Geometry readiness — ResPlan floors usable now; FIIT blocked.

Execution

Execution log — C4/C5 dense grid + rich personas, run fully locally (2026-07-13, M1 Max)

Run as direct sim run executions (not campaign sessions), driven by helper modules under monad_knowledge/notebooks/python/: oracle_grid_register.py (dense candidate grid → PostGIS experiment csi-oracle-grid-<floor>), oracle_grid_reduce2.py (multi-seed reduce → I(C;Φ) + Pareto + surrogate), oracle_grid_materialize.py (chosen APs → PostGIS), oracle_grid_gallery2.py.

  • Stage 0-2 (earlier): cheap coverage↔count Pareto corpus-wide — divergence 0.718, CI [0.680,0.754], n=57; counting-opt ≠ coverage-opt on 57/57. GO.
  • C4/C5 dense grid, 6 floors (12439 [16 cand, 3 seeds] · 1374 · 16157 · 2605 · 12853 · 1046): count ranges 1–10 … 1–22; per-candidate I(C;Φ) spreads 0.11–0.60 nats; coverage-greedy = 1.00 ≥ 1−1/e on all; operational vs experimental placements disjoint (Jaccard 0.00–0.50).
  • #3 multi-seed: 12439 at 3 seeds → per-candidate MI ranking only moderately stable (Spearman ρ = 0.41); average over seeds before trusting a rank.
  • #4 Pareto: swept k∈{2..5} × λ∈{0..1}; front + knee computed per floor.
  • #2b cross-floor surrogate: leave-one-floor-out ridge, 61 candidates/6 floors → mean ρ = 0.24, wildly variable (−0.52 … +0.72). Geometry does NOT predict ray-traced MI across floors — the physics sim is load-bearing (the "expensive RSQ" risk, confirmed). #2a Sionna signal-map coverage DEFERRED (exp-csi-crowd emits no radio map; LOS proxy kept pending a runner change).
  • #5 materialised: placement-<floor>-{operational,experimental,both} PostGIS experiments (18 experiments, 57 APs) → /map/ + QGIS render via existing device layers.

Runs synced to experiments/runs/; figures + rec.json + Pareto tables + cross-floor surrogate under _attachments/placement-oracle/agendas/; results narrated in the seed diary. Gallery: _attachments/placement-oracle/agendas_gallery.html.

Execution log — public-building day showcase, real institutional floors + real-crowd anchor (2026-07-14, M1 Max)

Extends the campaign off ResPlan onto real S3DIS institutional geometry with a multi-hour crowd and a real-crowd footfall anchor, and adds the furniture-as-scatterer counterfactual. Run fully locally as direct sim run executions; helper modules under monad_knowledge/notebooks/python/public_day_*.py. Deliverable bundle + executed notebook: _attachments/placement-oracle/public-day/ (public_day_results.ipynb).

Question (this run). On a real public floor, with a real-scale flowing crowd, does the coverage-optimal AP set equal the count-optimal set — and does the room's furniture move the answer? Two rooms of different shape (an office corridor, a public lobby) test whether any separation is a property of the objective or an artefact of geometry.

Hypotheses (falsifiable). H1 coverage-optimal ≠ count-optimal (Jaccard < 1, rank ρ low). Furniture reorders the count-informative ranking / count-optimal set.

How to read it. Per candidate AP we compute coverage (footfall-weighted LOS, submodular greedy) and count-informativeness I(C;Φ) = MI between the instantaneous room count and the ray-traced CSI feature (mean sub-carrier amplitude), over the coupled exp-csi-crowd frames; empty vs furnished scenes differ only in whether the room's furniture is injected as box scatterers.

Runs.

  • Real-crowd anchor — ATC shopping-mall (18,145 persons, 10.9 h) reconstructed occupancy + footfall; a naive 15-AP coverage grid leaves 46% of actual footfall in blind spots (the real-world motivation; _attachments/.../public-day/atc/).
  • Flagship day (area_5 office corridor) — full-day agenda crowd walk 01KXGKATQC7ZGQYM7ESXG9HHKN (242 agents, peak 89 on floor, replay + occupancy/footfall/speed plots). CSI kernel (60 ray-traced frames × 16 candidates, LOS-confined to the corridor): empty 01KXGMGTENDZZD5QZH6NQSSEN2, furnished 01KXGMWJ9XKC0NT4XY92KCZ1T8.
  • Room 2 (area_4 public lobby) — busy-period lobby crowd 01KXGNDQHH7DA88W5QN7H8KJ2H (46 agents, in-lobby count 3→29, median walk 1.20 m/s). CSI kernel (15 candidates over the open lobby): empty 01KXGNFD4SFWS2TE565AESXWYK, furnished 01KXGNJK42QB7G34D0CNEESSQ4.

Result.

Room count range H1 Jaccard (cov∩cnt) H1 rank ρ furniture MI ρ count-opt moved by furniture
area_5 corridor 1–28 0.00 (disjoint) −0.23 0.62 {1,5,15}→{2,9,15} ✓
area_4 lobby 3–46 0.50 (partial) 0.04 0.48 {1,9,14}→{1,8,14} ✓
  • H1 supported in both rooms. Coverage-optimal is never count-optimal: fully disjoint in the corridor (Jaccard 0.00), only half-overlapping in the lobby (0.50). In both, the per-AP coverage rank is essentially uncorrelated with count-informativeness (ρ ≈ 0), so a coverage site survey does not rank APs for counting.
  • The gap is geometry-dependent. Separation is stronger in the long corridor (coverage wants even spacing; counting wants the high-flux ends) than in the small open lobby (where most candidates see most of the room, so the two objectives partly coincide) — a physically sensible, honest nuance.
  • Furniture is not neutral. Injecting furniture as scatterers reorders the count-informative ranking (empty↔furnished MI ρ 0.48–0.62) and moves the count-optimal set in both rooms — a placement chosen on an empty CAD shell is not the placement you would choose furnished.

Meaning. This operationalises wang2025_2c42 's Open Question 6 for dynamic/flowing crowds on real institutional geometry: coverage and counting are distinct placement objectives, the divergence widens with corridor-like topology, and the furnished geometry — not the room shell — sets count sensitivity. Simulator evidence: a hypothesis generator, not deployment guidance — the channel is ray-traced and the impairment model uncalibrated; every claim is a falsifiable prediction awaiting the real AX210/Pi5 anchor (IP-106 / IP-112). One crowd seed per room for the headline; MI on a single amplitude feature.

Not yet done

  • Real-hardware anchor (the licensing gate): one AX210/Pi5 floor (IP-106 / IP-112) to confirm the sim ranking.
  • #2a propagation coverage from a Sionna signal-map (needs a sionna-csi-runner change).
  • Full 56-floor measured grid (deliberately gated on the surrogate, which under-performs).