CI License: MIT Model: ITU--R P.1812--8 Python 3.11+ Container
Reproducible, terrain-aware repeater field-strength maps with an embedded station registry, a complete Leaflet street-map demo, numerical web tiles, Cesium integration components, and expected S-meter values under explicit receiver assumptions. The primary result is always an electric field strength in dBμV/m—never a decorative or binary coverage shape.
Author: Beat W. Meier, HB9MQB
Quick start · Live API contract · Demo guide · Integration · Scientific paper · Contribute
Important
This is a planning model. It does not guarantee communication. Buildings, foliage, antenna patterns, polarization mismatch, feed-line loss, interference, receiver implementation, weather, and short-term propagation can materially change real reception.
Version 0.1.0 is the first published self-contained field-strength component. The current development line adds explicit clutter and P.1812 radio-climate inputs for production host integration. Its intentionally bounded scope is:
- calculation of terrain-aware repeater fields in dBμV/m;
- GeoTIFF, numeric tiles, colored overlays, and strongest-field composites;
- reusable Leaflet/Cesium integration patterns and controls; and
- geographic field sampling with an expected S-meter indication.
It can be embedded as a pinned Python dependency or OCI container. A host application remains responsible for its own authoritative station database, source merging, authentication, durable scheduling, artifact-retention policy, and globe or map shell. Those are clean integration boundaries, not duplicated features. See Host integration and the explicit replacement-readiness contract before removing an existing implementation.
Many repeater maps reduce propagation to a single-color visibility footprint. That is useful for orientation, but it hides whether a location is predicted at 5 or 75 dBμV/m and cannot support a meaningful threshold or cursor readout. This project instead:
- calculates path-specific field strength with ITU-R P.1812-8;
- uses terrain profiles over all azimuths and real ERP when supplied;
- treats the first 250 m with the P.525 free-space expression because P.1812 requires a sufficiently long terrain profile;
- represents the result on one absolute, station-independent color scale;
- publishes stable 0.5 dB-quantized numerical tiles in addition to rendered color tiles;
- lets a browser change opacity and the 0–50 dBμV/m display threshold without pretending that the physics changed;
- reports an expected S indication only after applying a stated idealized antenna and impedance conversion; and
- records model version, inputs, sampling, units, and assumptions in a manifest.
The scientific method and its limitations are described in the paper. See MODEL.md for the engineering contract and VALIDATION.md for the validation strategy.
Field-strength overlay integrated into an interactive map
This example shows a calculated repeater overlay integrated into an interactive map client:
- the purple-to-red surface is the transparent propagation layer; each color represents an absolute predicted electric field in dBμV/m;
- the pointer popup samples the numerical raster at that geographic position and shows 27.5 dBμV/m together with the derived expected S7 indication;
- the horizontal legend retains one station-independent 0–100 dBμV/m color scale and adds frequency-dependent expected S references below it;
- Opacity blends the overlay with the chosen base map without changing any calculated value;
- Minimum field strength hides values below the selected 0–50 dBμV/m threshold without modifying or recalculating the stored GeoTIFF; and
- the station card identifies the active artifact and records frequency, ERP, propagation model, terrain sampling, and DEM provenance.
The base map and analysis layer are independent. The screenshot uses imagery to
make terrain structure obvious; the included /demo/ application applies the
same Web Mercator overlay to an attributed street map. Switching base maps,
overlays, or stations does not change the camera position or zoom.
The same field-strength layer over a street map
The street-map view demonstrates that the numerical overlay is not tied to satellite imagery or a specific map vendor. Roads, settlements, lakes, and administrative labels remain readable below the adjustable transparent layer. At the sampled location the popup reports 35.5 dBμV/m and derives an expected S8 reading under the documented ideal 0 dBi / 50 Ω receiver reference. The field raster, legend thresholds, station metadata, and cursor sampling are identical in both views; only the base map has changed.
flowchart LR
Station[Transmitter: position, frequency, ERP, AGL] --> Engine
DEM[DEM GeoTIFF] --> Profiles[Radial terrain profiles]
Climate[Optional P.1812 radio-climate zones] --> Profiles
Profiles --> Engine[P.1812 path model]
Engine --> Polar[Polar dBμV/m samples]
Polar --> Raster[AEQD interpolation and GeoTIFF]
Raster --> Tiles[Cesium geographic and Web Mercator tiles]
Registry[(Embedded SQLite registry)] --> API[Calculation and delivery API]
Raster --> API
Tiles --> Demo[Leaflet street-map demo]
Tiles --> Overlay[Cesium integration package]
API --> Hover[Expected S-meter hover]
The calculator, artifact service, demo, and web package are deliberately separated. SQLite is embedded for zero-configuration station storage; an external database server or application framework is not required.
The native macOS calculation path is optimized for Apple M5: P.1812 rays run
across selected performance cores, large terrain grids are shared between
spawned workers, nested numerical thread pools are suppressed, and an optional
fused MLX/Metal kernel accelerates polar-to-Cartesian rasterization. Install it
with python -m pip install -e '.[apple]'. The manifest identifies whether
mlx-metal-polar-v1 or the equivalent NumPy backend produced the raster.
See PERFORMANCE.md for measurement requirements and contribution ideas for Linux, experimental Windows, CUDA, ROCm, SYCL, Vulkan and WebGPU. The repository does not claim an unimplemented GPU backend.
Download the repository archive, extract it, and run:
cp .env.example .env docker compose up -d curl http://127.0.0.1:8765/v1/health
Open http://127.0.0.1:8765/demo/ for the interactive street-map demo or http://127.0.0.1:8765/docs for OpenAPI. The demo exposes the full reference workflow in one screen: station filters and editing, radius and terrain mode, calculation status, transparent or background-rendered GeoTIFF selection, one bounded layer containing either an individual or strongest-field composite overlay, opacity, the 0–50 dBμV/m threshold, absolute legend, pointer field/S-meter inspection, and downloads. The fresh Docker database is seeded with the real HB9ZG Rigi-Scheidegg example from examples/stations.json. Seed records are inserted only when their station ID is absent, so later starts never replace edited data. On a fresh start HB9ZG is selected automatically and the 5 km quick-test radius is ready. Press Calculate selected once; the demo then displays the real P.1812 result, legend, hover readings, and download links automatically.
The compose file uses the downloadable multi-architecture image
ghcr.io/hb9mqb/hamrelay-field-strength:latest when published; add
--build to build locally. The first calculation in auto terrain mode
downloads only the required public Copernicus GLO-30 COG tiles and caches them,
with per-tile GLO-90 fallback. The container downloads the integral P.1812 maps
directly from the official ITU archive at startup and never republishes them in
the image.
Persistent artifacts, DEM cache, ITU data, and the embedded station database
live below runtime/. The service binds to 127.0.0.1 by
default. Configure TLS, authentication, rate limits and explicit CORS origins
before making calculation endpoints public. Docker runs the CPU/NumPy backend;
native macOS is required for M5 Metal acceleration.
Python 3.11+ and GDAL-compatible Rasterio wheels are required.
git clone https://github.com/hb9mqb/HamRelay-FieldStrength.git cd HamRelay-FieldStrength python -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip python -m pip install -e '.[dev]'
The pinned Py1812 implementation needs the DN50.TXT and N050.TXT digital
products distributed with ITU-R P.1812-8. Follow the upstream
Py1812 instructions.
These files are not redistributed here.
Copy examples/calculation.json and point dem_paths
to one or more co-registered GeoTIFFs. If erp_w is absent, the documented
fallback is 12 W. The radius is capped at 100 km.
hamrelay-field-strength calculate --config examples/calculation.json hamrelay-field-strength tiles \ --geotiff artifacts/TEST-UHF-001/field-strength.tif \ --output artifacts/TEST-UHF-001/tiles
export FIELD_STRENGTH_ARTIFACT_ROOT="$PWD/artifacts" uvicorn hamrelay_field_strength.service:app --host 127.0.0.1 --port 8765
OpenAPI is available at http://127.0.0.1:8765/docs. Production deployments
should place this read-only service behind TLS and a cache/CDN; never expose a
database directly to a public browser.
cd web && npm install && npm run build
import { CoverageOverlayController, FieldStrengthApi, SMeterHover, createLegend, } from "@hamrelay/field-strength-overlay"; const api = new FieldStrengthApi("https://coverage.example.org"); const coverage = new CoverageOverlayController(viewer, api, { opacity: 0.7, minimumFieldStrengthDbuvM: 5, }); coverage.setVisibleStations(["TEST-UHF-001"]); // camera is left unchanged document.body.append(createLegend()); const hover = new SMeterHover(viewer, api, () => ["TEST-UHF-001"], { render: (sample, position) => renderPopup(sample, position), });
When a station filter changes, call setVisibleStations(filteredStationIds).
Each station remains an independent layer and can be toggled without changing
map position, zoom, heading, or pitch.
| Parameter | Default | Meaning |
|---|---|---|
| Propagation method | ITU-R P.1812-8 | 30 MHz–6 GHz path-specific field model |
| Maximum radius | 100 km | Practical project boundary |
| ERP | source value, else 12 W | Effective radiated power |
| Terrain profile step | 50 m | DEM sampling along each ray |
| Radial field step | 200 m | P.1812 endpoint spacing |
| Output grid | 60 m | Publication grid; not a claim of 60 m model accuracy |
| Minimum rays | 360 | Full 360° coverage |
| Outer-arc target | 500 m | Raises ray count for large radii |
| Receiver height | 1.5 m AGL | Planning receiver |
| Time/location | 50% / 50% | Median planning conditions |
| Polarization | vertical | Configurable per station |
| Display threshold | 5 dBμV/m | UI default, adjustable from 0–50 |
Spatial output resolution, input DEM post spacing, terrain-profile sampling, angular sampling, and propagation-model accuracy are different concepts. The manifest reports each independently to prevent false precision.
| Method | Path | Purpose |
|---|---|---|
GET |
/v1/health |
Liveness |
GET |
/v1/capabilities |
Client feature and limit discovery |
GET |
/v1/stations |
Filtered station registry |
PUT |
/v1/stations/{id} |
Authenticated station upsert |
POST |
/v1/stations/import |
Authenticated bulk import |
POST |
/v1/calculations |
Optional job submission with 0.25–100 km radius |
GET |
/v1/calculations/{job_id} |
Calculation status |
GET |
/v1/coverage/{id}/manifest |
Inputs, provenance, range, model |
GET |
/v1/coverage/{id}/field-strength.tif |
Requested Float32 GeoTIFF download |
GET |
/v1/coverage/{id}/field-strength-visual.tif |
Transparent/map/street-map RGBA GeoTIFF |
GET |
/v1/coverage/{id}/tiles/{z}/{x}/{y}.png |
Thresholded RGBA tile |
GET |
/v1/coverage/{id}/web-tiles/{z}/{x}/{y}.png |
Leaflet/OSM Web Mercator tile |
GET |
/v1/coverage/{id}/values/{z}/{x}/{y}.png |
Stable 8-bit numerical tile |
GET |
/v1/coverage/{id}/sample?latitude_deg=...&longitude_deg=... |
Field and expected S reading |
POST |
/v1/samples |
Batch sample and strongest station |
GET |
/v1/composites/web-tiles/{z}/{x}/{y}.png |
Strongest-field composite |
The value-tile encoding reserves zero for NoData. Values 1–255 represent
-20 + (value - 1) ×ばつ 0.5 dBμV/m. Full schemas, status codes, caching semantics,
and examples are in API.md.
Project code is MIT licensed. Propagation implementations, elevation models, land-cover products, base maps, and ITU digital products retain their own licenses. Nothing in the MIT license grants rights to third-party data.
Recommended worldwide terrain input is Copernicus DEM GLO-30. It is a digital surface model (not a bare-earth DTM), has approximately 30 m latitude spacing, and requires the attribution described in its Product Handbook. Higher-quality regional DTMs can be supplied without changing the calculation contract. See DATA-SOURCES.md. The release-level summary is in THIRD_PARTY_NOTICES.md.
Every artifact manifest records transmitter inputs, model and implementation revision, sampling geometry, output resolution, field range, worker count, and explicit assumptions. A scientific claim requires more than a visually plausible map: compare predicted fields against calibrated mobile or fixed measurements, retain withheld validation routes, and publish residual statistics by terrain and distance. The repository intentionally distinguishes implementation conformance from empirical accuracy.
This project is looking for radio engineers, propagation researchers, field measurement teams, GIS developers, performance specialists, web developers, technical writers, accessibility reviewers, and curious radio amateurs. A small reproducible validation case or a careful documentation correction can be as valuable as a large feature.
Contributions are welcome, especially:
- calibrated measurement datasets with defensible metadata;
- independent P.1812 conformance tests;
- radio-climate and clutter adapters with clear provenance;
- uncertainty visualization and residual analysis;
- accessibility, WebGL performance, and non-Cesium clients; and
- reproducible benchmarks on Apple silicon, Linux ARM64, and x86-64.
The project is also seeking scientific co-authors. Contributors whose work substantially advances the method, calibrated validation, reproducible implementation, performance research, or scientific manuscript may be invited to co-author a future paper revision. The transparent authorship criteria and responsibilities are documented in CONTRIBUTING.md.
Windows code and CI configuration are included, but the Windows execution path is explicitly experimental and not yet tested. See WINDOWS.md; please help turn the prepared port into a measured, reproducible compatibility claim.
Read CONTRIBUTING.md, open an issue before a large change, and keep physical assumptions explicit. A colorful result is not sufficient; new propagation behavior must be testable and scientifically referenced.
The complete documentation map is in docs/README.md. Use SUPPORT.md to choose the right issue form, and see the public roadmap for well-bounded contribution ideas.
Use CITATION.cff, or cite the accompanying paper:
Beat W. Meier, HB9MQB. "Reproducible Terrain-Aware Repeater Field-Strength Mapping with ITU-R P.1812." 2026.
Copyright © 2026 Beat W. Meier, HB9MQB. Released under the MIT License.