Skip to content

Provide derivatives or second

The model consumes three derivative features — the rate of change of altitude, groundspeed and airspeed. Acropole gives you three ways to supply them, in increasing order of control.

Option A — let Acropole derive them from second

This is the recommended path. Provide a second column (elapsed seconds per sample) and Acropole computes each derivative as a backward difference divided by the time step (Δfeature / Δt). The column is detected by presence (name second, or a custom name passed as second="...") — no keyword argument is needed when it is already named second:

flight = pd.DataFrame({
    "typecode": ["A320", "A320", "A320"],
    "groundspeed": [400, 410, 420],
    "altitude": [10000, 11000, 12000],
    "vertical_rate": [2000, 1500, 1000],
    "second": [0.0, 4.0, 8.0],   # drives the derivatives
})

result = fe.estimate(flight)   # also produces fuel_cumsum

This path is the only one that also emits the fuel_cumsum column — emitted whenever the second column is present.

Duplicate timestamps

Where two consecutive samples share a timestamp (Δt == 0), the derivative is set to NaN rather than inf, making the undefined derivative visible. If this produces an unknown fuel contribution, the cumulative fuel stays unknown from that row onward.

Missing data and cumulative fuel

With second, derivatives are computed within each aircraft typecode group. A group with only one sample has no time difference: its computed derivatives are NaN. Explicitly supplied derivatives can replace those undefined derivatives.

Missing or unsupported typecodes emit a warning and yield NaN fuel flow. The fuel_cumsum column integrates the frame in its existing row order. Once a fuel contribution is unknown, its cumulative total and all subsequent totals are NaN. The estimator preserves that uncertainty instead of assuming zero consumption. Estimate individual trajectories separately when you need separate flight totals.

Option B — no second, no derivatives

If you provide neither second nor pre-computed derivatives, Acropole falls back to a reasonable default: d_altitude is derived from vertical_rate (converted ft/min → ft/s) and the speed derivatives are treated as zero.

flight = pd.DataFrame({
    "typecode": ["A320", "A320", "A320"],
    "groundspeed": [400, 410, 420],
    "altitude": [10000, 11000, 12000],
    "vertical_rate": [2000, 1500, 1000],
})

result = fe.estimate(flight)   # no fuel_cumsum, speed accelerations assumed 0

This is the least accurate path — prefer Option A whenever you have timestamps.

Option C — supply pre-computed derivatives

If you already have accelerations from your own pipeline, put them in the frame and point estimate at those columns. Any derivative you supply overrides what Acropole would compute; any you omit is derived from second (if given) or falls back as in Option B:

flight = pd.DataFrame({
    "typecode": ["A320", "A320", "A320"],
    "groundspeed": [400, 410, 420],
    "altitude": [10000, 11000, 12000],
    "vertical_rate": [2000, 1500, 1000],
    "second": [0.0, 4.0, 8.0],
    # your own per-second derivatives:
    "d_alt": [25.0, 25.0, 25.0],   # ft/s
    "d_gs": [2.5, 2.5, 2.5],       # kt/s
    "d_as": [2.5, 2.5, 2.5],       # kt/s
})

result = fe.estimate(
    flight,
    second="second",
    d_altitude="d_alt",
    d_groundspeed="d_gs",
    d_airspeed="d_as",
)

This mixes freely: e.g. supply d_groundspeed only, and d_altitude / d_airspeed are still derived from second.

Mapped columns must exist

A derivative column you name but that is absent from the frame is silently ignored — estimate falls back to deriving it (no error is raised). Double-check the column names match, or the pre-computed values you intended to pass will be dropped.

Summary

Inputs Altitude derivative Speed derivatives fuel_cumsum
second given Δalt / Δt Δspeed / Δt ✅
nothing given vertical_rate / 60 0 ❌
d_* given uses your value uses your value ✅ if second given