Surge pricing without overshoot. V2 adds polygon-level optimization — a 3×3 city map showing per-zone surge state. Because a city-average surge of 1.0x can hide Downtown at 2.5x (alert) and Suburbs at 0.8x (oversupply) at the same hour. Optimization happens at the polygon, not the aggregate.
Pick a scenario
PID tuning
Reacts to current error. Higher = more aggressive surge response now.
Accumulates error over time. Too high = oscillation in delayed systems.
Reacts to rate of change. Higher = catches spikes. Too high = noisy.
PID performance (city aggregate)
Avg MAPE
0%
Peak MAPE
0%
Peak surge
1.00x
Hours in alert (>20% MAPE)
0h
Demand vs Supply (24h)
How requests and available capacity move over the day.
DemandSupply
Surge Multiplier (PID Output)
What the PID controller asks the pricing system to do, clamped 1.0x–2.5x.
PID surgeNaive threshold (1.5x if MAPE>30%)
MAPE — Error Signal
|demand − supply| / demand × 100. Lower is better. Red zone > 20%.
PID-controlledNaive20% threshold
PID Term Contribution
Which term (P, I, or D) is driving the surge response at each moment.
P · proportionalI · integralD · derivative
PID vs Naive — same scenario, head to head
Naive (threshold 1.5x if MAPE > 30%)
0%
avg MAPE · peak 0% · 0h in alert
PID (your current tuning)
0%
avg MAPE · peak 0% · 0h in alert
Pick a scenario to compare.
Why polygon-level matters
Real marketplaces aren't one supply-demand curve per city. They're many curves, one per geographic zone. Downtown spikes at rush hour, the airport spikes at flight time, the stadium spikes during events, suburbs barely move. A city-average surge of 1.0x can mean Downtown is at 2.5x (alert) and Suburbs is at 0.8x (oversupply) in the same minute. The aggregate hides the truth. Production marketplace platforms run surge at the polygon (or hex cell) level for exactly this reason. This V2 view runs nine independent PID controllers — one per zone — and visualizes how the same time of day looks wildly different across geography.
Time of day
00:00
City zones — current state
Each polygon is a zone running its own PID surge controller. Color shows current MAPE status. Click any zone to see its detail. Drag the time scrubber above to see how the city evolves across 24h.
MAPE < 15% — balanced15-30% — watch> 30% — alert
Click a zone
Demand
—
Supply
—
MAPE
—
Surge
—
Polygon-level vs City-level — head to head (24h)
Same demand and supply data. Two approaches: a single city-wide PID controller vs nine polygon-level PID controllers. Polygon-level optimizes each zone independently and produces lower aggregate MAPE because it doesn't average away local imbalance.
City-level PID · avg MAPE
0%
Polygon-level PID · avg MAPE
0%
Improvement (relative)
0%
Worst polygon at this moment
—
Drag the scrubber to see how the city evolves and how polygon-level PID outperforms.
How PID surge pricing works
Marketplace platforms balance supply and demand using surge multipliers — pricing that adjusts in real time to bring more drivers/couriers/sellers online when demand exceeds capacity. The classic way to do this is a threshold rule: if imbalance > X%, set surge to 1.5x. It works, but it overshoots and oscillates because there's no feedback memory.
The smarter approach borrows from control theory invented in 1922 by Nicholas Minorsky: the PID controller. PID stands for Proportional, Integral, Derivative — three terms that together compute the right amount of correction to apply at any moment, given how much error there is now, how much has accumulated, and how fast it's changing.
Real-world impact
Illustrative scenarios drawn from operator practice. Numbers are realistic order-of-magnitude estimates, not measurements from any specific deployment.
Case 1: City-average surge masking 4 starving polygons
SetupPricing manager at a ride-hailing operation in a Tier-2 LATAM city running a single citywide surge multiplier on weekday evening peaks.
ProblemCitywide multiplier averaged 1.4x and looked healthy, but 4 outer polygons were stuck at 18 to 22 minute ETAs while downtown sat at 4 minutes, causing roughly 8% trip cancellation in those zones.
Tool surfacedV2 polygon view showed the 3x3 zone grid with two cells in deep undersupply at effective 1.0x while downtown was overshooting at 1.7x, the PID tune was too smooth for spatial variance.
OutcomeZone-level Kp raised on outer cells, cancellation in those polygons dropped from 8% to 3.2%, recovered an estimated $9K per weekday peak in completed trips.
Case 2: Surge oscillation eroding driver trust
SetupMarketplace ops at a delivery platform was running surge updates every 5 minutes and pricing kept swinging 1.0x to 1.8x to 1.1x within a single 30 minute window.
ProblemDriver complaints spiked about "phantom surge" and weekly driver churn climbed roughly 4 points, costing the team about $22K monthly in re-acquisition and onboarding.
Tool surfacedThe simulator showed integral gain was too high and derivative too low, producing classic PID overshoot; smoother coefficients held supply-demand inside the deadband 78% of the time vs 41% in current settings.
OutcomeNew PID coefficients rolled out region by region, driver churn dropped back 3.5 points within 2 cycles, savings around $19K monthly on retention alone.
P (proportional) reacts to current error. Big mismatch right now? Big surge right now. Used alone, it overshoots and oscillates around the target.
I (integral) accumulates error over time. If imbalance persists, I keeps pressing the surge up. Too much I creates oscillation.
D (derivative) reacts to how fast error is changing. Catches sudden surges (airport, weather event) but is sensitive to noise.
Why AND instead of OR? Each signal alone is too noisy. Volume velocity alone triggers on Black Friday. New-user count alone triggers on marketing campaigns. The intersection — all three crossing simultaneously — is the fingerprint of an attack.
The status tiers
Alert — all three signals cross. Pull a human investigator now.
Watch — velocity is elevated AND one of (volume floor or new-user count). Early stage or ambiguous pattern. Track daily, no ops response yet.
Safe — velocity normal or only one signal crossing. Stable large BINs with no velocity change land here even if they exceed the floor — that's intentional. The point is detecting change, not flagging size.
V2 — Polygon-level optimization
V1 ran a single PID controller over the city aggregate. V2 adds a second view: nine independent PID controllers, one per geographic zone. Real production surge systems (Uber's H3 hexes, Lyft's zones, DoorDash's dispatch cells) operate at this level for one reason — city averages hide local imbalance.
A 1.0x city surge can be the average of Downtown at 2.5x and Suburbs at 0.8x. Optimize the average, and Downtown riders wait too long while suburb drivers sit idle. Optimize each zone, and both problems disappear at the cost of slightly more complex control architecture.
How the comparison works
City-level PID takes the sum of all polygon demand and the sum of all polygon supply, runs one PID controller, and broadcasts the same surge multiplier to every zone. Simple but lossy.
Polygon-level PID runs an independent controller per zone. Each zone gets its own surge based on its local imbalance. The aggregate MAPE drops because no zone is being penalized by an averaged signal.
What this simulator is NOT
It's not a production-ready surge engine. Real implementations account for many more variables (cross-zone supply rebalancing, ETA targets, regulatory caps, two-sided NPS impact, weather signals).
It's not any specific platform's proprietary algorithm. Production systems at ride-hail and delivery companies are far more complex. This is the canonical PID pattern applied to a simplified marketplace model with industry-standard polygon-level decomposition.
It's not a substitute for ML-based surge. Modern systems often combine PID-style feedback with predictive ML on top.
What this simulator IS
A teaching tool for ops leaders studying the control-theory side of pricing
A starting point for implementing polygon-level surge in your own data pipeline
A way to build intuition for why naive threshold rules and city-level averaging both underperform
A reference implementation you can read in 200 lines of Python
Reference implementation
The Python reference of the (V1) city-level logic is available as surge-pid-reference.py. Polygon-level extension is straightforward: wrap the existing PIDController in a loop over zones, each with its own demand_fn and PID state.
Reading list
Minorsky, N. (1922). "Directional stability of automatically steered bodies" — original PID paper