Vix beside us: two systems measuring the same buses
Status: measured, on one service for one day — First South Yorkshire's 120
on 10 September 2026, 4,012 Vix observations against 4,642 of ours. Report at
/vix; the journey-by-journey view of our own data is at /journeys.
Download the full comparison as a spreadsheet
SYMCA's contract performance figures come out of Vix. This platform measures the same buses from the same BODS feed and reaches its own answer. Until the two are laid side by side nobody can say whether they agree, and "our number is different from theirs" is not a finding — it is the start of one.
Neither system has ever seen the other's data. Vix names a journey by its start time and a running-board reference; we hold a GTFS trip id. Vix reports schedule deviation as decimal minutes, we hold seconds. Both are the difference between when a bus was at a stop and when it should have been, so they are comparable — but only where both saw the same stop on the same journey, which is why every table gives each side's own count rather than assuming they match.
How the two are lined up
Journeys pair on the scheduled departure from the journey's first stop, within a direction. That is the only key both sides share. Where two journeys leave at the same time — two 120s leave at 09:19, one each way — they are numbered within the time and paired off one to one: arbitrary between the two, but one to one, which is what the totals have to be to mean anything.
Stops pair on the ATCO code and the position in the journey. Vix counts a journey's stops from 1 and our timetable from 0, so the same stop is one lower on our side; joining the two numbers as they stand pairs nothing at all. The offset was exactly one on every row checked.
Stop codes come back from Vix eight characters where ATCO has nine, dropping the zero in fourth position. It is put back on import: all 339 stops in the monthly extract matched the national register once it was restored.
The on-time window is the same on both sides — 1 minute early to 5 minutes 59 late. That was measured from Vix's own export rather than taken from a specification, and it is the window this platform already used.
What the two systems say about the 120
Timing points only, terminus excluded from on-time performance, deviation in seconds and positive late:
| Ours | Vix | |
|---|---|---|
| Timing points along the route | 403 | 374 |
| On time | 96.5% | 94.7% |
| Early | 1.2% | 2.9% |
| Late | 2.2% | 2.4% |
| Mean deviation | +73s | +67s |
| Terminus arrivals | 35 | 53 |
| Early at the terminus | 57.1% | 62.3% |
| On time if the terminus is counted in | 92.0% | 87.6% |
| Journeys held | 81 | 66 |
Within two points on a measure neither system built to match the other. Ours reads higher here, not lower.
The terminus is a different measurement, on both sides
A bus arriving early at the end of its journey is not a punctuality failure. The last leg of a timetable carries padding, an interchange is where a bus is meant to wait, and nobody misses a bus that got there ahead of time. Across the week to 10 September the early rate ran 29.4% at the terminus against 2.7% at intermediate timing points — eleven times, which is a different kind of measurement rather than a different standard of driving.
The comparison settles that it is not an artefact of ours. Both systems see about 60% of terminus arrivals as early — 57.1% here, 62.3% in Vix — in the same place, on the same journeys. Since 11 September this platform reports the terminus as two measures of its own rather than inside on-time performance.
That also says something about the headline gap. Vix's reported figure almost certainly excludes the terminus already, or weights it differently, because leaving it in drags a figure down by a different amount for each system: on the 120 it costs us 4.5 points and Vix 7.1.
The terminus difference has a cause, and it is ours
Vix holds 53 terminus arrivals on the 120 against our 35, and that asymmetry now has an explanation rather than a suspicion. Against the timetabled final stop of each of the 67 journeys both systems hold:
| Journeys | |
|---|---|
| Both have the terminus | 32 |
| Only Vix has it | 24 |
| Neither has it | 11 |
| Only we have it | 0 |
Vix 56 of 67, this platform 32, and not one journey the other way round.
The cause is that a bus's journey reference moves to its next journey at the moment it arrives — which is correct behaviour, since the next journey starts where the last one ended, but it is also the moment we are trying to record. An arrival is timed between two fixes, and at a terminus the second fix already carries the next journey, so the final stretch belongs to neither. Measured in both feeds: 28 of 34 GTFS-RT journey changes happen within 100 metres of the old journey's last stop.
Vix does not have this problem because it does not infer journey membership from a position stream at all — the equipment knows which journey the driver signed on to and records the arrival against it. Nothing is wrong with the feeds; what was wrong was our assumption that a journey's last fix would still carry that journey's label.
Corrected in the poller from 12 September, which should close most of this difference on any day captured after that: like-for-like capture of the final stop went from about 40% to 83.4% on the day it went live. It does not change the 10 September figures here, so read the terminus counts in this comparison as our recording rather than as the buses: 35 against 53 is a measurement gap, not a difference in operation. The full write-up, including how widely it applies — 25 to 47% of journeys depending on operator — is at /docs/journey-rebadging.
The eleven journeys neither system holds are worth a question to Vix. Whatever they are, they are not explained by reading the open feed.
Where the two disagree, and where they do not
Restricting to the 66 journeys both systems hold:
| Observations | On time | |
|---|---|---|
| Ours, shared journeys | 353 | 97.2% |
| Vix, same journeys | 374 | 94.6% |
| Ours, the 15 journeys Vix has no row for | 50 | — |
On identical journeys we read 2.6 points higher than Vix, and we record fewer timing points on them — 353 against 374 — because our tracking is less complete, not more generous. Our total of 403 is higher only because we hold 15 journeys Vix has no record of.
That inverts the network-level picture, where this platform sits several points below the figure SYMCA reports. Whatever explains the aggregate gap, it is not that we judge a given stop more harshly. Two candidates remain, and both are questions about the denominator rather than the measurement:
- whether Vix's headline counts arrivals at the final timing point;
- whether it counts only journeys it tracked well, which would lift a figure in a way ours does not.
A journey one side has and the other does not is the column worth reading. It is not an error to be reconciled away: one of the two systems saw a bus the other did not, and which is right has to be settled case by case.
What is in the spreadsheet
| Sheet | |
|---|---|
| Read me | What is compared, how it is paired, and what to filter |
| Summary | The headline figures, same basis both sides |
| Journeys | A row per journey pairing — stop counts, coverage, mean and worst deviation, references |
| Stops | A row per stop per journey, both systems side by side. 4,642 rows |
| Vix export | The rows as Vix sent them, after the pivot is unpicked, deviation in seconds as well as decimal minutes |
| Column notes | What every column actually holds |
The stops sheet is the one to filter. Timing point is Y/N — each system's own flag is given as well, because they are read from different sources and agreeing is a result rather than an assumption. Stop position is Origin, Intermediate or Terminus, so the terminus can be taken out of both sides at once. Seen by is Both, Vix only or Ours only: 3,762 rows matched, 630 only ours, 250 only Vix.
What would make this stronger
One service on one day, and a good one for us. Two things would settle more:
A day from 13 September onward. Two separate faults held the terminus down here, and both are now fixed: the arrival mark sat at the exact end of the trip geometry, which a bus stopping short never crossed (fixed 11 September, which took capture on the 120 from 43% to 71%), and the journey re-badging above (fixed 12 September). A comparison day captured after both is the clean test, and is the single thing that would most improve this.
Observations broken down per journey rather than aggregated, for more than one service. The aggregated monthly extract cannot answer which stops enter Vix's denominator, and that is now the open question.