feat: complete Phase 3 roadmap + COST 231 + ITM variability modes - #21
Draft
d3mocide wants to merge 2 commits into
Draft
feat: complete Phase 3 roadmap + COST 231 + ITM variability modes#21d3mocide wants to merge 2 commits into
d3mocide wants to merge 2 commits into
Conversation
Closes P3-1, P3-3, P3-4 and P4-2 ahead of the next production build. P3-1 -- Client-side Hata/FSPL: Port Okumura-Hata to JavaScript (src/utils/math/hata.js), mirroring rf_physics.calculate_hata_loss term-for-term including input clamping; both engines agree to 4 decimal places on the reference cases. Add a dispatcher (src/utils/math/pathLoss.js) and wire LinkLayer to resolve `fspl` and `hata` locally, so neither needs /api/calculate-link and both keep working offline/PWA. `bullington` and server `itm` stay on the backend, which applies clutter_height and k_factor to the profile in ways the current JS Bullington does not. P4-2 -- COST 231-Hata: Extend Hata coverage from 150-1500 MHz to 150-2000 MHz in both engines. Selecting "Hata" auto-dispatches to COST 231 at/above 1500 MHz; `cost231` is also accepted as an explicit backend model. Per the standard, COST 231 defines only the 3 dB metropolitan correction and has no suburban/rural term, so those environments now warn above the crossover rather than silently reusing the Okumura-Hata corrections. Link Analysis validity warnings now come from a single getHataValidity helper. P3-3 -- WASM ITM for batch reports: Add a propagation-model selector to Batch Processing. ITM runs the same WASM engine as Link Analysis over a 100-point profile (vs 20 for Bullington), honouring Ground Type and Climate Zone, so batch numbers match single-link analysis. The module loads lazily on selection (useWasmITM gained an `enabled` flag, keeping it off the startup path), and a link that fails ITM falls back to Bullington instead of failing the whole report. P3-4 -- Per-node configs in batch CSV: Parse optional Antenna_Height, Antenna_Gain, TX_Power, Device and Antenna columns, with aliases and loose preset-name matching. nodeConfig.js merges them over the global A/B config field-by-field; blank cells and existing three-column files behave exactly as before. Also fixed: Bullington diffraction was never displayed for Hata in LinkLayer -- the check compared against 'Hata' while the model value is lowercase 'hata'. Mesh report export now writes via a Blob and escapes CSV fields, so node names containing commas no longer corrupt the report, and it gained Model/PathLoss_dB/per-node parameter columns plus a progress bar. P4-6 (variability modes) is documented as blocked: it needs new LinkParameters fields and an emscripten rebuild of meshrf.wasm. Tests: 44 frontend (28 new), 23 backend (14 new). Lint and build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FU7LVUXdVx5YfXt4eJJSPs
ITM's time/location/situation variability was hardcoded to 50/50/50 in meshrf_itm.cpp, so every prediction was the median forecast with no way to plan for worst-case conditions. It is now user-selectable. C++ / WASM: - Add time_pct, loc_pct, sit_pct and mdvar to LinkParameters, defaulted to the values calculate_radial_loss previously hardcoded (50/50/50, mdvar=12). - Expose them through Embind. - Thread variability into the coverage path; calculate_rf_coverage gained three trailing arguments, so useRFCoverageTool now passes 20 (Embind matches on arity). - Regenerate public/meshrf.wasm, libmeshrf/js/meshrf.wasm and libmeshrf/js/meshrf.js. ROADMAP P4-6 documents the rebuild command. Frontend: - RELIABILITY_MODES presets in EnvironmentContext: Best Case (10/10/10), Typical (50/50/50, default), Reliable (90/90/90). - Reliability selector in the Environment sidebar. - Wired through Link Analysis, RF Coverage (click, recalc and drag paths) and batch ITM reports; batch rows record the mode that produced them. Backward compatibility is the important property here, and it is verified against the built module rather than assumed: a call that never sets the new fields returns a bit-identical result to an explicit 50/50/50. Struct defaults, all four Embind bindings, the 20-arg coverage call and the untouched viewshed binding were each exercised against the installed artifacts. Measured on a synthetic ridge (915 MHz, 10 m TX / 2 m RX): 10/10/10 = 193.49 dB, 50/50/50 = 203.76 dB, 90/90/90 = 213.66 dB. Note the WASM was rebuilt with emcc 6.0.4, which also regenerates the JS glue every WASM hook imports. Unit tests cannot cover a glue regression, so link analysis, coverage and viewshed want a manual pass before this ships. Tests: 52 frontend (8 new), 23 backend. Lint and build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FU7LVUXdVx5YfXt4eJJSPs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Knocks out the remaining roadmap items ahead of the next production build. Closes P3-1, P3-3, P3-4, P4-2 and P4-6.
Important
This PR rebuilds
meshrf.wasmand regenerateslibmeshrf/js/meshrf.js— the module loader every WASM hook imports. See Verification of the WASM rebuild below for what I checked and what still needs a human pass before shipping.P3-1 — Client-side Hata / FSPL
Okumura-Hata is now implemented in JavaScript (
src/utils/math/hata.js), mirroringrf_physics.calculate_hata_lossterm-for-term including the input clamping. Both engines agree to 4 decimal places on the reference cases (900 MHz / 5 km / 50 m / 1.5 m →146.9428 dBon each side).A new dispatcher (
src/utils/math/pathLoss.js) letsLinkLayerresolvefsplandhatalocally, so neither model needs/api/calculate-linkand both keep working offline / in the PWA.bullingtonand server-sideitmdeliberately stay on the backend — the Python implementation appliesclutter_heightandk_factorto the terrain profile, and the current JScalculateBullingtonDiffractiondoes not, so moving them would silently change existing results.P4-2 — COST 231-Hata extension
Extends Hata coverage from 150–1500 MHz to 150–2000 MHz in both engines. Selecting "Hata" auto-dispatches to COST 231 at or above 1500 MHz;
cost231is also accepted as an explicit backend model.Per the standard, COST 231 defines only the 3 dB metropolitan correction and has no suburban or rural term. Rather than silently reusing the Okumura-Hata corrections at frequencies where they aren't defined, selecting those environments above the crossover now raises an explicit warning. Link Analysis validity warnings are driven from a single
getHataValidityhelper instead of inline thresholds.P3-3 — WASM ITM for batch reports
Batch Processing gained a propagation-model selector:
The WASM module loads lazily on selection —
useWasmITMgained anenabledflag so this always-mounted panel doesn't pull a ~MB instantiation onto the startup path. A link that fails ITM falls back to Bullington rather than failing the whole report, and theModelcolumn records which model actually produced each row.P3-4 — Per-node configs in batch CSV
CSV import now reads optional
Antenna_Height,Antenna_Gain,TX_Power,DeviceandAntennacolumns, with aliases (Height/AGL/Gain/Power) and loose preset matching —HELTEC_V3,heltec-v3andHeltec V3all resolve to the same device. AnAntennapreset supplies its nominal gain; an explicitAntenna_Gainwins.nodeConfig.jsmerges overrides over the global A/B config field-by-field. Blank cells and existing three-column files behave exactly as before, so this is backward compatible.P4-6 — ITM statistical variability modes
Previously
time_pctwas hardcoded to50.0inmeshrf_itm.cpp, so every prediction was the median forecast with no way to plan for worst-case conditions.C++ / WASM: added
time_pct,loc_pct,sit_pctandmdvartoLinkParameters, exposed them through Embind, and threaded variability into the coverage path —calculate_rf_coveragegained three trailing arguments, souseRFCoverageToolnow passes 20 (Embind matches on arity).Frontend: a Reliability selector in the Environment sidebar offers Best Case (10/10/10), Typical (50/50/50, default) and Reliable (90/90/90), wired through Link Analysis, RF Coverage (click, recalc and drag paths) and batch ITM reports. Batch rows record the mode that produced them (e.g.
ITM 90/90/90).Measured on a synthetic ridge (915 MHz, 10 m TX / 2 m RX) — roughly a 20 dB spread:
Verification of the WASM rebuild
public/meshrf.wasm,libmeshrf/js/meshrf.wasmandlibmeshrf/js/meshrf.jsare regenerated artifacts. Built with emcc 6.0.4 via the repo's ownDockerfile.wasmrecipe; ROADMAP P4-6 documents the exact command.Checked against the installed artifacts, not assumed:
calculate_itm,calculate_rf_coverage,calculate_viewshed,LinkParameters).LinkParametersdefaults intact for every pre-existing field, plus the four new ones.calculate_rf_coveragecall succeeds and returns a full grid.calculate_viewshedstill works — it shares the rebuilt glue even though this change doesn't touch it.What this does not cover: emcc 6.0.4 is almost certainly not the version that produced the previously committed artifact (the JS glue moved 48,650 → 48,130 bytes). Unit tests can't catch a loader regression, so link analysis, RF coverage and viewshed each want a manual pass in the running app before this ships to prod.
Also in this PR
LinkLayer— the check compared against'Hata'while the model value is lowercase'hata', so the condition could never be true.Blobinstead of adata:URI and escapes CSV fields, so node names containing commas or quotes no longer corrupt the report.Model,PathLoss_dBand per-node TX/RX height/gain/power columns, plus a progress bar.Still open
P3-2 (model selection for RF coverage) — needs a JS raster path over the stitched elevation grid, now easier since
calculateClientPathLossexists.P4-6 statistical contours — the variability controls are done; rendering probability-of-reception contours from multiple percentage runs is tracked as the remaining piece.
Testing
rf-engine/tests/test_rf_physics.py, pinning the same reference values so the two engines can't drift apart).npm run lintandnpm run buildclean.Docs updated:
ROADMAP.md,CHANGELOG.md,README.md,Documentation/batch-processing.md,Documentation/link-analyzer.md.