Every noise figure in this repository is attached to a place. Every population figure is attached to a polygon. Those two cannot honestly be multiplied together, because exposure is neither — it is what accumulates along a path: dose = ∫ noise(position(t)) dt. The cohort model supplies dt and has no position(t) at all. This model is an attempt at the missing term.
It is a demonstration of mechanism, not a measurement of DUMBO. Nothing here is evidence about how loud anywhere is. Read the two red panels before quoting any number off this page.
Two people can follow the same itinerary, leave ninety seconds apart, and receive materially different noise doses — because whether you are on the waterfront path at the moment a train crosses is a matter of timing, not of geography.
That is a race condition in the precise sense: the outcome depends on the interleaving of two independent schedules, one of which (the trains) is published to the second and the other of which (a person's walk) is not. A cohort model cannot represent it, because a cohort has a duration but no clock position. Averaged over a long enough exposure the effect washes out. Over a single visit — which is what a tourist has, and what the Louisville survey says lasts about two hours — it does not.
A standing agent with no vote. It reports externality on populations the simulation does not contain, which is the only reason a model like this is worth building rather than merely watching.
Each group's accumulated A-weighted sound exposure over its whole visit, converted to an equivalent continuous level. The spread inside a single persona is the race condition; the offset between personas is the itinerary.
Every number above is a level or a duration. Neither says anything about whose ear it arrived at. A person with hyperacusis, an eighty-year-old with recruitment, a baby in a pram and a dog on a lead are all, to the model so far, one unit of exposure each.
That is enforced rather than promised. Class membership is drawn from its own random stream, so switching this layer on leaves the dose of every group whose itinerary it did not change bit for bit identical — checked group by group, not in aggregate. The groups whose dose does move are the ones now walking a dog, and they move because they genuinely go somewhere else, which is a change of itinerary and not a change of physics. The check is visual-review/verify_agent_model.js, and it has already caught three real defects in this page.
“The groups whose dose does move are exactly the ones now walking a dog”That is withdrawn. At a population of 400 the harness found a group with an identical persona, an identical itinerary and an identical arrival time whose dose moved by 0.97 dB when this layer was switched on. It had not changed. Someone else had. Nineteen groups were rerouted to the dog run, one of them out of a place that was at capacity, and the group that had been turned away from that place was no longer turned away — so it stayed 1,100 s longer, somewhere quieter, and its dose fell.
That is the race condition this model was built to demonstrate, arriving unannounced in its own verification output. The rule still holds in the form that matters — no decibel anywhere is multiplied by anything about a person — but the weaker claim that the layer is separable from the dose is false once capacity is modelled. Occupancy is a shared resource, and a shared resource couples strangers to each other. The test now distinguishes the two: a dose may move only if the group's re-plan count moved with it, and a dose that moves with the same plan, the same arrival time and the same re-plan count is a desynchronised random stream and fails the build.
Classes overlap on purpose: membership is drawn per person, so one person can appear in two rows. Summing this column double-counts. The “any class” row is the only correct total, and it is produced by the draw rather than by addition.
The one question an agent model can answer that a cohort model cannot. A cohort has an exposure; it does not have an itinerary, and so it cannot be asked who picked the route.
The natural way to say what this noise does to a sound-sensitive person is a threshold. Audiology has one: the loudness discomfort level, the point at which a sound is reported as uncomfortably loud. For normal-hearing listeners without a tolerance problem it averages around 100 dB HL across the audiometric frequencies, and hyperacusis is commonly marked at 90 dB HL or below. The MTA measured 98.90 dB(A) peaks at the dog run. Those two numbers are begging to be compared.
That refusal is the most useful thing on this page, because it converts a vague call for “more data” into one specific missing measurement. A third-octave spectrum of a pass-by is the thing standing between this model and a defensible statement about a sound-sensitive listener — and it is a capture that has already been specified, costed and left undone. It is capture C1 in this programme's field protocol, and the desk work that would follow it is Method 43.
It will not give a clean verdict even then. A headphone threshold and a free-field broadband exposure are different measurements, so the defensible output is a bracket with its assumptions named — and a bracket that straddles the measured peak would be as informative as either clean result.
Everyone in this model walks in through one of four gateways — the York Street F platform, the High Street A/C platform, the Brooklyn Bridge walkway, or Fulton Ferry Landing — drawn per persona, with the exit sampled independently. So arrivals were never all from one place. They were, however, at a perfectly constant rate, and that is a description of nothing that has ever happened at a subway station.
“Arrival is a Poisson-ish trickle spread over the first three quarters of the window”The line underneath it contained no random draw of any kind. It admitted floor(pop × t / window) groups — a deterministic ramp, which is not Poisson-ish but perfectly regular, the one thing arrivals never are. That is withdrawn. The arrival process is now explicit and selectable, and the default has moved from the ramp to Poisson.
A subway door is a starting gun. Nobody trickles out of a train: the doors open and a slug of people climbs the stairs together, walks the same way at the same time, and wants the same bench. So a third process models arrivals at the two gateways that have a door, in slugs on the feeder line's headway, while people who walked over the bridge or stepped off the ferry keep the Poisson process — because there is no gun for them.
Group i is the same group under all three: same persona, same party size, same itinerary, same susceptibilities. Only the moment it walks in changes, because the schedule is built from its own random stream. The diff is therefore a diff of timing and of nothing else.
Takes a few seconds, and resets the view afterwards.“peak arrivals per minute go from 14.0 … to 58.9 under train doors — a 4.2× increase in bunching … the paired difference in mean dose is +0.001 dB”Every one of those figures was measured correctly, and not at this page's settings: the twelve-seed run behind them was executed with the stair-climb spread tightened to 0–10 s, which is the adversarial end of the sensitivity sweep and not the default of 25–150 s. Presenting them without saying so invited a reader to check the figures against the button above and find different ones. That is withdrawn and replaced by the default-configuration run in the block above. The tightened run is kept, as what it always was:
An adversarial check, not the headline. Re-running the same twelve seeds with the stair spread tightened to 0–10 s — a whole train reaching the street almost at once, which is physically impossible — pushes bunching to 58.9 per minute, 4.2× the ramp, and the paired dose difference falls to +0.001 dB with a worst seed of 0.037 dB. Making the burst as sharp as it can possibly be does not make it matter. That is a stronger result than the default run, which is why the two are reported separately rather than averaged.
That null has a mechanism, which is why it is reportable rather than merely observed. Arrival time sets a group's phase against the train cycle, and phase can only matter if the visit is comparable to the headway. It is not. Weekday daytime headway on the bridge is 58 s, and even the shortest-dwell tenth of the population is in the corridor for a median of about 430 s — roughly seven crossings. Shifting phase moves that by at most one crossing in seven, and across a population it cancels.
This bounds a worry that has been near the top of the weaknesses list since the model was built. “The arrivals are invented” was true and is still true — but for the dose it is now invented within 0.05 dB, which is far below every other uncertainty on this page. It would stop being true for anyone whose time in the corridor approached the headway, and nothing in DUMBO produces that: the corridor takes minutes to cross at any pace.
The obvious way to give every point on the map a sound level is a propagation model: take the track as a line source, attenuate with distance, done. That was tried first. It was rejected, and the reason is worth more than the model would have been.
So the field below carries no physics. It is inverse-distance interpolation between the measured anchors, computed in the energy domain because energy is what adds, with the train contribution switched by the published headway. It is a way of moving a plausible number around a map so that timing and route can be studied. It is not a noise map of DUMBO and must never be reproduced as one.
Four object types. They are printed here in full because the schema is the argument: it fixes what the model can represent and, more importantly, what it cannot.
Two ratings, because two things are being claimed. Prevalence is how well established the share is in the population it was measured in. Applies here is whether the same share walks through DUMBO, and it is 1/5 for every row without exception, because nobody has ever counted who is in this corridor by any attribute at all. A flat national rate is knowably wrong in places whose whole purpose selects for a class — a dog run, a playground, the residential blocks at Farragut Houses — and it is wrong in a different direction at each of them.
1. OPEN the clock advances; arrivals spawn
2. PERCEIVE groups read visible state; no writes
3. ACT groups emit intents; buffered, not applied
4. RESOLVE engine applies intents in a fixed
order and writes the event log
A group may not observe another group's action from the same tick. Actions taken in tick n become visible in tick n+1. This removes order-dependence between agents, which is the precondition for the run being reproducible at all.
Places have capacity. When more groups want a bench, a cafe table or a viewpoint than it holds, the engine resolves intents in ascending group_id — never arrival order, never insertion order, never the order the array happens to be in. A group that loses is re-routed to another place of the same kind that still has room, and emits place.contended. If nothing of that kind has room it abandons the slot and moves on.
This is the literal race condition, and it is deliberately made boring: a real one would be a bug. The interesting race is the one against the train timetable, which no amount of careful scheduling removes.
Everything on this page is the twin. It makes the same shape of decisions as a language-model agent would — pick a scenario, pick places matching it, re-plan when blocked — with zero model calls, so the whole run is a pure function of the seed. A model-backed variant is specified in the repository and is deliberately not shipped here: an artifact that produces different answers on every load cannot be checked by a reader, and this programme's entire method is that a reader can check it.
Five separate policies rather than five options on one policy, so that what each layer adds can be read off by running them against the same seed and diffing the result. Switching rung re-runs from the same seed for exactly that reason.
“what each layer adds can be read off by diffing runs at the same seed”The group sub-seed included the rung. Diffing two rungs at one seed therefore compared two different random samples rather than the same people under a richer policy, so the diff measured resampling as much as it measured the policy. The rung has been removed from the sub-seed and the ladder is now genuinely paired. This changes the numbers every rung reports. No claim elsewhere in this repository rests on them — the figures on this page are computed in the reader's own browser and are never quoted as findings — but the change is stated rather than absorbed.
The same seed, day type, hour, population and rung produce a byte-identical event log. Sub-seeds are derived per group, so changing the population size does not reshuffle the groups that were already there.
Ratings. Measured sound levels 5/5 — MTA's own instrumented sessions. Train headway 5/5 — MTA GTFS. Anchor positions 2/5 — digitised by eye. Noise field between anchors 1/5 — interpolation with no physics. Itineraries, group sizes, walking speeds 1/5 — invented. Visitor dwell 4/5 for Louisville, 2/5 as a transfer to Brooklyn. Susceptibility prevalences 4/5 in the populations they were measured in, 1/5 as a statement about who is in this corridor. The share of groups that bring a dog 1/5 — reasoned from a transit rule, not counted. Feeder-line headways at York St and High St 1/5 — plausible timetable intervals, one constant away from being computed from the GTFS tooling already here. Stair-climb dispersal 1/5 — invented, and swept rather than asserted.
Part of the DUMBO rail-noise research programme. Frequency dashboard · 3D model · Acoustic demo · Overview