fuzzyworld

tower / files / src / canon / constants.ts

constants.ts

11.0 KB · history · blame

1/**
2 * Tower canon. See design.md §1.
3 *
4 * Per decisions.md D-007, only the values in FREE PARAMETERS are chosen. Everything
5 * below them is derived, so changing the radius changes the whole world coherently.
6 * test/canon.test.ts pins every derived figure to the number printed in design.md.
7 */
8
9// ---------------------------------------------------------------- free parameters
10export const RADIUS_M = 50_000
11export const LENGTH_M = 540_000
12/**
13 * Canon default: **none**. The hull is sealed (design.md §1.4, D-017).
14 * The 0–16 control in src/canon/slats.ts is retained as an exploration tool for
15 * the author, not because canon is undecided.
16 */
17export const SLAT_COUNT_DEFAULT = 0
18export const SLAT_COUNT_MIN = 0
19export const SLAT_COUNT_MAX = 16
20/** Wisconsin's land area. Slats are sized to leave exactly this much land (D-002). */
21export const TARGET_LAND_AREA_M2 = 140_268e6
22
23// ------------------------------------------------------------------------ physics
24export const G0 = 9.80665
25export const SOLAR_CONSTANT_W_M2 = 1361
26/** Speed of light, for radiation pressure. */
27export const C_M_S = 2.998e8
28
29// ----------------------------------------------------------------------- geometry
30export const CIRCUMFERENCE_M = 2 * Math.PI * RADIUS_M
31export const INNER_AREA_M2 = CIRCUMFERENCE_M * LENGTH_M
32
33// ------------------------------------------------------------- spin (design.md §1.2)
34/** Angular velocity giving exactly 1 g at the floor. */
35export const OMEGA_RAD_S = Math.sqrt(G0 / RADIUS_M)
36export const SPIN_PERIOD_S = (2 * Math.PI) / OMEGA_RAD_S
37export const RIM_SPEED_M_S = OMEGA_RAD_S * RADIUS_M
38/** Gravity at radius `s` from the axis. Zero on the axis, 1 g at the floor. */
39export const gravityAtRadius = (s: number): number => OMEGA_RAD_S ** 2 * s
40/** Gravity at height `h` above the floor. */
41export const gravityAtHeight = (h: number): number => gravityAtRadius(RADIUS_M - h)
42
43// ------------------------------------------------------------ slats (design.md §1.4)
44/**
45 * Total slat width is fixed by the land-area target (D-002) and does NOT depend on
46 * how many slats that width is divided into. So changing the slat count changes
47 * how wide each one is, and leaves Tower's land area exactly Wisconsin's.
48 */
49export const SLAT_TOTAL_WIDTH_M = (INNER_AREA_M2 - TARGET_LAND_AREA_M2) / LENGTH_M
50/** Land area with at least one slat. With none, the land is the whole surface. */
51export const LAND_AREA_M2 = CIRCUMFERENCE_M * LENGTH_M - SLAT_TOTAL_WIDTH_M * LENGTH_M
52
53// ------------------------------------------------------- sun system (design.md §1.3)
54export const BEAM_CIRCUMFERENCE_M = 10_000
55export const BEAM_RADIUS_M = BEAM_CIRCUMFERENCE_M / (2 * Math.PI)
56export const BEAM_AREA_M2 = Math.PI * BEAM_RADIUS_M ** 2
57/** Odeillo-class, and 11% of the étendue limit. See D-003. */
58export const BEAM_CONCENTRATION = 5_000
59export const BEAM_INTENSITY_W_M2 = SOLAR_CONSTANT_W_M2 * BEAM_CONCENTRATION
60export const BEAM_POWER_W = BEAM_AREA_M2 * BEAM_INTENSITY_W_M2
61/** Thermodynamic ceiling on passive concentration at 1 AU (D-003). */
62export const ETENDUE_LIMIT = 46_223
63
64/** The sun's disc from Tower's orbit — 0.53°, and the reason the eclipse is total. */
65export const SUN_ANGULAR_DIAMETER_RAD = 0.53 * Math.PI / 180
66export const COLLECTOR_EFFICIENCY = 0.85
67export const COLLECTOR_AREA_M2 = BEAM_POWER_W / SOLAR_CONSTANT_W_M2 / COLLECTOR_EFFICIENCY
68export const COLLECTOR_DIAMETER_M = 2 * Math.sqrt(COLLECTOR_AREA_M2 / Math.PI)
69/**
70 * How far ahead of the sun cap the collector flies. Not fixed by canon, but it has
71 * to live here rather than in one view: both 3D views draw the collector now, and
72 * the interior needs it to decide which part of the sun cap window it covers.
73 */
74export const COLLECTOR_STANDOFF_M = 320_000
75/**
76 * The collector is **41.8° across from the sun cap — 79 times the sun's diameter**,
77 * so it occults the sun completely and Tower sits in its umbra permanently. Nobody
78 * aboard can see the sun, for the same reason nobody can see Earth (§1.4). From
79 * inside, the back of it is the only object in the sky that is neither Tower nor a
80 * star, and it never moves. D-050.
81 */
82export const COLLECTOR_ANGULAR_DIAMETER_RAD =
83 2 * Math.atan(COLLECTOR_DIAMETER_M / 2 / COLLECTOR_STANDOFF_M)
84/**
85 * The sunlit rim.
86 *
87 * The collector's face is a mirror pointed away from Tower, so from inside it is a
88 * black disc — but it is a **backlit** black disc, and its edge is not. The array
89 * has to hold 46,938 km² flat, and the structure that does it stands proud of the
90 * mirror plane at the rim, where the sun strikes it side-on. Add the scatter any
91 * real mirror throws at grazing incidence and the edge reads as a thin sun-coloured
92 * ring: a crescent of lit structure with nothing behind it. 4 km on a 244 km disc.
93 *
94 * Note what it is *not*: sunlight leaking past the edge. Tower sits wholly inside
95 * the umbra (below), so the sun's disc is hidden from every point in the world. The
96 * ring is lit structure, not a sliver of star. D-054.
97 */
98export const COLLECTOR_RIM_M = 4000
99
100/**
101 * Umbra radius at the sun cap. Tower's 51 km sits well inside it, which is what
102 * makes the eclipse total rather than partial.
103 */
104export const COLLECTOR_UMBRA_RADIUS_M =
105 COLLECTOR_DIAMETER_M / 2 - COLLECTOR_STANDOFF_M * (SUN_ANGULAR_DIAMETER_RAD / 2)
106
107// ---------------------------------------------------- diffuser swarm (design.md §1.3.1)
108export const MIRRORLET_EDGE_M = 0.012
109export const MIRRORLET_AREA_M2 = MIRRORLET_EDGE_M ** 2
110export const MIRRORLET_MASS_KG = 2.0e-6
111/** Projected mirror area needed to divert the whole beam, tilted ~45°. */
112export const SWARM_AREA_M2 = BEAM_AREA_M2 * Math.SQRT2
113export const SWARM_COUNT = SWARM_AREA_M2 / MIRRORLET_AREA_M2
114export const SWARM_MASS_KG = SWARM_COUNT * MIRRORLET_MASS_KG
115export const SWARM_OPTICAL_DEPTH = (SWARM_COUNT / (BEAM_AREA_M2 * LENGTH_M)) * MIRRORLET_AREA_M2 * LENGTH_M
116/** Green-light diffraction limit of one mirrorlet — sets Tower's aiming resolution. */
117export const MIRRORLET_DIFFRACTION_RAD = 550e-9 / MIRRORLET_EDGE_M
118export const AIM_SPOT_AT_FLOOR_M = MIRRORLET_DIFFRACTION_RAD * RADIUS_M
119
120// --------------------------------------------------- illumination (design.md §1.3)
121/** Mean insolation settings, W/m² over the whole inner surface. */
122export const BRIGHTNESS_TWILIGHT_W_M2 = 30
123export const BRIGHTNESS_TEMPERATE_W_M2 = 200
124export const BRIGHTNESS_FULL_W_M2 = BEAM_POWER_W / INNER_AREA_M2
125// ------------------------------------------- the far cap mirror (design.md §1.3.2)
126/**
127 * What survives the swarm arrives collimated, in the beam's own cross-section —
128 * 7.96 km², a thousandth of the far cap's 7,854. So the load is not 13 TW spread
129 * over a disc; it is **1.7 MW/m² in a 3.2 km spot**, some 1,200 suns, which an
130 * absorber would sit at 2,330 K to re-radiate. D-048 puts a mirror there instead.
131 */
132export const BEAM_FAR_CAP_FLUX_W_M2 =
133 (BEAM_POWER_W * Math.exp(-SWARM_OPTICAL_DEPTH)) / BEAM_AREA_M2
134/** Sized to the beam's 1,592 m with a margin, since the spot is not held perfectly. */
135export const FAR_CAP_MIRROR_RADIUS_M = 2000
136/**
137 * A mirror is the cheap thermal answer, not the expensive one: at 99.9% it absorbs
138 * about 1.2 Earth solar constants, which is a warm plate rather than a glowing one.
139 */
140export const FAR_CAP_MIRROR_REFLECTIVITY = 0.999
141export const FAR_CAP_MIRROR_ABSORBED_W_M2 =
142 BEAM_FAR_CAP_FLUX_W_M2 * (1 - FAR_CAP_MIRROR_REFLECTIVITY)
143/**
144 * Returning the residual for a second pass makes the optical column 1,080 km
145 * rather than 540, so utilisation is 1 - e^(-2τ) instead of 1 - e^(-τ): **94%**
146 * against 76%. What survives even that exits the beam aperture toward the
147 * collector, which returns it again — so in the limit the whole 54.3 TW lands on
148 * the inner surface, and BRIGHTNESS_FULL_W_M2 is right as it stands (D-048).
149 */
150export const BEAM_UTILISATION_ONE_PASS = 1 - Math.exp(-SWARM_OPTICAL_DEPTH)
151export const BEAM_UTILISATION_TWO_PASS = 1 - Math.exp(-2 * SWARM_OPTICAL_DEPTH)
152
153/**
154 * The beam's own glow, seen from the floor (design.md §1.3).
155 *
156 * Radiance is the figure §1.3 states — 26x a clear blue sky — and is taken from
157 * the doc rather than re-derived here; the derivation needs the Rayleigh phase
158 * function and the air density at the axis, and a second version of it that
159 * disagreed by 30% would be worse than none. The angular width IS derived, and
160 * comes out at the 3.65° §1.3 prints.
161 */
162export const BEAM_RADIANCE_W_M2_SR = 779
163export const BEAM_ANGULAR_WIDTH_RAD = 2 * Math.atan(BEAM_RADIUS_M / RADIUS_M)
164
165/**
166 * Night is made by banking the beam, not by aiming the swarm away — §1.3 says the
167 * glow belongs to the beam and the air, so a lit beam lights the world whatever
168 * the diffusers do. A thousandth of full leaves a rod you can still find overhead
169 * and a world you can just make out under it. D-046.
170 */
171export const NIGHT_BEAM_FRACTION = 0.001
172export const BRIGHTNESS_NIGHT_W_M2 = BRIGHTNESS_FULL_W_M2 * NIGHT_BEAM_FRACTION
173
174// ------------------------------------------------ the day cycle (design.md §1.3.4)
175/**
176 * Tower's day. Nothing physical sets it — there is no rotation to inherit one from,
177 * since the spin is 7.5 minutes and has nothing to do with light. It is chosen for
178 * the people living under it, so it is Earth's: Tower keeps an Earth city's clock and
179 * its sunrises and sunsets (D-074, src/world/sky.ts).
180 */
181export const DAY_LENGTH_S = 86_400
182/**
183 * How long Tower's sun takes to light after sunrise, and to go out before sunset: the
184 * swarm gathering into its shoal at the sun cap, and dispersing at the far cap. D-074.
185 */
186export const SUN_RAMP_H = 0.25
187
188/**
189 * Tower's moon (D-088): by night a second, smaller gathering of the swarm on the banked
190 * beam, the size of the sun, which lights at the far cap as the sun goes out there and
191 * crosses the world the other way, to the sun cap by sunrise. It keeps Earth's Moon's
192 * phases, lit as much as the Moon is lit that night.
193 *
194 * At full it throws as much light on the floor as the whole banked rod does, so a full-moon
195 * night is twice as bright as a moonless one; Tower banks the beam that much less to feed
196 * it. That is a choice, not a physical necessity: Earth's full moon is about a hundred and
197 * fiftieth of Tower's banked night, and would be lost in it.
198 */
199export const MOON_AT_FULL_OF_NIGHT = 1
200export const MOON_RADIUS_M = BEAM_RADIUS_M
201/** The sun's radius on the axis: the beam's own, since it is the beam that is lit up. */
202export const SUN_RADIUS_M = BEAM_RADIUS_M
203
204// --------------------------------------------------------- structure (design.md §1.1)
205/**
206 * Wall depth, floor to outer skin. Canon had no figure for this; 1 km is 2% of the
207 * radius — enough to read as built from outside and to give the cap windows a
208 * reveal you can see the depth of, without making Tower a pipe. D-044.
209 */
210export const HULL_DEPTH_M = 1000
211
212// --------------------------------------------------- atmosphere (design.md §1.5)
213export const SPECIFIC_GAS_CONSTANT = 287
214export const TEMPERATURE_K = 288
215export const FLOOR_PRESSURE_PA = 101_325
216export const FLOOR_DENSITY_KG_M3 = FLOOR_PRESSURE_PA / (SPECIFIC_GAS_CONSTANT * TEMPERATURE_K)
217/** Rayleigh volume scattering coefficient at floor density, 550 nm. */
218export const RAYLEIGH_FLOOR_PER_M = 1.16e-5