Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ACCESSIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ and a set of live charts. That makes some of it hard or impossible to use withou
and some of it hard to use without a mouse. This page says what works today, what
doesn't, and how to get every result without the visual app.

Last reviewed: November 2026, version 0.5.0.
Last reviewed: November 2026, version 0.5.1.

## Every result is available as text

Expand Down Expand Up @@ -53,8 +53,8 @@ findings as text and tables, and every image in them has a text description.
* **No screen-reader support in the browser version.** It draws everything on a single
canvas, so assistive technology finds nothing to read. Use the desktop app or the
command-line tools instead.
* **Mouse-only tasks:** selecting a vehicle, placing sensors and choosing a crosswalk
corner need a pointer.
* **Pointer-only tasks:** panning and zooming the map, selecting a vehicle, placing a
pedestrian at a crosswalk corner and the charts' hover readouts need a pointer.
* **No shortcuts between panels:** reaching the settings means tabbing through the whole
top toolbar, about two dozen controls.
* **Color:** the *Color by delay* and *Color by speed* map views use color alone. The
Expand Down
43 changes: 25 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ Arrivals come from a dedicated random stream, so every controller faces the *sam

## Signal controllers

All controllers see only the `SensorView`, never ground truth.
All controllers see only the `SensorView`, built from their sensors rather than ground
truth. Pedestrians and emergency vehicles are the exceptions (below).

1. **Fixed-time (Webster).** Cycle and splits from critical flow ratios of historical
demand; every green covers its pedestrian interval. In a corridor it can be
Expand Down Expand Up @@ -162,19 +163,25 @@ delay 22.1 s → 4.0 s, `examples/preempt.rs`) and a **max-wait guard**.
| Sensor | What controllers get | Realistic errors |
|---|---|---|
| Inductive loops | Stop-bar presence, advance pulses, spot speed, input-output queue estimate | Stations fail stuck-on/off; motorcycles missed ~35%. Diagnostics (max presence 3 min; no activity for 10 expected headways) flag failures, and the lane falls back to volume-based estimates / recall |
| Intersection camera | Tracks within range with intent, class and individual waits; waiting pedestrians | Detection falls with distance and weather (night, rain, fog, snow shrink range and hit rate); trucks and buses hide vehicles behind them; intent only from drivers who signal (80%), others look like through traffic |
| Intersection camera | Tracks within range with intent, class and individual waits | Detection falls with distance and weather (night, rain, fog, snow shrink range and hit rate); trucks and buses hide vehicles behind them; intent only from drivers who signal (80%), others look like through traffic |
| Advance radar | Long-range position and speed | ±1.5 m / ±0.5 m/s noise, small miss rate in rain/snow |
| Connected vehicles | Position, speed, route, class at any distance | GPS noise (latency compensated by timestamps) |
| Upstream link (corridor) | Vehicles the upstream signal has released toward us | Intent unknown |

Pedestrians and emergency vehicles reach the `SensorView` straight from ground truth,
whichever sensors are on. Controllers use the push-button calls and the number of people
waiting at each crosswalk, with the longest wait. Only preemption reads the emergency
vehicles within 300 m of the stop line; controllers see them only through their sensors.

## The signal-free cooperative crossing

The last intersection is a look at a possible future rather than at today's streets. It
assumes every vehicle is automated, connected and fitted with crash avoidance. It has no
signals and no roadside sensors, and pedestrians cross in underpasses, so they never
stop traffic. Each vehicle asks an **intersection manager** for a slot when it enters
the map; the manager answers with a complete trajectory, and the vehicle drives exactly
that.
stop traffic. An **intersection manager** schedules every vehicle that crosses the box.
In each lane it considers only the first vehicle without a slot; when it grants one, it
sends a complete trajectory, and the vehicle drives exactly that. Right turns leave on
slip lanes before the box and never ask for a slot.

The design notes in
[docs/cooperative-intersections.md](docs/cooperative-intersections.md) work through the
Expand All @@ -189,8 +196,8 @@ measured.
| Geometry | Each approach has two left-turn lanes, three through lanes and a right-turn slip lane around a corner island, so right turns never enter the box. Opposite left turns pass clear of each other and every lane has its own receiving lane: paths in the box only cross, never merge. Default demand: 4,500 veh/h per approach (18,000 in all), 20% turning left and 15% right |
| Reservations | Each pair of crossing paths has a conflict zone on each path. The manager builds every trajectory with the simulator's own integrator, so it knows when each vehicle will be in each zone, and grants it only if it keeps the required gap to every trajectory already granted. A granted trajectory never changes |
| Phases | By default the manager serves each movement in batches, in two rings with a barrier like an actuated signal, ending a batch when no vehicle can continue it (gap-out) or at its demand-weighted share of a 100 s maximum cycle (max-out). Left turns lag the through movements: a left turn can follow the opposing through traffic almost at once (0.3 s), while the reverse switch would cost about 6 s. The next batch starts as soon as its zones are free, with no yellow or all-red. Emergency vehicles are served out of turn |
| First come, first served | The alternative schedule has no phases: in order of arrival, each vehicle gets the earliest trajectory that fits around those already granted. It is the familiar picture of vehicles weaving through one another, and it carries about half as much (below) |
| Safety gaps | *Fail-safe* (default): enough time for a follower to stop short of the zone if the vehicle ahead stalls in it: two message latencies, the actuation delay, and the time its braking distance takes at crossing speed (1.43 s for a car at 40 km/h). *Mitigated*: it could still slow to 25 km/h. *Nominal*: message latency only |
| First come, first served | The alternative schedule has no phases. Of the vehicles first in their lanes without a slot, the one that could cross the stop line soonest goes next, with the earliest trajectory that fits around those already granted. It is the familiar picture of vehicles weaving through one another, and it carries about half as much (below) |
| Safety gaps | *Fail-safe* (default): enough time for a follower to stop short of the zone if the vehicle ahead stalls in it: two message latencies, the actuation delay and the time its braking distance takes at crossing speed (1.43 s for a car at 40 km/h). *Mitigated*: it could still slow to 25 km/h. *Nominal*: the two message latencies and the actuation delay only (0.5 s), assuming no vehicle ever fails |
| Monitors | Independently of the plans, the simulator measures what vehicles actually did: the closest post-encroachment time (PET), zones entered while occupied, box entries without a reservation, and any step off the granted trajectory |

### Why weaving one at a time carries less
Expand Down Expand Up @@ -219,7 +226,7 @@ Three things cost the zipper its throughput:
* **Every switch pays a safety gap; a follower doesn't.** A vehicle following another on
the same path needs only its car-following gap, about 1.0 s at 40 km/h. A vehicle
crossing behind one from a conflicting path must wait for the first to clear the
zone, about 0.7 s, and then for the fail-safe gap, 1.43 s for a car: about 2.2 s in
zone, about 0.7 s, and then for the fail-safe gap, 1.43 s for a car: about 2.1 s in
all. Served one vehicle at a time, alternating between two paths, a single conflict
zone carries about 1,700 veh/h; in batches of 8 it carries about 3,100.
* **Each path crosses ten other lanes.** A weaving vehicle needs a free window at every
Expand All @@ -230,14 +237,14 @@ Three things cost the zipper its throughput:
keeps every lane of a movement streaming together.

Shorter gaps help the zipper more than batches, since they make switching cheap. With
nominal gaps (message latency only) first come, first served reaches about 12,600 veh/h,
25% more, while batches gain only 3.5%, to 19,700; the zipper still carries about a
third less. So the schedule that carries the most looks like a signal without its yellow
and all-red: each movement goes in a batch, and the next starts the moment its zones are
free. To watch the difference, pick the cooperative crossing and turn on *Compare side
by side*: B weaves the same arrivals through first come, first served, slows its
vehicles far out on the approaches and, at the design demand, soon has a queue waiting
to enter the map.
nominal gaps (latency and actuation delay only) first come, first served reaches about
12,600 veh/h, 25% more, while batches gain only 3.5%, to 19,700; the zipper still
carries about a third less. So the schedule that carries the most looks like a signal
without its yellow and all-red: each movement goes in a batch, and the next starts the
moment its zones are free. To watch the difference, pick the cooperative crossing and
turn on *Compare side by side*: B weaves the same arrivals through first come, first
served, slows its vehicles far out on the approaches and, at the design demand, soon has
a queue waiting to enter the map.

![Batches (A) and first come, first served (B) side by side at the design demand](docs/cooperative.png)

Expand Down Expand Up @@ -446,8 +453,8 @@ A fuller write-up of every finding, with the commands that reproduce it, is in
excellent at moderate volumes, and a two-way stop fails once the major road is busy.
* **Signal-free crossings still need phases.** With every vehicle automated, an
intersection manager carries the design demand of 18,000 veh/h at 29 s average delay
and saturates near 19,000 veh/h with fail-safe gaps (19,700 with latency-only gaps,
about 21,700 if every vehicle were a car). The capacity comes from serving each
and saturates near 19,000 veh/h with fail-safe gaps (19,700 with nominal gaps, about
21,700 if every vehicle were a car). The capacity comes from serving each
movement in batches, like a signal without its yellow and all-red, not from weaving
vehicles through one at a time: every switch between conflicting movements costs a
clearance gap, and a weaving vehicle must find one in up to ten crossing lanes at
Expand Down
22 changes: 17 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ cannot:
This rule is what makes sensor studies meaningful. If a controller does better with
radar, it is because it saw more, not because it peeked. The exception is pedestrians
and emergency vehicles, which reach the `SensorView` straight from ground truth,
whatever sensors are fitted (§6.5).
whatever sensors are fitted (§6.5). No controller reads the emergency vehicles, though:
only `Sim`'s preemption does (§7.2), so controllers see them only through their sensors.

`Ctx` carries the network, the `SensorView`, the signal state, the configured demand and
sensor settings, the time, `can_switch` and `reward_delay`. Two of those deserve a note:
Expand Down Expand Up @@ -965,7 +966,9 @@ flowchart TB
rain and snow.
* **Pedestrians and emergency vehicles** come straight from ground truth, whatever
sensors are fitted: the waiting pedestrians and push-button calls at each crosswalk,
and emergency vehicles within 300 m of the stop line or already in the box.
and emergency vehicles within 300 m of the stop line or already in the box. Only
`Sim`'s preemption reads the emergency vehicles (§7.2); controllers see them only
through the sensors above.
* **The upstream link** (`upstream_link`, off by default; *Upstream signal shares its
outflow* in the app) adds the vehicles the upstream intersection has released toward
this one, but only beyond the reach of our own sensors. Their intent is unknown, so
Expand Down Expand Up @@ -1300,7 +1303,7 @@ emergency deceleration is 6 m/s², or 4.5 m/s² for trucks and buses.
|---|---|---|---:|
| `FailSafe` (P2, the default) | Fail-safe: can stop for a stalled vehicle | 0.5 s + braking distance ÷ speed | 1.43 s / 1.73 s |
| `Mitigated` (PH) | Mitigated: can slow to 25 km/h | 0.5 s + distance to slow to 25 km/h ÷ speed | 1.06 s / 1.25 s |
| `Nominal` (P1) | Nominal: latency only (no failures) | 0.5 s | 0.50 s |
| `Nominal` (P1) | Nominal: latency and actuation (no failures) | 0.5 s | 0.50 s |

P2, PH and P1 are the names `docs/cooperative-intersections.md` gives these policies
(stop-safe, harm-limited and brake-safe), and `TS_POLICY` takes them in lower case.
Expand Down Expand Up @@ -2908,8 +2911,8 @@ a 1.5 s batch join window">
* **Scheduling:** *Batches: each movement in turn*, or *First come, first served: one
at a time*.
* **Safety gap:** *Fail-safe: can stop for a stalled vehicle*, *Mitigated: can slow to
25 km/h* or *Nominal: latency only (no failures)* (§6.11). The line below gives the
resulting gap at 40 km/h for a car and for a truck or bus.
25 km/h* or *Nominal: latency and actuation (no failures)* (§6.11). The line below
gives the resulting gap at 40 km/h for a car and for a truck or bus.
* **max cycle** (40 to 200 s) and **batch join window** (0 to 5 s), grayed out under
first come, first served.

Expand Down Expand Up @@ -3330,6 +3333,15 @@ Every capture used `TS_SPEED=20` and `TS_SHOT_AFTER=120` unless listed otherwise
| `coop-bench-window` | `TS_LAYOUT=cooperative TS_BENCH=controllers TS_SPEED=1 TS_SHOT_AFTER=150` |
| `layouts` | `TS_LAYOUT` set to each layout's key |

The README's screenshots are made the same way:

| Image | Settings |
|---|---|
| `docs/arterial.png` | `TS_SPEED=30 TS_SHOT_AFTER=420` |
| `docs/compare.png` | `TS_TWIN=Fixed TS_SPEED=100 TS_SHOT_AFTER=600` |
| `docs/corridor.png` | `TS_CORRIDOR=3 TS_SPEED=100 TS_SHOT_AFTER=600` |
| `docs/cooperative.png` | `TS_LAYOUT=cooperative TS_TWIN=fcfs TS_SPEED=10 TS_SHOT_AFTER=600` |

A few things to know when making new ones:

* **Resolution:** on a Retina display a 1600 × 1000 window is captured at 3200 × 2000
Expand Down
Binary file modified docs/arterial.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/compare.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading