Traffic Light Green Phase Throughput
2025 — A simulation of how many cars clear one green light
01 Problem
A single lane of cars is already queued at a red light when it turns green for 15 seconds. Each driver waits for the car ahead to move, reacts, and only then accelerates, so the start of the queue ripples backward one car at a time.
The goal is how many cars clear the intersection before the light turns red, and how much driver reaction time and car acceleration change that number.
02 Queue
Sixteen cars wait in line, each 5 m long with a 2 m gap, the first with its front bumper on the stop line. The app tracks each car by the position of its rear bumper, measured from the stop line, so car starts 5 m back plus 7 m for every car ahead of it.
A car counts as through once its rear bumper clears the far side of the intersection, 12 m wide. That leaves the first car 17 m to cover and every car behind it 7 m more.
CAR_LENGTH <- 5
INITIAL_GAP <- 2
TOTAL_CAR_SPACE <- CAR_LENGTH + INITIAL_GAP
MAX_CARS <- 16
cars_df <- data.frame(
id = 1:MAX_CARS,
position = -(0:(MAX_CARS - 1)) * TOTAL_CAR_SPACE - CAR_LENGTH,
velocity = 0,
status = "resting",
reaction_start_time = Inf,
start_time = Inf
)03 Drivers
The first driver starts reacting the moment the light turns green. Every other driver starts reacting only when the car ahead begins to move, then waits the full 2-second reaction time before moving.
The delays stack up. Counting the light itself as car 0, car starts moving one reaction time after the car ahead, so the fourth car does not move until 8 seconds, more than half the green light.
if (t == 0) {
cars$status[1] <- "reacting"
cars$reaction_start_time[1] <- 0
}
if (cars$status[i] == "resting" && i > 1) {
car_in_front <- cars[i - 1, ]
if (car_in_front$status == "moving" && cars$reaction_start_time[i] == Inf) {
cars$status[i] <- "reacting"
cars$reaction_start_time[i] <- car_in_front$start_time
}
}
if (cars$status[i] == "reacting") {
if (t >= cars$reaction_start_time[i] + reaction_time) {
cars$status[i] <- "moving"
cars$start_time[i] <- t
}
}04 Cars
Once moving, a car accelerates at m/s² until it reaches the speed limit m/s, about 40 km/h, then holds that speed. Its speed and position follow the formulas for uniform acceleration and then uniform motion. They are counted from , the time since the car started moving, and is the time it takes to reach the speed limit.
At 1 m/s² the speed limit takes 11 seconds to reach, so only the first 2 cars get there before the light turns red.
if (cars$status[i] == "moving") {
time_since_move <- t - cars$start_time[i]
initial_position <- -(i - 1) * TOTAL_CAR_SPACE - CAR_LENGTH
time_to_max_speed <- speed_limit / acceleration
if (time_since_move <= time_to_max_speed) {
cars$position[i] <- initial_position + 0.5 * acceleration * time_since_move^2
cars$velocity[i] <- acceleration * time_since_move
} else {
distance_during_accel <- 0.5 * acceleration * time_to_max_speed^2
time_at_max_speed <- time_since_move - time_to_max_speed
cars$position[i] <- initial_position + distance_during_accel + speed_limit * time_at_max_speed
cars$velocity[i] <- speed_limit
}
}05 Clearing time
Because every car starts on a fixed schedule and moves by these formulas, the moment its rear clears the intersection can be solved by hand instead of stepped through. Car has to travel and covers the first of it while still accelerating.
Each car starts later and has further to go, so rises with , and the cars that get through are exactly those with inside the green light. Once cars clear at the speed limit, each follows the one ahead by the reaction time plus the time to cover 7 m.
06 Default settings
The defaults are a 2-second reaction time, 1 m/s² acceleration, a speed limit of 11 m/s, and a 12 m intersection. With them, a car covers 60.5 m before reaching the speed limit, so the first 7 cars clear while still accelerating.
The third car clears with 1.1 s to spare and the fourth misses by 1.7 s, so 3 cars get through. The gap between cars narrows toward 2.6 s, so a longer green helps steadily, with 5 cars clearing in 20 seconds and 7 in 25, which backs the original analysis's recommendation of a 20 to 25-second green.
07 Simulation
The app starts its clock at -1 and steps one second at a time, so the first step lands on 0, the moment the light turns green. At each step it updates every car in queue order, so a car can start reacting in the same step the car ahead starts moving.
Every step also recounts the cars whose rear has cleared the intersection, so the count at 15 seconds is the final one.
DT <- 1
while (local_sim_state$timer < 15 && !local_sim_state$is_finished) {
local_sim_state <- run_simulation_step(
current_sim_state = local_sim_state,
reaction_time = input$reaction_time,
acceleration = input$acceleration,
speed_limit = input$speed_limit,
intersection_width = input$intersection_width
)
}
current_sim_state$cars_passed <- sum(cars$position >= intersection_width)08 Answer
The step-by-step run lands on the same answer: only 3 cars clear the intersection in 15 seconds. The fourth starts moving at 8 seconds and still has 13.5 m to go when the light turns red.
The simulation and the clearing-time formula agree on 8,192 of the 8,192 combinations of the app's four sliders. Every car starts exactly on a whole second, and the app computes positions from the same formulas rather than adding them up step by step, so the 1-second step never changes the count.
09 Sensitivity
Reaction time matters more than acceleration. Halving the reaction time from 2 seconds to 1 lets 5 cars through, as many as raising acceleration from 1 to 8 m/s² at the default reaction time, which gives 5.
With a 4-second reaction time, 2 cars get through no matter how hard they accelerate, because the wave of starts reaches the back of the queue too slowly.
sliderInput("reaction_time",
"Driver Reaction Time (seconds):",
min = 1,
max = 4,
value = 2,
step = 1)
sliderInput("acceleration",
"Car Acceleration (m/s²):",
min = 1.0,
max = 8,
value = 1,
step = 1)10 Original app
The simulation was first built in R as an interactive Shiny dashboard. Sliders set the reaction time, acceleration, speed limit, and intersection width, and step buttons move the queue forward or back one second at a time while a plot traces every car through resting, reacting, and moving.
The app is still live on shinyapps.io. The free tier puts it to sleep when nobody is using it, so the first visit can take a while to load.

11 Limits
A car counts only once its rear clears the far side of the intersection before the light turns red. Signal timing usually counts a car once it crosses the stop line on green, since it can finish crossing on amber. Counting front bumpers at the stop line gives 4 cars instead of 3.
The 1-second step only delays the counter, which ticks up at 8, 11, and 14 seconds rather than at 7.8, 10.9, and 13.9. A fractional reaction time would also push every start to the next whole second, but the app's slider only allows whole seconds.
Every driver reacts in exactly the same time and every car accelerates the same way, so no car ever closes in on the one ahead or brakes. Reaction time and acceleration are assumptions, not measurements, and video counts at a real intersection would make the answer worth trusting.
Traffic Light Green Phase Throughput
Clears 3 cars in a 15-second green light