OmniSense Mobility Hack The City 2026 · Challenge #4 · Service Reliability Scorecard Where the network fails, who feels it, and why. Inspiration Carris Metropolitana carried 194 million passengers in 2025, a record. Yet satisfaction with waiting time sits at 6.1 / 10, and TML itself says reliability is “what people ask us for most”. The awkward part is that nobody could give us a single number, one they would stand behind, for how reliable the service was yesterday. Punctuality, trip completion and regularity live in separate systems. When we first compared the GTFS timetables with the GPS feed for a single day, the same data gave us anything from 42% to 78% punctuality, depending on small, invisible rules about how you match a bus to a stop. We wanted to build an index that is explicit, reproducible, and explainable down to the individual trip. It also had to be explainable to the passenger: not just “the network scores 83”, but who waited, where, and why. What it does OmniSense Mobility turns raw GPS pings and ticket validations into a reliability scorecard for the Lisbon Metropolitan Area. You can read it on four layers of the same map: Demand: where people tap in, stop by stop and hour by hour (validations). Supply: how the service kept its promise at each stop: punctuality, completion and regularity, combined into one index. Impact: critical points, where unreliable service meets real passengers. Cause: where each route’s delay is born, and the most probable reason for it. The Service Reliability Index is a weighted sum of three rates: "SRI"=100×(0.40 P+0.30 C+0.30 R) P: share of stop passages between -1 and +5 minutes of schedule. Running early only counts against the bus where passengers can board. C: share of planned trips actually run. R: share of actual headways within ±50% of the planned headway. People affected at a stop s in hour h combines demand and failure: 〖"Affected" 〗(s,h)=B(s,h)×(1-〖"rate" 〗(s,h) ) Here B is the number of validations. A stop is only a critical point in hours where it has both validations and a measured scorecard. For every trip, we split the delay exactly into its sources: d"arrival" =d_"departure" +∑"segments" ^▒(((max(0,min(A,R)-P))┬⏟)┬"tight timetable" +((max(0,A-max(R,P)))┬⏟)┬"traffic" +((min(0,A-P))┬⏟)┬"slack" ) +∑"stops" ^▒"dwell" P is the planned time on a segment. A is the actual time. R is the segment’s typical time that day (its median). That lets us assign each trip a probable cause at departure (inherited from upstream, previous trip ran late, bus arrived late), en route (traffic, dwell, unrealistic timetable) and at arrival (delay not recovered, created en route, recovered thanks to slack). Everything is filterable by cluster (road; rail and ferry; aggregate), operator, hour of day and dimension, with traffic lights on a fixed scale (green ≥85, amber 70–85, red <70). Every screen is reproduced in an Excel workbook with the formulas visible, so anyone can check how a number was reached. How we built it Data: TML’s GTFS plans for the four Carris Metropolitana operators, 833,573 GPS events for one day in one Lisbon grid cell (Sete Rios, Campolide, Campo Grande), and 1 million validations across ten operators. Pipeline: Python and DuckDB. It matches every bus to every stop within 50 m and a time window, measures departures at the origin and arrivals at the terminus, and computes headways and running times. A full day runs in seconds. Clusters: road operators (Carris, Carris Metropolitana Areas 1–4, Metro, MobiCascais) and rail and ferry operators (CP, Fertagus, Soflusa/Transtejo). Basemap: official CAOP 2025 boundaries and COSc 2026 land use from DGT, plus streets, names, rail lines and parks from OpenStreetMap. Everything is drawn on an HTML canvas with no tile servers. Station names: Carris Metropolitana’s open datasets. Metro station names were inferred from the ordering of the codes, and Carris stops were located from GPS traces. Explainability: an Excel model with ~241,000 formulas, driven by the same filters as the dashboard, plus a pitch deck in Portuguese and English. Challenges we ran into The rules decide the result. Duplicate trips from calendar variants, buses waiting at the origin before departing, early running at set-down-only stops, and trip IDs repeated on other days each shifted punctuality by tens of points. We made every rule explicit, measured its effect, and made each one switchable. Partial data. We had one GPS day and one grid cell. Validations and GPS came from different days, and there were no timetables or coordinates for Metro, CP, Fertagus, MobiCascais or the ferries. We kept those operators in the analysis with equivalent charts and labelled every gap instead of hiding it. Two definitions of “completion”: per stop, which the map needs, and per trip, which the challenge defines. They gave different network scores (80.9 vs 83.0). We show both and explain why they differ. Tooling limits. The sandbox could not reach map tile servers or Google Drive, so the whole basemap had to be built from data files and embedded in the page. Trust. An audit caught three real errors: an operator key collision, overstated early departures, and the hidden double definition of completion. We fixed all three before shipping. Accomplishments that we’re proud of A network index that is robust to the choice of weights. Across 2,000 random weight combinations, the route ranking barely moves (median Spearman correlation 0.994). Finding that more than 70% of delay arrives already made: inherited from upstream or caused by a late departure. When a departure was late, 69% of the time the bus had not yet come back from its previous trip. Probable causes for 998 trips, with the delay identity verified to be exactly zero on every trip and every segment. The dashboard and the Excel model agree on 257 of 257 cross-checked values across five filter scenarios, and 179 interactive states run with zero errors. Going from “the network scores 83” to “at 18:00, 2,119 people validated at stops where the service failed, and here is where the delay started”. What we learned Reliability metrics are only as trustworthy as their matching rules. Transparency matters more than sophistication. Medians hide the pain. The problem lives in the tail, for example the 1 in 10 passages that are 12 minutes late at the evening peak. Weighting reliability by passengers, not by trips, changes the priority list. Route 1704 has the worst index, but 1716 affects three times as many people. Many delays are structural, not incidental. Timetables barely change through the day while the evening-peak speed drops to 7.3 km/h (against 21.9 at night), and short layovers carry a late trip into the next one. What’s next for OmniSense Mobility Full coverage: run the pipeline on the whole week and every grid cell, and bring in the GTFS for Carris, Metro, CP, Fertagus, MobiCascais and the ferries so all ten operators get a full scorecard. Validate the causes with TML: cancellation lists, vehicle blocks and layovers, and traffic-signal and traffic-count data from EMEL and CML, to turn “probable” causes into confirmed ones. Daily production on the TML GO platform or Power BI, with the index published as open data by route and period, as London, Dublin and Sydney do. Action loop: rank bus-lane and signal-priority candidates by passengers affected, and flag timetables with too little or too much slack for the next service change.

Built With

Share this project:

Updates

Submission history