Skip to content

Derived channels & metrics

Every lap stores a full 60 Hz sample series. Some columns are raw packet values; others are computed at capture time. This page lists every stored channel with its exact formula, then the per-lap aggregates, then the channels the frontend derives on the fly.

Stored sample columns

One value per column per tick (~60/s):

Column Formula Unit
t tick_index × 1/60 s
dist running Σ speed_mps × 1/60 m
speed speed_mps × 3.6 km/h
throttle raw_byte ÷ 2.55 % (0–100)
brake raw_byte ÷ 2.55 %
coast 1 if throttle < 1 % and brake < 1 % flag
gear low nibble of the gear byte (15 = neutral)
rpm raw rpm
boost raw − 1.0 (packet stores bar + 1) bar
tire_slip mean of the four wheel slips ratio
yaw_rate abs(angular_velocity_y) rad/s
pos_x, pos_z raw world coordinates m
body_height raw × 1000 mm
fuel raw fuel level L
slip_fl/fr/rl/rr abs(wheel_rad_per_s) × tire_radius ÷ speed_mps ratio
tt_fl/fr/rl/rr raw tire temps °C
sus_fl/fr/rl/rr suspension_travel × 1000 mm
aids bitmask: TCS=1, ASM=2, handbrake=4, rev limiter=8 mask
surface per-wheel surface codes, 4 bits each, FL in the lowest nibble (0 = no data, 1 = tarmac, 2 = kerb, 3 = dirt, 4 = grass, 5 = sand, 6 = snow, 7 = other) — packet C only mask

Optional columns

These need an extended packet format, and a lap that did not carry one from start to finish does not have the column at all rather than a column of zeros. A zero-filled steering trace reads as "the driver never turned"; an absent panel says nothing false. The rule is enforced once, at lap completion (prune_optional in app/processing/laps.py), so it also covers a recording whose packet format changed mid-lap.

Column Needs Formula Unit
steer packet B wheel_rotation as broadcast rad
acc_lat packet B sway, raw see below
acc_long packet B surge, raw see below
acc_vert packet B heave, raw see below
throttle_f packet ~ throttle_filtered ÷ 2.55 %
brake_f packet ~ brake_filtered ÷ 2.55 %

Filtered pedals are the pedal position after the aids acted on it. The gap to the raw throttle / brake column is the intervention itself — TCS trimming throttle, ABS bleeding brake pressure — measured rather than inferred from the aids bitmask, which only says whether an aid was active at all.

Accelerometer units are calibrated, not assumed

GT7 documents neither a unit nor a sign convention for sway/heave/surge, and the simulator source cannot prove what a real console sends. The channels are therefore stored raw, and analysis.accel_calibration() fits each axis against physics the same lap already recorded:

Axis Reference Recovers
lateral v × ω, with ω the signed yaw rate taken from the driven path (the stored yaw_rate column is absolute, so it cannot settle the sign) unit and sign
longitudinal dv/dt from the speed trace unit and sign
vertical nothing; no independent reference exists

Each fit is a least-squares slope forced through the origin (zero acceleration must mean zero reading), graded by R² about zero rather than a mean-centred correlation — a long constant-rate braking zone makes both series near-constant, where Pearson r collapses into numerical noise. A fit needs ≥ 150 qualifying samples and R² ≥ 0.75; below that the axis reports fitted: false, falls back to assuming m/s², and the g-g panel says the scale is unverified.

The result is delivered as g_per_unit — multiply the raw channel by it to get g, sign included — on the accel key of /api/analysis/compare, fitted on the reference lap and applied to every lap in the comparison so they share one axis.

Wheel slip is a slip-ratio proxy: wheel surface speed divided by car speed. < 1 under braking means the wheel is locking; > 1 under power means it's spinning. Below 1 m/s car speed the ratio is meaningless, so all four are pinned to 1.0.

Per-lap aggregates

Computed once when the lap is saved (n = number of samples):

Metric Formula
Fuel consumed max(0, fuel_at_lap_start − fuel_at_lap_end) L
Full throttle % 100 × count(throttle ≥ 98 %) ÷ n
Full brake % 100 × count(brake ≥ 98 %) ÷ n
Coasting % 100 × count(coast flag set) ÷ n
Tire spin % 100 × count(tire_slip ≥ 1.1) ÷ n
Max speed max(speed) km/h
Min body height min(body_height) mm
TCS / ASM active % 100 × count(aid bit set) ÷ n
Off-track count excursions where ≥ 3 wheels sat on a loose surface for ≥ 6 ticks; -1 = unknown (no surface data)
Clean lap off_track_count == 0; null = unknown — distinct from counts_for_best, which flags partial pit out-laps

Engine health is tracked as running per-lap extremes rather than per-tick columns (these values drift over minutes, not corners):

  • max_water_temp, max_oil_temp — running maxima (°C)
  • min_oil_pressure — running minimum (bar), sampled only while RPM > 1200 so idling in the pits doesn't record a misleading low; −1 means unknown

Gearing is captured once per lap from the lap-boundary packet: the non-zero gear ratios, the tune's transmission top speed, and the redline (rpm_alert_max).

Frontend-derived channels

These are computed in the browser from the stored columns, never persisted:

Channel Formula
Slip front / rear avg (slip_fl + slip_fr) ÷ 2, (slip_rl + slip_rr) ÷ 2
Tire temp front / rear avg mean of the two front / rear corners
Tire temp F−R balance mean(tt_fl, tt_fr) − mean(tt_rl, tt_rr) °C — positive = fronts running hotter (push/understeer working the fronts)
Susp travel front / rear avg mean of the two front / rear corners
TCS cut max(0, throttle − throttle_f) % — how much throttle traction control took away
ABS release max(0, brake − brake_f) % — how much brake pressure ABS gave back
Lateral / longitudinal / vertical g acc_* ÷ 9.80665 as a trace (assumes m/s²; the g-g panel uses the fitted scale instead)

Laps recorded before per-corner channels existed simply skip these lines rather than erroring.

Units: speed is the only channel with a display transform (km/h → mph × 0.621371 when imperial units are selected). Everything else displays in its stored unit.

Gearing panel math

The estimated speed at redline for gear i assumes the tune's top speed is reached in top gear, then scales by ratio:

speed_i = top_speed × (ratio_top ÷ ratio_i)

A note on "tiers"

If you browse the code or TODO.md you'll see channels grouped into tiers. That's a roadmap grouping, not a runtime concept: Tier 1 = surface data already in the packet (per-corner slip/temps/suspension, aids, engine health, gearing — all implemented), Tier 2 = derived analytics like sector splits (sectors still future work; the g-g diagram is implemented from the broadcast accelerometer rather than derived from speed deltas), Tier 3+ = larger features (overlay, webhooks, strategy — implemented). There is no brake-temp or slip-angle channel — GT7 doesn't send them and they aren't synthesized.