Wire the EASA ANP fleet database into the ECAC Doc 29 airport-noise chain (#260)
* feat(aircraft): wire the EASA ANP fleet database into the Doc 29 chain
Add phonometry.aircraft.anp_fleet, a loader that reads the Aircraft Noise
and Performance (ANP) database tables and feeds real aircraft types into the
existing ECAC Doc 29 airport-noise functions.
load_anp_database returns an AnpDatabase. For a given aircraft identifier and
operation it exposes the Noise-Power-Distance curves (AnpNpdCurves, LAmax and
SEL versus slant distance for each tabulated power setting) and the default
fixed-point trajectory (AnpProfile, a ready (N,5) Doc 29 flight path with the
takeoff and landing ground-roll masks). AnpDatabase and AnpAircraft carry
convenience event_level and noise_contour methods that assemble the NPD curves
and the profile and call the existing chain, so users compute levels and
contours from actual aircraft instead of only synthetic NPD input.
Called without a path the loader uses a small curated subset shipped with the
package: a heavy jet (747100, wing), a narrowbody (727200, fuselage) and a
propeller aircraft (PA31), each with both NPD sets and fixed-point profiles.
Pointed at a directory it reads a full ANP CSV export the user has downloaded
under the database's own licence. The raw database is not redistributed; the
curated CSVs are reproduced verbatim with a provenance note.
Only fixed-point trajectories are read as ready-to-use profiles; procedural
step profiles (which need the flight-mechanics performance model) are out of
scope for this bridge, and NPD curves are available for every aircraft.
Validation uses the ANP database's own published values as the clean-room
oracle: interpolating at a tabulated (power, distance) node recovers the
published level exactly. Tests cover the round-trip exactness over the whole
subset, the profile unit conversion and ground-roll masks, an end-to-end
contour smoke test, external-directory loading and the error paths. A matching
conformance row is registered.
* feat(aircraft): ship the full EASA ANP v2.3 database, not a curated subset
Bundle the complete EASA ANP database (archive version 2.3, 155 aircraft
types) as the default dataset, so load_anp_database() exposes the whole fleet
out of the box instead of three representative types. All ten v2.3 CSV tables
are reproduced verbatim under aircraft/data/anp with an updated provenance and
licence note (redistributed on EASA's free, non-commercial basis).
The loader still consumes the Aircraft, NPD and fixed-point-profile tables; the
procedural-step, coefficient and spectral-class tables ship for completeness
and future use. Modern types that carry only procedural-step profiles (for
example A320-211) expose NPD curves and raise a clear error for the profile,
which the tests now assert. Add the data to MANIFEST.in for the sdist and
regenerate docs/CONFORMANCE.md.
* fix(aircraft): use an on-ground altitude threshold instead of float equality
Detecting runway segments by comparing the altitude to exactly 0 m tripped the
static-analysis float-equality rule. Ground points are tabulated at 0 m and the
lowest airborne profile point is above 150 m, so a 1 m threshold separates them
unambiguously and reads as intentional.
* docs: regenerate conformance report after rebase onto main
* docs: regenerate conformance report after rebase onto main
* fix(aircraft): address ANP loader review feedback
- Tolerate a UTF-8 BOM in exported ANP CSVs (utf-8-sig).
- profile() raises the unknown-aircraft error for an unknown id, not the
misleading no-fixed-point-profile message.
- Validate that the SEL and LAmax NPD curves share power settings before
assembling them for the Doc 29 chain (guards malformed user exports).
- _pick() raises an explicit ambiguity error when several files match a table
keyword instead of silently taking the first.
- Validate the parsed NPD distance columns are strictly increasing.
- Expose the parsed NPD and profile arrays as read-only views and note it in
the docstrings.
- Fix the profile-plot roll highlight off-by-one so the final point of a roll
span is included.