FreeSimulationNo signup

Bus Route Simulator

Buses on a loop, passengers arriving stochastically. Bunching is inevitable — unless you design against it.

Ready
Step 0 / 0
Agents: 0
Group AGroup BEmpty
10/s

Parameters

3
110
40
2080
1.00
0.15

Tweak parameters, then press Reset to apply.

What you just saw

Even with identical buses, identical stops, and identical passenger arrival rates, buses end up bunched. Why? A bus running slightly late picks up more waiting passengers at each stop, which makes it later. A bus running slightly early finds fewer passengers and catches up. This positive feedback is fundamental to any headway-based transit system — and explains why real bus routes need active control (skip-stop, holding, short-turning) to stay on schedule.

The science behind it

The bus bunching phenomenon was formalized by Newell and Potts (1964) and has been studied continuously since. It is the archetypal example of why transit operations can't rely on static timetables alone. Modern agent-based transit models (MATSim, SUMO public transport) extend this with network topology, transfer penalties, and demand response — but the bunching dynamic on a single route is always the first thing they reproduce.

Try these experiments

  1. 1. Under-supplied

    Settings: num_buses=2 passenger_arrival_rate=2

    What to look for: Massive wait times, buses overloaded, obvious bunching within one or two cycles.

  2. 2. Well-supplied

    Settings: num_buses=6 passenger_arrival_rate=1

    What to look for: Stable headways, short waits. The bunching feedback is too weak to compound.

  3. 3. Demand spike

    Settings: passenger_arrival_rate=4

    What to look for: Even a large fleet struggles; dwell times explode at high-demand stops.

Sprint 1 scaffold. Full long-form article, references, and FAQ will land in the content sprints (3–6). The simulation above is already wired to the production worker.
SimLab

Run this at 100x scale

Bus route runs in your browser up to 3 buses agents. With SimLab, the same model runs on GPU at full city network, with ensemble parameter sweeps and publication-ready output.

from scirouter import SciRouter
client = SciRouter(api_key="sk-sci-...")
result = client.simulation.run(
    model="bus_route",
    params={"num_buses": 5, "bus_capacity": 40,
            "passenger_arrival_rate": 1.5},
    steps=3600, seed=42,
)
print(result.metrics["avg_wait_time"])

Related simulations

Frequently asked questions

Why can't buses just stick to a schedule?

Because each deviation amplifies. A driver holding for 30 seconds to match the schedule gives the following bus a chance to catch up. Without active intervention (holding, skip-stop, short-turning), small perturbations grow into full bunching within one loop.

Is this useful for real transit agencies?

For intuition, yes. For operations planning, agencies use MATSim, SUMO-pt, or vendor-specific tools (Remix, Optibus) with real passenger OD data. The dynamic you see here is universal — real tools just add the network and demand detail.