height correction, new defalt

This commit is contained in:
Olaf committed 2026-10-21 09:24:12 +02:00
1 parent 0891cf12a5
commit b692f94122
12 files changed
+792 -205

No files matched your search

+80 -52
View File
@@ -23,8 +23,8 @@ The default map rectangle is in Uithoorn, Netherlands:
| Corner | Latitude | Longitude |
| --- | --- | --- |
| Southwest | 52.232025 | 4.784498 |
| Northeast | 52.253985 | 4.863525 |
| Southwest | 52.232 | 4.784 |
| Northeast | 52.258 | 4.864 |
OpenSky supports OAuth client credentials. Obtain your own credentials through
OpenSky and set them in your shell, **not in source code**:
@@ -116,7 +116,7 @@ remain straight; duplicate positions are handled without invalid coordinates.
Smoothing never joins separate tracks or fills long recording gaps. Curves are
interpolations, not evidence of the aircraft's precise motion between samples.
The actual curves are clipped geometrically to the output rectangle, and their
in-map portions determine the time-weighted height calculation.
in-map portions determine the time-weighted reported-altitude calculation.
### Map cache and offline plotting
@@ -126,8 +126,9 @@ unfilled lines. Minor pedestrian/cycle paths, steps, proposed roads, and roads
under construction are omitted from the drawing. Building outlines whose shorter
dimension would be smaller than three pen widths are omitted to prevent dense
housing from turning into ink blobs; larger paper or a finer pen retains more
buildings without another download. Multipolygon relations are not assembled in this initial version;
only returned way geometry is drawn.
buildings without another download. Water multipolygon relations (including
islands) are assembled for the land-elevation mask; the map drawing itself uses
returned way geometry.
Downloaded map data is cached in `.flight-map-cache/`. The cache key includes
the service URL, exact map bounds, and feature query. Different time ranges,
@@ -151,59 +152,84 @@ For entirely offline plotting, pass a local Overpass JSON export containing
```sh
flight-map plot --db flights.sqlite --session SESSION_ID --output offline.svg \
--map-data local-map.json
--map-data local-map.json --no-terrain
```
### Height above the map's average ground level
Omit `--no-terrain` when using cached automatic AHN terrain or supply a local
`--terrain` raster for the separate land-elevation summary offline. For a complete water mask,
local exports must include closed water ways and water multipolygon relations
with full member geometry, including areas enclosing the requested map.
**Without suitable elevation inputs the map still plots, but heights are `N/A`
and the program emits warnings.** It never substitutes pressure altitude, zero
ground elevation, or sea-level altitude.
### Reported aircraft altitude
The calculation is:
Flight labels use **average reported barometric altitude (pressure altitude)**,
in metres, from OpenSky's `baro_altitude` field. It is time-weighted over the
smoothed flight path's portion inside the saved map bounds, using linear
interpolation of altitude between observation timestamps. Outside-map extensions
do not contribute.
```text
height = time-weighted mean aircraft altitude inside the saved map bounds
minus area-weighted mean ground elevation inside those same bounds
```
No terrain elevation is subtracted and no geoid, pressure, or vertical-reference
correction is applied. This is not height above ground, terrain clearance, or
necessarily true altitude above sea level. Geometric altitude is still stored
but is never substituted for missing barometric data. If a contributing segment
has missing barometric altitude, the track's altitude is `N/A` with a warning.
Zero and negative reported altitudes remain valid.
Outside-map extensions do not contribute. Heights are in metres, not terrain
clearance under the aircraft.
Flight altitude does not depend on terrain downloads or the water mask.
The former `--geoid` and `--confirm-geometric-ellipsoid` options have been removed.
SVG metadata uses `data-average-barometric-altitude-metres` and
`data-altitude-source="barometric"` instead of `data-average-height-metres`.
Supply a terrain GeoTIFF whose first band contains ground elevation in metres,
has a CRS, and covers the entire map rectangle. Its declared vertical reference
must be known. Sampling uses an equal-area 64 by 64 geographic grid and honors
nodata, raster band scale, and offset. Any missing sampled ground value makes
the mean unavailable. Choose terrain resolution appropriate to the map; the
grid is an approximation, not a survey-grade terrain integral.
### Separate average land-elevation summary
For terrain already referenced to the WGS84 ellipsoid:
For Dutch map bounds, plotting automatically downloads the **AHN digital terrain
model (DTM)** through the [PDOK WCS](https://service.pdok.nl/rws/ahn/wcs/v1_0?service=WCS&request=GetCapabilities).
It uses coverage `dtm_05m`, not a surface model containing roofs and vegetation.
The service currently describes this coverage as AHN4. Data is requested in
RD New (EPSG:28992) as a 512 by 512 nearest-neighbour GeoTIFF subset of the
source's 0.5 m raster. The downloaded subset is a sampled overview, not the
full-resolution source. Elevations are metres relative to **NAP**.
```sh
flight-map plot --db flights.sqlite --session SESSION_ID --output heights.svg \
--terrain terrain-ellipsoid.tif --terrain-reference wgs84-ellipsoid \
--confirm-geometric-ellipsoid
flight-map plot --db flights.sqlite --session SESSION_ID --output map.svg
flight-map plot --db flights.sqlite --session SESSION_ID --output refreshed.svg \
--refresh-terrain
```
For orthometric terrain, also supply a geoid separation GeoTIFF in metres,
representing **N = h - H**, matching the terrain's vertical datum and covering
the track observations used for conversion:
Terrain is cached under `--cache/terrain/` (by default
`.flight-map-cache/terrain/`), keyed by the PDOK endpoint, coverage, projected
bounds, resolution, and request parameters. Validated downloads atomically replace
cache entries; refresh failures preserve the previous file but warn and leave
land elevation unavailable for that run. Files contain provenance and NAP metadata.
There is no automatic expiry. A changed vector-map query also gets a new cache
key; the first run after the water-mask update downloads fresh OSM data.
```sh
flight-map plot --db flights.sqlite --session SESSION_ID --output heights.svg \
--terrain terrain.tif --terrain-reference orthometric \
--geoid matching-geoid.tif --confirm-geometric-ellipsoid
```
Outside AHN's coverage, on service/download failures, or when no valid land
elevations are available, the program **warns and continues plotting**. Ground
elevation is then `N/A`; reported aircraft altitudes remain available independently.
Use `--no-terrain` to disable the separate land-elevation summary and its downloads.
The land average is informational only and never corrects aircraft altitude.
The application computes `H = h - N` for each geometric aircraft altitude.
OpenSky documents its field as geometric altitude but does not establish every
observation's datum or accuracy. The confirmation flag is a deliberate assertion
by the operator that treating these heights as WGS84 ellipsoidal is appropriate.
Do not set it without verifying your source's interpretation. A missing geometric
altitude or geoid value on a contributing segment makes that track's height
unavailable. Pressure altitude is recorded for provenance, not used for this
calculation. For Dutch terrain in NAP, use a conversion consistent with NAP;
do not assume an arbitrary global geoid matches it.
Sampling uses an equal-area 64 by 64 geographic grid. Mapped OSM water areas
(`natural=water` or `waterway=riverbank`) are excluded, including multipolygon
water areas with islands retained as land. Unmapped water and coastline-derived
sea areas are not inferred. Water masking is only as complete as the OSM data.
If a water outline is unclosed or a multipolygon is incomplete, the program warns
and leaves land elevation unavailable rather than silently
counting that water as land. Map and flight geometry still render.
Valid samples on the remaining land are averaged, honoring raster nodata, scale,
and offset. Missing land samples are **not** assumed to be water: they are
excluded with a warning showing the valid land coverage percentage and sample
counts. Even small coverage gaps produce a warning. Coverage is included in
the plotted legend and SVG metadata; low coverage can bias the average. No
arbitrary minimum is imposed: no valid land samples means `N/A`. The grid is
an approximation, not a survey-grade terrain integral.
You can override automatic AHN with a local terrain GeoTIFF whose first band
contains ground elevation in metres and has a CRS. Declare its vertical reference
with `--terrain-reference` (`nap`, `orthometric`, or `wgs84-ellipsoid`).
`--refresh-terrain` only applies to automatic AHN, not local input.
### Pen-plotter settings
@@ -224,7 +250,7 @@ with an original single-stroke alphabet: no installed fonts, raster images,
filled glyphs, or SVG clipping support are required.
Each track has a numeric identifier and a legend entry with UTC dates/times,
callsign, ICAO identifier, and average height. For dense recordings, select
callsign, ICAO identifier, and average reported barometric altitude. For dense recordings, select
shorter periods or larger paper. The program fails explicitly if the legend
does not fit or a track identifier cannot be placed legibly. Flight identifiers
avoid each other; intersections with map geometry or flight paths are not fully
@@ -237,15 +263,15 @@ rejected.
## Offline synthetic demo
This creates **invented** tracks, map features, terrain, and geoid data, for
This creates **invented** tracks, map features, and terrain data, for
checking the complete workflow without network access:
```sh
python examples/make_demo.py demo
```
Run the plotting command printed by the script. Its heights use synthetic,
known-compatible references; these inputs are not a real Uithoorn dataset.
Run the plotting command printed by the script. Altitude labels use the synthetic
barometric observations directly; these inputs are not a real Uithoorn dataset.
## Development
@@ -258,8 +284,8 @@ mypy flight_map
```
Tests cover recording and resume settings, persistence, deduplication, bounds,
projection, track gaps, clipping, time-weighted heights, missing terrain, vertical
references, cache reuse/refresh/failure, and repeatable offline SVG generation
projection, track gaps, clipping, time-weighted reported barometric altitude,
missing altitude and terrain, cache reuse/refresh/failure, and repeatable offline SVG generation
without mutating the database.
## Data policies and attribution
@@ -276,8 +302,10 @@ without mutating the database.
Cite Matthias Schaefer, Martin Strohmeier, Vincent Lenders, Ivan Martinovic,
and Matthias Wilhelm, "Bringing Up OpenSky: A Large-scale ADS-B Sensor Network
for Research", IPSN 2014, pp. 83-94, when publishing derived work.
- Terrain and geoid: supplied by the operator; follow their separate licenses
and attribution requirements when distributing outputs.
- Local terrain: supplied by the operator; follow its separate license
and attribution requirements when distributing outputs. Automatic AHN DTM
through PDOK is CC0; its source and NAP reference are included in SVG metadata
and the plotted attribution.
Map and flight attribution is included as plotter paths, with further provenance
in SVG metadata. This is an artistic recording/plotting tool, not a navigation