A yard engine shoves a cut of eight over the crest at 3.2 mph. Past the crest each car uncouples and goes down the hill on its own, and there is no throttle on the far side of that moment — only two retarders, 370 feet apart, and the clock.
A car couples cleanly at 4 mph or less. How fast it will be going when it gets there depends on its rolling resistance, and rolling resistance is the one quantity in a hump yard that nobody can read off anything. You get the weight from the weigh rail and the speed from the radar. The number that decides the answer you have to infer, from how the car has been behaving, while it is already most of the way to the place it will be wrong.
The identity underneath all of it
Resistance is quoted in pounds per ton. A grade pulls with pounds per ton too:
a_grade = g·(grade/100) a_roll = g·(R/2000)
which are equal when R = 20 · grade%. A 1% grade is worth exactly 20 lb per ton, and once you see it that way the whole yard reads as one number line:
| grade | pulls with |
|---|---|
| 4.0% — the crest drop-off | 80 lb/ton |
| 1.1% — through the master retarder | 22 lb/ton |
| 0.7% — the ladder | 14 lb/ton |
| 0.12% — the bowl | 2.4 lb/ton |
The bowl’s grade is the interesting one, because 2.4 lb/ton sits below every car in the yard. A loaded hopper resists about 2.7; an empty gondola about 7 before its journals are even considered. So the bowl is very slightly uphill for all of them. Nothing runs away down a bowl. Things stop short in one, which is a different problem and a worse one, because the car then has to be fetched.
Why the empty is the hard one
The resistance model is Davis, in the form yards use it:
R = 1.3 + 29/w + 0.045·V + 0.0024·A·V²/tons w = tons per axle
The 29/w term does nearly all the work, and it is divided by weight. A loaded
hopper carries 32 tons on each axle and pays 0.91 lb/ton for its bearings. An
empty gondola carries 6.3 and pays 4.64 for the same bearings. It is not a
worse car. It is the same drag spread over a quarter of the tons.
| tons | R at 8 mph | must arrive at the bowl doing | |
|---|---|---|---|
| loaded hopper | 128 | 2.70 | 2.8 mph |
| coil car | 112 | 2.85 | 2.9 mph |
| empty autorack | 42 | 4.82 | 4.1 mph |
| empty gondola | 25 | 6.98 | 5.0 mph |
Add the journal stiffness the demo hides from you — a wider draw on empties, because empties are the cars whose bearings and springs have the loudest say — and the real spread at the bowl throat is 3.0 mph for a 128-ton loaded hopper and 6.4 mph for a 25-ton empty gondola, with 270 ft of clear track in front of both. Twice the speed, through the same sixty feet of retarder, for two cars told apart by a number no instrument in the yard can read.
Two levers, and they are not doing the same job
F — the master retarder, 140 ft of shoes starting 150 ft past the crest.
J — the tangent retarder, 60 ft at the bowl throat, after every switch.
H holds the pusher. That is the whole input surface.
The instruments are two marks on each speed tape, and they are different kinds of thing:
- The needle (teal) is the speed this car should be doing right now to
couple at walking pace. It runs backwards from the coupling, which is the
only place in the yard where the right answer is known:
v²(s) = v_face² − 2g·drop(s→face) + 2g·(R/2000)·(face−s). R is the one term in it nobody can measure, so it is drawn as a band, not a line. - The ceiling (red) is the fastest this car can be doing and still be brought down by the retarders it has left. Above the ceiling, nothing downstream can fix it.
And here is the thing the yard is built around. For a loaded car in the master retarder, the needle reads zero. Not “slow down” — zero, as in there is no speed slow enough, because the 230 ft of 0.7% ladder waiting below hands a good roller back more than a coupling is allowed to have. The first brake cannot meter that car at all.
What it can do is keep it under the ceiling. Measured at the master retarder’s exit, that ceiling is:
LOADED HOPPER 128 t leave under 3.9 mph
COIL CAR 112 t leave under 4.8 mph
LOADED BOXCAR 97 t leave under 5.8 mph
EMPTY GONDOLA 25 t leave under 16.8 mph
So the first lever makes a capacity decision — get it slow enough that the second lever can still finish — and the second makes a precision decision. On an empty, the ceiling is so far above anything the car will ever be doing that the master retarder is simply not needed; on a loaded hopper it is the only thing standing between you and a car that cannot be saved. You can tell which is which from the weight, which you are given. That is the one gift in the game.
Where the information is, versus where the decision is
The estimate of R comes out of energy in minus energy out over the distance rolled, with a radar good to 0.45 ft/s and a fixed error per car. Its uncertainty falls as 1/distance, so, measured over twelve cuts at the moment each car arrives at each lever:
σ quoted error actually made
the master retarder, station 150 ft ±2.79 lb/ton 1.47 lb/ton
the tangent retarder, station 520 ft ±0.75 lb/ton 0.53 lb/ton
That is the shape of the whole thing. The lever that makes the decision nothing downstream can undo stands where the car has rolled 150 feet. The lever with a good reading is 370 feet too late to change the answer. Every retarder yard ever built is an argument about this gap, and the usual answer — build a third retarder further down — just moves it.
What the reference operator gets
A bang-bang operator, master riding 92% of the ceiling and tangent riding the needle, over twelve seeded cuts of eight:
never holding the hump 237s + 21s = 257s 6.1/8 clean
holding for gap 276s + 3s = 280s 7.7/8 clean
...and a resistance gauge 276s + 5s = 280s 7.6/8 clean
Two things in there are worth the trouble of having measured them.
The hurry wins on the scoreboard. Holding the pusher to keep gap costs 40 seconds of clock and saves only 17 seconds of penalty, so running the cars close is 22 seconds ahead — and buys that with 1.6 more cars a shift ending up somewhere they have to be fetched from. Which of those two numbers a yard is graded on is not a physics question, and the game does not settle it for you.
A perfect resistance gauge is worth nothing here. Not because the estimate is good — at the master retarder it is out by 1.5 lb/ton on average — but because by the lever that actually sets the coupling speed it is out by 0.5, and everything lost after that is lost to a lever that is only ever fully on or fully off, and to the cut in the bowl creeping toward the throat while the car is still in flight toward it. The expensive instrument would fix the error you can already live with.
Run node scripts/measure.mjs and every number on this page comes back out of
src/yard.mjs.
The other ways it goes wrong
- A switch will not move with steel over the points. That is the real reason
a hump has a speed limit, and it is why
Hexists: two cars rolling too close together cannot be sent to different tracks, so the second one follows the first into a block it does not belong in. A rehandle is billed at 10 seconds, which is the most expensive thing on the board and still an undercount. - Ladder switches are good for 12 mph. Leave the master retarder alone
entirely and a loaded hopper takes the first switch at 12.4, and an empty
gondola — the car you were worried about — at 10.6. The heavy one is over the
limit and the light one is not, which is the opposite of the intuition and the
same
29/wterm saying it again. - A car stopped on the ladder stops the hump, so the levers have a floor: you do not brake a car below about 1 mph inside a retarder, because every retarder in this yard sits on a grade worth more than any car’s resistance — a retarder that stops a car does not hold it, and one that keeps holding it has parked it.
- The bowl fills behind you. Each car that couples moves its track’s face 45 to 89 feet closer to the throat, and the needle for the next car into that track moves with it. The clear distance is printed under every track for exactly that reason.
What’s under it
src/yard.mjs is the engine: framework-free, headless, no canvas anywhere in
it. Feet, seconds, pounds-force, short tons. The physics is one dimensional
along the track — the ladder’s lateral weave is drawing, not simulation — and
within any one grade segment both accelerations are constant, so the
projections (coast, requiredSpeedAt, capacitySpeedAt) are closed form
rather than integrated. That is what makes it cheap enough to run the whole
prediction band twice a frame for every car in flight.
src/render.mjs is the drawing. The plan view stretches the lateral axis about
eight times, the way every yard diagram ever printed does, because the real
thing is a thousand feet long and ninety feet wide and nothing about the
physics is lateral.
Reuse
src/yard.mjs—createYard()thenstepYard(yard, dt, {master, tangent, hold}). Readneedle(yard, car),band(yard, car),carInRetarder(yard, id),tally(yard). No imports.requiredSpeedAt/capacitySpeedAt/coastare general: give them a grade profile, a resistance and a target and they answer any “what speed should this rolling thing be doing here” question. They are the reusable part.demo/carries its own copies of both modules (ADR-0002). Editsrc/, thencp src/*.mjs demo/.
Gotchas
- The grade profile is real in shape but short in length. A real hump yard’s bowl tracks are two to four thousand feet; these are two to three hundred, which is a small terminal yard at the end of a shift with its tracks nearly full. Lengthen the bowl and every transit becomes minutes, which is true of the real thing and fatal to a game.
- The tangent retarder sits after the whole ladder. In a six-track bowl there is one group, so the group retarder and the tangent-point retarder are the same set of shoes. In a big yard they are not, and the arithmetic gets worse, not better.
- The resistance estimate is fed a reading with a fixed per-car offset rather than frame noise, because that is what radar error actually looks like — a calibration and a sighting angle wrong by the same amount all the way down the hill, whose effect therefore shrinks as the car rolls further. The speed on the tape is the true one; only the estimator is lied to.
- A car held still by a live retarder is not stalled, it is held, and the engine knows the difference: only a car nobody is holding gets billed as dead on the ladder.
- Once a car is in the bowl its prediction band stops being drawn. It is still computable and still interesting and it is no longer information, because nothing you can press changes it.
window.__demoexposes the live yard for the site’s validation harness.__demo.pose(seconds)runs the real engine under the reference operator for that many seconds, which is how every screenshot inmedia/was taken and the quickest way to look at the drawing in a fixed state.


