Keeping Time · Part 1 of 7
One Turn an Hour
Every watch in Tick Again is a model of a real movement. A wheel on the bench is a toothing with a count and a module, meshing with a pinion that has its own; the hands move because the train turns them, and the seconds hand steps because the train only moves when the escapement lets it. None of it is keyframed. This series walks through that model, which lives in a Swift package called TickAgainCore with no interface in it at all, and it starts where a watch's power goes: down the train.
Five arbors
The first caliber in the game, C1, is a Swiss lever pocket watch, and its train is the textbook one for its beat. The mainspring's barrel has 72 teeth and drives a pinion of 12 on the centre arbor. The centre wheel, 80 teeth, drives a third pinion of 10; the third wheel, 75, drives a fourth pinion of 10; the fourth wheel, 80, drives an escape pinion of 8; and the escape wheel has 15 club teeth that the pallets let go one half at a time.
Start from the hand
The obvious way to work out a train is to start at the barrel and multiply forward. The game starts at the other end. Whatever arbor carries the minute hand is fixed at exactly one turn an hour, and every other arbor’s rate is worked out from it by walking the meshes outward, multiplying by the driver’s count over the follower’s at each step, with a minus sign because meshing wheels turn opposite ways.
public init(_ caliber: Caliber) throws {
var rates: [String: Double] = [caliber.hands.minute: 1]
// Every mesh as a link both ways between two arbors.
var links: [String: [(to: String, factor: Double)]] = [:]
for mesh in caliber.meshes {
guard let a = caliber.toothing(mesh.driver) else { throw Failure.missingToothing(mesh.driver) }
guard let b = caliber.toothing(mesh.follower) else { throw Failure.missingToothing(mesh.follower) }
guard abs(a.module - b.module) < 1e-9 else { throw Failure.moduleMismatch(mesh) }
let factor = -Double(a.count) / Double(b.count)
links[mesh.driver.arbor, default: []].append((mesh.follower.arbor, factor))
links[mesh.follower.arbor, default: []].append((mesh.driver.arbor, 1 / factor))
}Starting from the hand means the one fact every watch must satisfy is the starting point rather than something to check afterwards. Two wheels can only mesh if their teeth are the same size, so a mesh between different modules is refused before any arithmetic happens. And because the walk reaches some arbors by more than one path, an arbor that comes out at two different rates is a contradiction, and the model throws rather than pick one. The type’s own comment puts it plainly: no physics and no rounding, so a ratio that is wrong in the data comes out wrong here.
For C1 the walk comes out like this, with a turn clockwise seen from the dial counted positive:
Half a tooth a beat
The escape wheel turning 600 times an hour is where the train meets the balance. Each tooth of the escape wheel is released in two halves, one by each pallet, and each release is one beat, the tick or the tock you hear. So the beat rate falls straight out of the train: 600 turns an hour, times 15 teeth, times two beats a tooth, is 18,000 beats an hour. Five a second. A full swing of the balance there and back is two beats, so the balance swings at 2.5 hertz, and every beat moves the escape wheel 12 degrees.
C1 also declares its beat outright, as the escapement’s own figure of 18,000. The model never quietly trusts one of the two numbers. A test checks that the train and the escapement agree, for every caliber in the game.
Before you read on
Suppose the third wheel had been cut with 74 teeth instead of 75. The balance still beats 18,000 times an hour. Does the watch gain, lose, or stop?
It gains, and badly. The balance sets the pace, so the escape wheel still turns 600 times an hour; one tooth fewer on the third wheel means the hands are turned 75/74 as fast for the same beats, and the watch gains about nineteen minutes a day. In the model it never gets that far. Starting from the minute hand, the walk says this train needs 17,760 beats an hour, the escapement says 18,000, and testAWrongRatioIsCaught fails. That is the test’s whole purpose: a typo in a tooth count cannot ship.
A watch with no centre wheel
Starting from the minute hand rather than from a wheel called the centre wheel turns out to matter. C3 is a Roskopf, the cheap pin-lever pocket watch, and Roskopf’s economy was to leave the centre wheel out. A large barrel sits just above the middle and drives the going train directly, while a second set of teeth on the same barrel, 40 of them, turns the cannon pinion of 10 that carries the minute hand on a fixed post. The minute hand is driven backwards off the barrel, from the dial side, by a wheel that has nothing to do with the train that keeps time.
The walk does not care. The cannon is seeded at one turn an hour, the barrel comes out at a quarter turn the other way, and the going train follows: 64 on 8, 48 on 8, 40 on 8, 60 on 6 and an escape wheel of 15, which again is 18,000 beats. The same function handles both watches with no special case, which is a better argument for a design than anything I could say about it. The Roskopf’s counts are marked in the source for review against a real one; C1’s are the standard ones.
What the tests hold
The train has the strictest tests in the package, because everything else in the game stands on it:
- For every caliber, the beat rate the train implies equals the one the escapement declares.
- The hands turn at one turn an hour, one turn in twelve, and sixty an hour for seconds, all clockwise.
- Every pair of meshing arbors stands apart by exactly the sum of their pitch radii, to a thousandth of a millimetre. The test’s own comment notes that this is tighter than any watchmaker could measure.
- A third wheel cut with 74 teeth is caught, and a fourth pinion at the wrong module is refused.
All of that is arithmetic, and it is the easy part. The train only says how far each wheel turns per beat. When it turns, and how a beat actually happens, is the escapement’s business, and that is the next article.