Engineering methodology
Trackday Analyst turns a consumer GPS lap-timer export into corner-level coaching. This page explains the analysis chain in engineering terms — how each derived quantity is computed, which assumptions it rests on, and where it stops being trustworthy. The honesty about limits is deliberate: a number is only useful if you know what it does and does not mean.
Everything below is the engineering detail behind those five sentences: how each number is computed, what it assumes, and where it stops being trustworthy. You do not need any of it to use the app. For the rider-facing versions instead, read the User Guide or what the numbers mean.
Every screen in the app is one of three layers, and they are kept strictly separate.
The first layer is raw telemetry: the position, speed, lean, altitude, and accelerometer samples exactly as a Diablo Super Biker GPX or a RaceBox CSV recorded them — typically at about one sample per second for the Diablo device. These values are never smoothed, corrected, back-filled, or overwritten. A missing or implausible reading stays missing.
The second layer is derived analytics: laps, sectors, distances, corners, braking zones, the friction circle, cumulative time deltas, and consistency. Each of these is computed from the raw layer and stored separately from it, so a derived value can never be mistaken for something the device measured. Where a field is derived, the app marks it — a superscript D badge in the cursor inspector, explicit "calculated" headers in the CSV export.
The third layer is coaching: short, plain-language statements about where time is won or lost between two laps. These are conclusions built on the second layer, and they are phrased to describe what happened, not to prescribe a physics-model ideal.
All three layers run entirely in your browser. There is no account, no server, and no upload step; loading a file hands its bytes to JavaScript on your own machine and nothing leaves it. Satellite map tiles are the only thing fetched from the network, and the analysis works without them.
Both supported devices record a lean-angle channel directly, so lean itself is a source value, not an estimate. Where judgement is needed is the lateral load the bike carries through a corner — the horizontal axis of the G-G (friction-circle) diagram — because the device's own accelerometer usually cannot be trusted to supply it.
On the Diablo logger the measured longitudinal accelerometer channel is authoritative in name only. Its axes are labelled by the manufacturer's documented convention (longitudinal, lateral, vertical), but the recorded longitudinal values sit around ±0.3 g — far below the 0.8–1.2 g of real track braking — and show essentially zero correlation with the deceleration implied by GPS speed. A body-fixed sensor on a leaning motorcycle, its mounting, and exporter filtering are the likely causes. Using that channel to measure braking or cornering would fabricate an interpretation the data contradicts, so the app refuses to.
Instead the app applies an explicit trust model. It classifies the measured accelerometer as usable only when it is not frozen (near-zero variance), not inconsistent with GPS-derived deceleration, and within a plausible calibrated range. When the channel fails those checks — which the Diablo's always does — the analytics fall back to values derived from data that is trustworthy: lateral load from the recorded lean angle, and longitudinal load from the rate of change of GPS speed. The friction-circle diagram is drawn from those derived quantities by default, with an honest note that it is derived rather than measured. An advanced rider can force the raw channel back on for inspection, but no action is required for the default to be the trustworthy one.
The app also measures the effective sample rate from the data itself and flags anything below 5 Hz as low-frequency, because corner and braking analysis on a roughly 1 Hz source is inherently coarse. The design deliberately does not assume "GPS-derived is always better" — it is better only because this device's accelerometer is poor. A future higher-rate logger with a sound accelerometer would pass the trust checks and be used directly. The thresholds that draw these lines are named constants tuned against the current recordings, not a large calibrated corpus.
RaceBox CSV exports a raw gyroscope alongside its recorded lean angle. Trackday Analyst keeps that gyroscope byte-honest, then uses GyroX with the lean observation in a 2-state linear Kalman filter: one state estimates roll angle and the other estimates gyroscope bias. The resulting bias-corrected roll rate replaces the noisy finite difference of lean for the corner-table roll-rate metric. The raw channels remain available; the filter produces a separate, labelled analysis input rather than rewriting what the device recorded.
A Kalman filter is useful here for reasons a simple smoother would hide. The process noise uses each recording interval, so irregular timestamps enter the estimate instead of being treated as evenly spaced. A recording gap grows the state covariance; when that uncertainty is too high, the result is honestly marked unavailable rather than bridged. The bias is estimated online, too, instead of assuming that a consumer device starts and stays at zero. Missing observations, missing gyro samples, and rejected observations have explicit status rules rather than silent interpolation.
That does not make this a calibrated physical instrument. RaceBox's lean angle is already a filtered device output, so the filter deliberately over-states its observation noise; the estimator is practical, but its statistical optimality is nominal. More importantly, a reproducible audit of the two bundled RaceBox exports failed the planned calibration thresholds for scale and stationary noise. The fused rate is therefore adopted as a labelled analysis input, not claimed as a calibrated measurement. In the corner table, the gyro annotation says exactly that; the Sensor fusion card in Session data shows the fused and lean-derived traces, bias, resets, statuses, and limitations.
Sources without a gyroscope, including Diablo GPX, retain the lean-derived roll-rate computation. The choice follows the available capability, not the file name.
Corners are found from geometry, not from a track database. The app projects the lap's latitude/longitude onto a local plane, measures the heading change between consecutive points, and turns that into a smoothed curvature series in degrees of turn per metre. A corner is a run of samples where that curvature stays above a threshold with a consistent turning direction and accumulates at least a minimum total heading change — enough to reject GPS wiggle and gentle kinks. Corners that nearly touch are merged, and the apex is taken as the slowest recorded sample within the span.
Braking zones are derived from the speed channel alone. Starting at a corner's minimum speed, the app walks backwards through the samples while speed keeps rising, and calls that span a braking zone if the total speed drop clears a minimum. As explained above, the longitudinal accelerometer is not used to detect or corroborate braking, because it does not track deceleration.
The honest limits here are real. At roughly one sample per second and tens of metres of travel between samples, a braking point's location carries a tens-of-metres uncertainty, so the app shows braking as a soft zone rather than a precise point, and leads with a speed triplet (entry, minimum, exit) rather than a spurious "you braked at X metres" claim. Shallow, high-speed sweepers whose curvature never crosses the threshold can be missed, and every threshold in this stage is tuned against the bundled fixtures rather than a broad sample of tracks.
Lap boundaries come from the device's own lap markers where present. The difficulty is that the logger stamps a new lap on the first sample after the finish line, which at 1 Hz can be tens of metres past it at a different offset every lap. Taking that first sample as "zero" would fold sampling phase into every comparison. The app instead fits a single transverse finish line from the geometry of the lap-entry segments, intersects each lap's path with it, and interpolates the crossing time between the two bracketing real samples. The same sub-sample gate-fitting produces sector splits when a file's own sector configuration is absent, by detecting where the trajectory crosses known gate coordinates. No lap or sector is invented where the evidence is missing.
The cumulative time delta — the running "how far ahead or behind" curve between two laps as a function of distance — needs a value for "elapsed time at distance d" that no single sample holds. The app builds each lap's (distance-from-start, elapsed-time) series from real samples only and linearly interpolates between the two bracketing points, evaluating the delta at the union of both laps' real sample distances and only over the range both laps cover. It never extrapolates beyond recorded data. Nearest-sample lookup was rejected because its ±0.5 s quantization at this sample rate is larger than many real per-corner deltas and would produce a misleading staircase.
The assumptions are stated plainly: the delta presumes roughly constant speed across each one-second interval, the fitted finish line is an estimate from available crossings rather than surveyed circuit geometry, and both inherit GPS noise. Where alignment can't be built cleanly on both sides, the pair falls back together to raw first-sample origins rather than mixing an aligned origin with a raw one.
For a comparison of two circuit laps, the coaching layer reports where the time actually went: the sectors and corners with the largest cumulative-time swings, up to a few "largest local changes" cards that open the corner where lap B gained or lost the most, an inferred neutral-motion measure (how long derived longitudinal acceleration was near zero while leaned over, not a throttle or brake measurement), and an apex table putting minimum speed, apex lean, and flick rate side by side.
Just as important is the deliberate restraint. The summary compares two laps you actually rode; it does not model a theoretical fastest line or issue prescriptions like "brake ten metres later" or "you had more grip available." It states no absolute limits. Neutral motion has no universal better/worse direction: its A/B difference is descriptive until it can be tied to a named time-loss reference. The "largest local changes" are presented as neutral cards that show where a difference occurred without asserting why — the cause is left to the rider, who was there. This keeps the coaching anchored to measured differences rather than to a physics model the 1 Hz data cannot support. The narrative is available for circuit comparisons; it is not generated for road runs.
Saying where a corner loses time is arithmetic. Saying what is different there is where a telemetry product starts inventing, so each family below is listed with the channel it reads, the test it must pass, and the sentence it is not allowed to write.
Two rules apply to all five. The reference is always your own best valid lap — never a model, a pro, or another rider. And a difference must clear two independent tests before it becomes a sentence: an absolute floor, so trivia stays out, and its own uncertainty at twice over, so the recording must actually be able to demonstrate it. A difference that fails keeps its number in the evidence rows and loses its sentence, with the reason shown.
Reads position and speed. Measures how far before the corner speed starts falling, compared with your best lap. Uncertainty combines two things: how precisely a sample is located, and how far the detected onset could slide and still be the same observation — because the onset is found by walking back until the speed decrease goes flat, and anywhere inside that flat run would have given the same answer. Carrying only the first term would let a 168 m difference be printed as ±1 m. Will not say that you braked, braked early, braked hard, or should move a braking marker. There is no brake channel; there is a speed trace that starts to drop.
Reads speed. Measures the difference in the lowest recorded speed through the corner. Uncertainty is the band inside which speed still counts as "at minimum", because within it the data does not distinguish one sample's minimum from another's. Will not say "apex". An apex is a physical place no sample rate here can resolve, so the product says the slowest recorded point and means exactly that.
Reads speed and position. Measures speed at the corner's entry and exit boundaries, as two separate numbers, so arriving slowly and driving out slowly stay distinguishable. Uncertainty combines how precisely a speed is known with how much speed changes across the distance within which the boundary itself sits — which correctly makes a reading on a hard braking approach less certain than one at constant speed. Will not say anything about throttle. A higher exit speed is an outcome, not an input.
Reads speed and time. Measures how long the corner is spent with no speed change the recording can resolve. "No resolvable change" is a criterion, not a fixed number: acceleration within twice its own propagated uncertainty, evaluated at each recording's own resolution over a window fixed in seconds. A window fixed in samples would quietly mean a different physical quantity on every device. Will not say that you were coasting, off the brakes, or off the throttle. It says the speed trace is flat, which is all that was recorded.
Reads position. Measures how far your path through the corner sits, left or right, from the path your best lap took at the same point in the lap. The comparison happens on a shared distance axis, and the difference between two laps is split into an along-track part (the sampler firing somewhere else — measurement noise) and a cross-track part. Only the second is reported, and only when the two laps could be aligned to the same physical point closely enough for it to mean anything; often they cannot, and the page says so. Being honest about that second part: it contains the line you rode and whatever sideways GPS error the two passes carried, and this data cannot separate the two. That is why a small offset is never reported — the floor exists precisely because the bound does not cover lateral scatter. Will not say that a line is correct, ideal, or the racing line. This product has no track boundaries and no ideal line, and it compares you only to yourself.
They are listed side by side, and the surface states that the recording cannot rank one of them as the cause. A slower entry, a lower minimum speed, and a wider line at the same corner are three observations, not a diagnosis; picking one would be the product asserting a causal model it has no way to test.
These comparisons need positions dense enough to separate one part of a corner from another, which means 20 Hz or better. Anything slower — including every standard ~1 Hz export — supports none of them. It does not go quiet: each family is named with the frequency it needed and the frequency the recording has, because a stated limit is more useful than a blank.
The guiding rule across the whole app is that source telemetry is never silently altered. Missing or implausible values are surfaced rather than fabricated: a gap in the recording is drawn as a break in the line, not bridged with an invented segment, and the break threshold is worked out from each session's own sampling rate rather than a fixed number of seconds. Suspect GPS or accelerometer samples are flagged, never deleted.
Raw and derived channels are kept in separate places in both the code and the interface, so a computed lap time, distance, delta, or coaching metric can always be told apart from something the device recorded. The Session data view exposes the underlying facts directly — field availability, malformed values, sampling intervals, and a classification of every gap as a genuine outage, a stationary stop, or suspended transit — so you can check the source before trusting a strange-looking graph. Those classifications use fixed thresholds that can misjudge an unfamiliar device or very slow movement, which is itself stated in that view.
None of this makes the app infallible; it makes it legible. Every derived number on the screen has a method behind it, an assumption inside it, and a limit past which it should not be trusted — and the app tries to show you all three. For how to drive the interface itself, see the User Guide.