Project dossier
GridPulse
Formula 1 telemetry analytics and replay platform for lap, sector, and driver comparison.
What it solves
Overview
GridPulse ingests race telemetry, normalizes high-frequency time-series data, and renders interactive replay and analysis views for speed, throttle, brake, gear, tires, and lap comparisons. Interview focus: explain FastF1 ingestion, cache behavior, full-session telemetry versus lap fallback, merge_asof alignment, one-second resampling, interpolation, lap/compound mapping, time-base shifting, race-control and team-radio normalization, replay request caching, and why one shared race clock prevents UI drift.
Target audience
System design
Architecture
A FastAPI backend fetches or accepts F1 telemetry, processes it into aligned series, and serves it to a React plus D3 visualization layer. Replay mode synchronizes charts and session state over time. The source backend loads FastF1 race sessions, enables a cache directory, merges position and car telemetry, resamples to one-second intervals, interpolates continuous channels, forward-fills discrete channels, computes global time bases, and returns replay-ready payloads consumed by React hooks and replay math utilities.
Architecture diagram
Ingestion layer
Fetches race, driver, lap, tire, and telemetry data from FastF1 or OpenF1 style sources.
Processing layer
Aligns time-series channels, segments laps and sectors, and computes replay-ready samples.
API layer
Serves sessions, lap comparisons, telemetry channels, and replay metadata.
Visualization layer
Renders SVG and canvas-style views for speed traces, throttle/brake overlays, and replay panels.
FastF1 session layer
Loads seasons, race schedules, sessions, laps, weather, race-control messages, car data, and position data through FastF1.
Replay normalization layer
Merges car and position streams, maps lap metadata onto telemetry, resamples to one-second rows, and shifts timestamps onto a frontend timeline.
Client replay cache layer
The React hook deduplicates telemetry and team-radio fetches by cache key so retries and re-renders do not hammer the backend.
Implementation surface
Tech stack
Telemetry API, replay metadata, and processed session endpoints.
Data ingestion, normalization, lap segmentation, and metric computation.
Interactive telemetry workspace and replay screens.
Custom SVG visualizations for lap traces and driver comparisons.
Reproducible local and deployment environment.
Source data adapters for race telemetry and session metadata.
Aligns telemetry rows with nearest car/position samples and latest lap metadata.
Stores downloaded race/session data locally or in /tmp for hosted environments.
Frontend data fetching for telemetry replay and team radio endpoints.
Binary search, time-window slicing, lap completion, pit-stop visibility, sector visibility, and race-clock formatting.
Operational flow
How it works
Telemetry is ingested from a race data source, normalized into comparable time-series channels, exposed through an API, and replayed in the browser with synchronized visualizations.
Load session data
The backend fetches race session, driver, lap, tire, and telemetry records for a selected event.
Normalize channels
Speed, throttle, brake, gear, RPM, and timestamps are aligned so comparisons use a common timeline.
Segment laps
The processor splits telemetry by lap and sector so driver comparisons are meaningful.
Serve analysis views
FastAPI returns processed traces, deltas, tire windows, and replay metadata to the frontend.
Synchronize replay
The browser advances a replay clock and updates every chart from the same timestamp.
Merge car and position telemetry
The backend merges car channels such as speed, throttle, brake, RPM, and gear with position channels such as X and Y using nearest-time alignment.
This prevents separate traces from drifting when the replay needs both motion and car-state channels.
Resample and fill channels
Telemetry is resampled to one-second rows, continuous channels are interpolated, and categorical channels such as lap, tire compound, gear, and DRS are forward-filled.
This creates smoother playback while keeping discrete racing state stable between raw samples.
Normalize race-control and radio messages
Frontend parsing converts mixed time formats into seconds and sorts messages so they appear at the right replay moment.
Compute replay visibility
Replay utilities decide whether laps, sectors, pit stops, race-clock messages, and time windows should be visible at the current replay time.
Sequence diagram
Concept depth
Key concepts
Telemetry channels arrive as sequences with timestamps. Comparing drivers requires alignment so speed, throttle, and brake values refer to the same moment or distance.
In GridPulse: GridPulse normalizes high-frequency F1 telemetry before rendering lap comparisons and replay.
Confidence
Implementation evidence
Code highlights
Replay cursor lookup
The replay engine finds the closest telemetry sample for the active replay time.
Binary search avoids scanning every sample on each animation frame.
A shared elapsed time keeps speed, throttle, brake, and map views synchronized.
Telemetry normalization
Raw records are converted into a consistent shape before charts consume them.
A consistent elapsed_ms axis makes frontend replay independent of source timestamps.
The chart layer receives cleaned values instead of source-specific column names.
Telemetry merge and resample
The backend creates replay-ready rows by aligning sources, resampling, interpolating continuous values, and forward-filling discrete state.
Continuous and categorical channels are filled differently.
The tolerance prevents joining samples that are too far apart in time.
Replay request cache
The frontend caches in-flight replay requests so duplicate effects share the same network work.
Failed requests are removed so retry can fetch again.
The key includes API URL, year, race, and retry token.
Contracts
API design
Base URL: http://localhost:8000/api
/sessionsLists available seasons, races, and sessions for telemetry analysis.
/sessions/{sessionId}/telemetryReturns processed telemetry channels for selected drivers and laps.
/sessions/{sessionId}/replayReturns replay metadata and synchronized samples for playback.
/sessions/{sessionId}/compareReturns lap deltas and channel overlays for driver comparison.
/api/build_infoReturns container build metadata so deployed environments can prove they are running the latest backend image.
/api/seasonsReturns seasons from 2018 through the current year for replay selection.
/api/{year}/{race_name}/race/team_radioReturns team-radio messages normalized for the replay timeline when source data is available.
/api/{year}/{race_name}/race/weatherReturns weather samples used to explain stint, tire, and pace changes during the replay.
State model
Database design
Data relationship diagram
sessions
Race weekend metadata such as season, round, race name, and session type.
laps
Lap-level timing, driver, sector, and tire information.
telemetry_samples
Aligned channel samples used by charts and replay.
driver_session
Driver-level race metadata including team color, classified position, total time, and driver number.
race_control_message
Official messages normalized to replay seconds for timeline display.
team_radio_message
Team-radio snippets normalized to replay time and linked to driver/session metadata.
weather_sample
Weather readings for air temperature, track temperature, humidity, pressure, wind, and rainfall.
Architecture decisions
Trade-offs
Charting library
D3.js over Chart.js or Recharts
F1 telemetry needs custom scales, synchronized cursors, overlays, and non-standard interactions that are easier with D3 primitives.
Backend processing
FastAPI with Python over Browser-only parsing
Python has stronger data tooling for telemetry normalization, and the browser should receive replay-ready payloads.
Deployment runtime
Docker over Host-machine setup
Telemetry libraries can be environment-sensitive, so containers reduce setup drift.
Telemetry granularity
One-second resampled replay rows over Sending every raw high-frequency sample
Raw telemetry can be large and uneven. One-second rows are smoother for browser replay and reduce payload size, while still showing strategy and performance trends.
Source alignment
merge_asof with tolerance over Exact timestamp joins
Car and position data do not always share exact timestamps. Nearest-time joins with a tolerance recover usable rows without creating arbitrary matches.
Client request behavior
In-flight request cache over Every hook run starts new network calls
Telemetry replay payloads are heavy. Reusing identical in-flight promises protects the backend and improves page stability.
Replay timeline
Shared race clock over Independent component timers
Charts, map, lap panels, messages, sectors, and pit stops must agree on one current time to avoid replay drift.
Lessons learned
Challenges and solutions
Problem
Telemetry sources can have uneven sampling and missing channels.
Solution: Normalize timestamps, keep channel availability explicit, and make charts tolerant of missing series.
Lesson: Data visualization correctness starts with clear assumptions about source quality.
Problem
Replay views can drift if each chart manages its own time state.
Solution: Use one replay clock and derive all chart cursors from that shared elapsed time.
Lesson: Synchronized visualization needs a single source of temporal truth.
Problem
FastF1 versions and sessions can expose different message-loading capabilities.
Solution: Attempt session.load with messages and fall back to telemetry/laps/weather when messages are unsupported.
Lesson: External data libraries need compatibility paths around version differences.
Problem
Synthetic rows at time zero can make lap one appear to last through formation/grid delay.
Solution: Avoid injecting fake time-zero rows and leave leading LapNumber empty until the real first LapStartTime.
Lesson: Visualization fixes can corrupt domain meaning if they ignore race timing.
Problem
Race replay can fetch large payloads repeatedly during React effect reruns.
Solution: Cache in-flight replay requests and clear failed entries so retries remain explicit.
Lesson: Frontend data loading strategy matters when payloads are expensive.
Runbook
Requirements and future work
Requirements
- Python 3.x with FastAPI for the processing API.
- React and D3.js for custom telemetry visualizations.
- Docker for reproducible local setup.
- FastF1 or OpenF1-style data source for race telemetry.
- FastF1 cache directory must be writable; hosted environments can use /tmp/f1_cache.
- ALLOWED_ORIGINS must match the frontend origin unless wildcard mode is intentionally used.
- Telemetry replay expects sessions with laps and telemetry available from FastF1 or local extracted CSVs.
- Large races need payload-conscious frontend rendering and request deduplication.
Future improvements
- Add live session monitoring when source latency allows it.
- Persist processed race caches for faster repeat analysis.
- Add tire degradation modeling and pit strategy simulation.
- Add persistent processed-session cache keyed by year, race, session, driver set, and processing version.
- Add distance-based interpolation for driver comparison views where elapsed time hides corner-by-corner differences.
- Add source-quality badges for missing channels, interpolated segments, and fallback telemetry paths.
- Add lap-delta explanations that connect time loss to throttle, brake, gear, DRS, tire, and weather changes.
Active recall
Interview Q&A
Why use D3 instead of a standard chart library?
What makes telemetry comparison difficult?
How do you prevent replay drift across charts?
Why use merge_asof for telemetry alignment?
Why resample telemetry to one-second intervals?
Why should categorical telemetry be forward-filled instead of interpolated?
How does GridPulse avoid replay drift?
What is the purpose of time-base shifting?
Why cache in-flight replay requests on the client?
What can go wrong if you inject a synthetic row at time zero?
What would you add for production-grade telemetry caching?