Analyse a complete flight
This guide walks through a full flight — taxi, climb, cruise, descent — loaded
from the example_flight.csv shipped under examples/, visualises its
trajectory, estimates the fuel flow, and compares the estimate against the
measured fuel flow recorded in the file. It then shows how the estimate
degrades gracefully as optional features are removed.
It is the documentation counterpart of the examples/fuel_estimation.ipynb
notebook.
Dependencies
The plots below use matplotlib and pandas, which are not core
dependencies of acropole. Install them alongside the pandas extra:
1. Load and resample the flight
The model expects a sampling rate of about 4 seconds. The example flight is
recorded at 1 Hz, so we resample with iloc[::4]:
import pandas as pd
from matplotlib import pyplot as plt
pd.options.display.max_columns = 999
flight = pd.read_csv("example_flight.csv")
flight = flight.iloc[::4].reset_index(drop=True)
flight.head()
The columns follow a QAR naming scheme (FLPL_AIRC_TYPE, GRND_SPD_KT,
ALTI_STD_FT, …); we map them to the model inputs with keyword arguments in
the next step. The file also carries FUEL_FLOW_KGH, the measured per-engine
fuel flow, which we use as ground truth.
2. Visualise speed and altitude
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12, 3))
ax1.plot(flight.FLIGHT_TIME, flight.GRND_SPD_KT, color="b", lw=1, label="Ground Speed")
ax1.plot(flight.FLIGHT_TIME, flight.TRUE_AIR_SPD_KT, color="g", lw=1, label="True Air Speed")
ax1.legend()
ax1.set_xlabel("Flight time (s)")
ax1.set_ylabel("Speed (kt)")
ax2.plot(flight.FLIGHT_TIME, flight.ALTI_STD_FT, color="b", lw=1)
ax2.set_xlabel("Flight time (s)")
ax2.set_ylabel("Altitude standard (ft)")
ax3.plot(flight.FLIGHT_TIME, flight.VERT_SPD_FTMN, color="b", lw=1)
ax3.set_xlabel("Flight time (s)")
ax3.set_ylabel("Vertical Speed (ft/min)")
plt.tight_layout()
3. Estimate fuel flow (all features)
With timestamp, true airspeed and mass available, the estimate is at its most accurate:
from acropole import FuelEstimator
fe = FuelEstimator()
flight_fuel = fe.estimate(
flight,
typecode="FLPL_AIRC_TYPE",
groundspeed="GRND_SPD_KT",
altitude="ALTI_STD_FT",
vertical_rate="VERT_SPD_FTMN",
# optional features:
second="FLIGHT_TIME",
airspeed="TRUE_AIR_SPD_KT",
mass="MASS_KG",
)
estimate adds fuel_flow (kg/s), fuel_flow_kgh (kg/h) and — because
second was given — fuel_cumsum (cumulative kg).
Compare to the measured fuel flow
acropole predicts the total aircraft fuel flow (single-engine output
scaled by ENGINE_NUM), whereas FUEL_FLOW_KGH in the file is recorded
per engine. To compare like with like, scale the measured trace by the
engine count — 2 for this A320, but read it from your own data rather than
hard-coding it (a quad would be 4):
n_engines = 2 # A320 — use ENGINE_NUM for your aircraft
plt.plot(flight_fuel.FLIGHT_TIME, flight_fuel.FUEL_FLOW_KGH * n_engines, lw=1, label="actual (kg/h)")
plt.plot(flight_fuel.FLIGHT_TIME, flight_fuel.fuel_flow_kgh, alpha=0.8, lw=1, label="estimate (kg/h)")
plt.legend()
plt.show()
The estimate tracks the measured curve closely across all flight phases.
4. How optional features affect the estimate
The only required inputs are typecode, groundspeed, altitude and
vertical_rate. Everything else is optional and improves accuracy. Dropping
features one by one shows their contribution.
Without mass
flight_fuel = fe.estimate(
flight,
typecode="FLPL_AIRC_TYPE",
groundspeed="GRND_SPD_KT",
altitude="ALTI_STD_FT",
vertical_rate="VERT_SPD_FTMN",
second="FLIGHT_TIME",
airspeed="TRUE_AIR_SPD_KT",
# no mass
)
Without mass nor airspeed
When airspeed is omitted it defaults to groundspeed:
flight_fuel = fe.estimate(
flight,
typecode="FLPL_AIRC_TYPE",
groundspeed="GRND_SPD_KT",
altitude="ALTI_STD_FT",
vertical_rate="VERT_SPD_FTMN",
second="FLIGHT_TIME",
# no airspeed, no mass
)
Minimum information
With only the four required columns, the derivatives fall back to a
quasi-steady-state assumption (d_groundspeed = d_airspeed = 0,
d_altitude = vertical_rate / 60):
flight_fuel = fe.estimate(
flight,
typecode="FLPL_AIRC_TYPE",
groundspeed="GRND_SPD_KT",
altitude="ALTI_STD_FT",
vertical_rate="VERT_SPD_FTMN",
)
Each removed feature widens the gap with the measured curve, but the estimate
remains usable even with the minimum input set. Provide second whenever you
can — it unlocks the speed/altitude derivatives that drive accuracy during
acceleration and climb.