Aircraft

Aircraft performance models with speed profiles, climb/descent rates, turn radii, and endurance limits. 12 pre-configured research aircraft are included; custom aircraft can be created by instantiating Aircraft directly.

Base class

class Aircraft[source]

Bases: object

Aircraft performance model.

Holds identity, geometric constraints, phase-specific speed schedules, vertical performance profiles, turn model, and provenance metadata.

Parameters:
  • aircraft_type (str) – Aircraft model name (e.g. "Gulfstream V").

  • tail_number (str) – Tail number or "Unknown".

  • operator (str) – Operating organization.

  • service_ceiling (Quantity) – Maximum operational altitude.

  • approach_speed (Quantity) – Landing approach speed.

  • climb_schedule (Union[CasMachSchedule, TasSchedule]) – Speed schedule for climb phase.

  • cruise_schedule (Union[CasMachSchedule, TasSchedule]) – Speed schedule for cruise phase.

  • descent_schedule (Union[CasMachSchedule, TasSchedule]) – Speed schedule for descent phase.

  • climb_profile (VerticalProfile) – Rate-of-climb vs altitude.

  • descent_profile (VerticalProfile) – Rate-of-descent vs altitude. When approach_profile is set, this profile is intended to cover the cruise-altitude → top-of-approach (MSL) regime only; the terminal descent below top-of-approach is owned by approach_profile. When approach_profile is None, descent_profile continues to cover the full cruise-to-touchdown range as before (legacy behavior).

  • turn_model (TurnModel) – Turn performance / bank angles.

  • engine_type (Literal['jet', 'turboprop', 'piston']) – Propulsion category — "jet", "turboprop", or "piston".

  • confidence (Optional[PerformanceConfidence]) – Per-submodel confidence ratings.

  • sources (Optional[List[SourceRecord]]) – List of provenance records.

  • range (Optional[Quantity]) – Maximum flight range (optional, metadata only).

  • endurance (Optional[Quantity]) – Maximum flight duration (optional, metadata only).

  • useful_payload (Optional[Quantity]) – Payload capacity (optional, metadata only).

  • approach_profile (Optional[ApproachProfile]) – Optional terminal-arrival template covering top-of-approach → touchdown. When set, the planner can estimate terminal-segment timing geometrically from the speed schedule and glideslope. When None, the legacy scalar approach_speed and descent_profile are used for arrival behavior.

  • descent_path_angle_max_deg (Optional[float]) – Maximum sustainable flight path angle during descent (degrees). When set, _hybrid_path steepens the descent to fit available lateral distance rather than spiralling at end of leg.

  • climb_path_angle_max_deg (Optional[float]) – Maximum sustainable flight path angle during climb (degrees). When set, _hybrid_path steepens the climb to fit available lateral distance rather than spiralling at departure. When None and typical_climb_out.absorbed_in_climb_profile is True, the spiral-up regime acts as the absorption mechanism for mission-typical level-offs / .delay orbits.

  • typical_climb_out (Optional[ClimbOutPolicy]) – Optional ClimbOutPolicy documenting the pre-cruise climb-out behaviour the calibrated climb_profile is tuned to absorb. Pure metadata in v1.5 — names the absorption posture so it’s queryable rather than buried in comments.

  • calibration_status (Literal['calibrated', 'inferred', 'uncalibrated']) –

    Provenance label for the performance model. One of:

    • "calibrated" — climb / cruise / descent profiles and TAS schedules are fit to in-situ flight data (IWG1 / ICARTT) per docs/calibration.md.

    • "inferred" — performance is mirrored from a calibrated cousin airframe of the same type certificate (e.g. NCAR_GV mirrors NASA_GV); not directly measured against the target airframe.

    • "uncalibrated" — performance comes from brochures, AFM tables, or rough estimates with no measured-data fit. Timing and reachability output for these aircraft should be treated as a best-effort starting point rather than a calibrated model.

    Defaults to "uncalibrated"; calibrated subclasses set this explicitly.

__init__(aircraft_type, tail_number, operator, service_ceiling, approach_speed, climb_schedule, cruise_schedule, descent_schedule, climb_profile, descent_profile, turn_model, engine_type, confidence=None, sources=None, range=None, endurance=None, useful_payload=None, approach_profile=None, descent_path_angle_max_deg=None, climb_path_angle_max_deg=None, typical_climb_out=None, stall_speed_cas=None, calibration_status='uncalibrated')[source]
Parameters:
  • aircraft_type (str)

  • tail_number (str)

  • operator (str)

  • service_ceiling (Quantity)

  • approach_speed (Quantity)

  • climb_schedule (CasMachSchedule | TasSchedule)

  • cruise_schedule (CasMachSchedule | TasSchedule)

  • descent_schedule (CasMachSchedule | TasSchedule)

  • climb_profile (VerticalProfile)

  • descent_profile (VerticalProfile)

  • turn_model (TurnModel)

  • engine_type (Literal['jet', 'turboprop', 'piston'])

  • confidence (PerformanceConfidence | None)

  • sources (List[SourceRecord] | None)

  • range (Quantity | None)

  • endurance (Quantity | None)

  • useful_payload (Quantity | None)

  • approach_profile (ApproachProfile | None)

  • descent_path_angle_max_deg (float | None)

  • climb_path_angle_max_deg (float | None)

  • typical_climb_out (ClimbOutPolicy | None)

  • stall_speed_cas (Quantity | None)

  • calibration_status (Literal['calibrated', 'inferred', 'uncalibrated'])

property speed_model_fidelity: str

Describe the fidelity level of the cruise speed model.

Returns one of:

  • "cas_mach" — CAS/Mach schedule (atmosphere-aware).

  • "simplified_tas" — piecewise-linear TAS approximation.

property max_bank_angle: float

Maximum bank angle in degrees (for Dubins path geometry).

cruise_speed_at(altitude)[source]

True airspeed at altitude using the cruise speed schedule.

Return type:

Quantity

Parameters:

altitude (Quantity)

climb_speed_at(altitude)[source]

True airspeed during climb at altitude.

Mirrors descent_speed_at() for the climb schedule. Most aircraft factories alias climb_schedule to cruise_schedule, in which case this returns the same value as cruise_speed_at().

Return type:

Quantity

Parameters:

altitude (Quantity)

rate_of_climb(altitude)[source]

Rate of climb at altitude from the climb profile.

Return type:

Quantity

Parameters:

altitude (Quantity)

descent_speed_at(altitude)[source]

True airspeed during descent at altitude.

Return type:

Quantity

Parameters:

altitude (Quantity)

stall_speed_at(altitude)[source]

True airspeed at stall at altitude.

Stall is published as a single stall_speed_cas value (calibrated airspeed at landing config, MLW). TAS at altitude is derived via standard atmosphere — Vs in CAS is approximately invariant with altitude (stall is a fixed-AoA, fixed-q event) but TAS scales as 1/sqrt(density), so TAS at FL400 is roughly twice the SL value.

Raises:

HyPlanValueError – If stall_speed_cas is None for this aircraft.

Return type:

Quantity

Parameters:

altitude (Quantity)

min_safe_speed_at(altitude, *, margin=1.3)[source]

Minimum safe true airspeed at altitude, with margin above stall.

margin defaults to 1.3, mirroring the FAR Part 25 rule that V_ref >= 1.3 * Vs0. Pass a tighter margin (e.g., 1.2) for attentive level orbits in benign conditions, or a looser one (1.4-1.5) for night IFR / unstable atmospheres.

Returns margin * stall_speed_at(altitude) — useful for science planners deciding whether a slow-survey speed at a given altitude is acceptable.

Raises:

HyPlanValueError – If stall_speed_cas is None or margin is non-positive.

Return type:

Quantity

Parameters:
approach_speed_at(altitude_agl)[source]

True airspeed at altitude_agl during the terminal approach.

When approach_profile is set, this returns the schedule value at altitude_agl. When it isn’t, this returns the legacy scalar approach_speed for any altitude (the existing single-speed approximation).

Return type:

Quantity

Parameters:

altitude_agl (Quantity)

approach_vertical_rate_at(altitude_agl, groundspeed=None)[source]

Approximate vertical rate on the terminal approach.

When approach_profile is set, returns the geometric rate from ApproachProfile.approx_vertical_rate_at() (using the optional groundspeed override or scheduled TAS in still air). Returns None when no approach profile is configured — callers should fall back to legacy descent behavior in that case rather than synthesizing from descent_profile, which keeps the regime split crisp.

Return type:

Optional[Quantity]

Parameters:
climb_gradient_at(altitude)[source]

Climb gradient at altitude — dimensionless rise/run.

Computed from the integrated climb performance: the climb rate from climb_profile divided by the climb-schedule TAS. Useful for terrain-aware planning (“can the aircraft clear a 10,000 ft ridge in 50 nmi?”) since obstacle clearance is naturally expressed as a horizontal-vs-vertical ratio.

Returns 0.0 if TAS is zero (defensive — physically unreachable).

Return type:

float

Parameters:

altitude (Quantity)

descent_gradient_at(altitude)[source]

Descent gradient at altitude — dimensionless drop/run, positive.

Mirror of climb_gradient_at() for descent, returning a positive value (the magnitude of the descent slope).

Return type:

float

Parameters:

altitude (Quantity)

max_bank_under_budget(pitch_deg=0.0)[source]

Maximum bank angle (deg) consistent with the load-factor budget.

For a steady banked climb / descent at pitch angle pitch_deg, lift balance gives n = 1 / (cos(bank) · cos(pitch)). Solving for the bank that drives n to turn_model.max_load_factor:

cos(bank_max) = 1 / (n_max · cos(pitch))

Returns 0.0 when the implied pitch alone exceeds the budget (i.e. the aircraft can’t sustain level flight at that pitch — physically unreachable, included as a defensive guard). Returns 90.0 when the budget is unbounded (n_max <= 0 is treated as “no limit”).

The default pitch_deg=0 covers level cruise; callers in the climb / descent paths supply the implicit pitch from the rate-vs-altitude profile.

For the calibrated HyPlan aircraft library this returns large values (60-67° depending on aircraft and pitch) — well above every aircraft’s calibrated bank_by_phase entry — so the budget is effectively a defensive ceiling. It only narrows the chosen bank when callers force unusually aggressive manoeuvres.

Return type:

float

Parameters:

pitch_deg (float)

climb_altitude_profile(start_altitude, end_altitude, n_points=50)[source]

Generate altitude-vs-time curve during a climb.

Returns (times, altitudes) as numpy arrays in minutes and feet.

Return type:

tuple[ndarray, ndarray]

Parameters:
step_climb(start_altitude, end_altitude, pauses, wind_along_track=None)[source]

Total time and forward distance for a staged climb with pauses.

Real high-altitude aircraft step-climb out of weight-limited ceiling: they climb to an intermediate altitude, level off briefly to burn fuel and reduce gross weight, then continue climbing. For a NASA ER-2 sortie this typically looks like a 25-minute hold at FL611 climbing slowly under reduced weight, before final climb to the FL650 cruise altitude.

Each entry in pauses is (level_off_altitude, hold_duration). At each pause altitude, the aircraft holds (level orbit) for hold_duration adding only to total time — zero forward distance, since the aircraft is presumed to be orbiting at one location during the hold. Climb segments between pauses use the aircraft’s calibrated climb_profile via _climb().

Pauses are applied in altitude order; pauses outside the [start_altitude, end_altitude] range are silently skipped.

Parameters:
  • start_altitude (Quantity) – Starting altitude (e.g., airport elevation).

  • end_altitude (Quantity) – Final altitude (e.g., cruise altitude).

  • pauses (List[Tuple[Quantity, Quantity]]) – List of (altitude, hold_duration) tuples. Pass an empty list to recover the no-pause behavior of _climb().

  • wind_along_track (Quantity | None)

Return type:

Tuple[Quantity, Quantity]

Returns:

Tuple of (total_time, total_forward_distance) as pint.Quantity.

Example

ER-2 NM17 B planned climb-out: 25-min hold at FL611 climbing to FL650.

>>> ac = NASA_ER2()
>>> t, d = ac.step_climb(
...     start_altitude=6_187 * ureg.foot,
...     end_altitude=65_000 * ureg.foot,
...     pauses=[(35_600 * ureg.foot, 25 * ureg.minute)],
... )
time_to_takeoff(airport, waypoint, wind=None, wind_source=None, t_anchor=None, climb_plan='auto', n_samples=20)[source]

Calculate time from takeoff to the first waypoint.

Builds the path via _hybrid_path() with phase="climb" — 2D Dubins horizontally, integrated climb_profile vertically — so the climb-out timing reflects the aircraft’s calibrated rate-vs-altitude curve, not a constant pitch.

climb_plan controls the pre-cruise hold model:

  • "auto" (default): use this aircraft’s typical_climb_out.explicit_climb_plan if defined, otherwise no holds.

  • ClimbPlan: caller-supplied pauses, used as-is.

  • None: no holds; pure active-climb integration.

Return type:

dict

Parameters:
time_to_return(waypoint, airport, wind=None, wind_source=None, t_anchor=None, n_samples=20)[source]

Calculate time from the last waypoint back to the airport.

Builds the path via _hybrid_path() with phase="descent" — 2D Dubins horizontally, integrated descent_profile vertically.

When approach_profile is set, the descent is targeted at top-of-approach MSL (= airport.elevation + approach_profile.top_of_approach_agl) and a terminal "approach" segment is appended using ApproachProfile.time_to_touchdown(). When no profile is set, the legacy single-leg-to-runway behavior is preserved.

Return type:

dict

Parameters:
time_to_cruise(start_waypoint, end_waypoint, true_air_speed=None, wind=None, wind_source=None, t_anchor=None, phase='cruise', climb_plan=None, n_samples=20)[source]

Calculate time to fly between two waypoints.

Hybrid 2D Dubins (horizontal layout) + integrated vertical profile. Returns a dict with total_time, phases, and dubins_path (the 2D path; legacy key name kept for backward compatibility — use horizontal_path in new code).

Parameters:
  • wind (Optional[Tuple[float, float]]) – Optional (u_east, v_north) wind vector in m/s. When provided, horizontal turning arcs become trochoids, the 2D path length and timing account for wind drift, and the vertical phases project the wind onto the great-circle bearing for ground-speed-corrected forward distance.

  • phase (str) – Which entry of PhaseBankAngles drives the horizontal Dubins turn radius — see _hybrid_path(). Defaults to "cruise".

  • climb_plan (Optional[ClimbPlan]) – Optional ClimbPlan with level-off pauses to insert during the climb. Only takes effect when phase == "climb" and the leg actually climbs.

  • start_waypoint (Waypoint)

  • end_waypoint (Waypoint)

  • true_air_speed (Quantity | None)

  • wind_source (WindField | None)

  • t_anchor (datetime | None)

  • n_samples (int)

Return type:

dict

Pre-configured aircraft

class NASA_ER2[source]

Bases: Aircraft

NASA ER-2 high-altitude research aircraft.

Operates at 70,000 ft, acquiring data above 95% of the Earth’s atmosphere. Based at NASA Armstrong Flight Research Center (AFRC).

Speed schedules, vertical-rate profile, and approach behavior calibrated from cached NASA AFRC IWG1 in-situ flight logs covering NASA 806 and NASA 809. See [notebooks/calibration/er2/calibration.ipynb] for the full derivation: per-altitude-bin |VS| medians, breakpoint selection rules, and validation against per-sortie observed timing.

Vertical-rate highlights from the calibration:

  • Weight-management level-offs and holds during climb-out are modeled explicitly via typical_climb_out; the climb_profile itself is active-climb-only performance, not wall-clock climb-out timing.

  • Two-regime descent: peak idle-power |VS| ~3675 fpm at top-of- descent, decaying to ~840 fpm at top-of-approach as the aircraft configures for the terminal pattern.

  • Empirical 2.5° glideslope on the terminal approach (shallower than standard 3° ILS — ER-2’s approach geometry as flown across the IWG1 sortie set; touchdown estimate uses 6 sorties with fixes ≤ 50 ft AGL after ground-taxi trim).

__init__()[source]
class NASA_GIII[source]

Bases: Aircraft

NASA Gulfstream III (NASA 520) research aircraft.

Operated by NASA Langley Research Center (LaRC).

__init__()[source]
class NASA_GIV[source]

Bases: Aircraft

NASA Gulfstream IV (NASA 817) research aircraft.

Twin turbofan operated by NASA Armstrong Flight Research Center (AFRC).

Warning

Uncalibrated. Performance values come from manufacturer brochures / type-certificate data; no in-situ flight-data fit has been performed. Treat planning output as a best-effort starting point.

__init__()[source]
class NASA_GV[source]

Bases: Aircraft

NASA Gulfstream V research aircraft.

Operated by NASA Armstrong Flight Research Center (AFRC). Service ceiling 51,000 ft, cruise speed 500 kt (Mach 0.80). Currently undergoing modifications expected to conclude ~August 2026.

__init__()[source]
class NASA_C20A[source]

Bases: Aircraft

NASA C-20A (Gulfstream III variant, NASA 502) research aircraft.

Obtained from the U.S. Air Force in 2003. Primary platform for UAVSAR missions. Operated by NASA AFRC.

Note

Inferred. Performance is mirrored from the calibrated NASA_GIII model (same type certificate). C-20A-specific IWG1 calibration is deferred pending data access. Output is more reliable than a brochure-only model but may not capture C-20A-specific operational differences.

__init__()[source]
class NASA_P3[source]

Bases: Aircraft

NASA P-3 Orion (NASA 426) airborne science laboratory.

Four-engine turboprop capable of long-duration flights (8–14 hours) and large payloads up to 18,000 lbs. Operated by NASA Wallops Flight Facility (WFF).

__init__()[source]
class NASA_WB57[source]

Bases: Aircraft

NASA WB-57 (NASA 927) high-altitude research aircraft.

Based at NASA Johnson Space Center (JSC), Ellington Field. Operates up to 60,000 ft with 8,800 lbs useful payload.

__init__()[source]
class NASA_B777[source]

Bases: Aircraft

NASA Boeing 777 long-range research aircraft.

Operated by NASA Langley Research Center (LaRC). Very large payload capacity (75,000 lbs) and long endurance (18 hours).

Warning

Uncalibrated. Performance values come from manufacturer brochures / type-certificate data; no in-situ flight-data fit has been performed. Treat planning output as a best-effort starting point.

__init__()[source]
class KingAirA90[source]

Bases: Aircraft

Beechcraft King Air A90 twin-turboprop aircraft.

Warning

Uncalibrated. Performance values come from manufacturer brochures with no in-situ flight-data fit. No public IWG1-grade A-90 data is currently available; calibration is deferred. Treat planning output as a best-effort starting point.

__init__()[source]
class KingAirB200[source]

Bases: Aircraft

Beechcraft King Air B200 twin-turboprop aircraft.

__init__()[source]
class C130[source]

Bases: Aircraft

C-130H Hercules four-engine turboprop transport / research aircraft.

__init__()[source]
class TwinOtter[source]

Bases: Aircraft

DHC-6 Twin Otter STOL twin-turboprop utility aircraft.

__init__()[source]