tower / files / src / canon / constants.ts
constants.ts
ec7e78a8 2026-09-07 Pavel Safronov | 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 | |
| 10 | export const RADIUS_M = 50_000 | |
| 11 | export 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 | */ | |
| 17 | export const SLAT_COUNT_DEFAULT = 0 | |
| 18 | export const SLAT_COUNT_MIN = 0 | |
| 19 | export const SLAT_COUNT_MAX = 16 | |
| 20 | /** Wisconsin's land area. Slats are sized to leave exactly this much land (D-002). */ | |
| 21 | export const TARGET_LAND_AREA_M2 = 140_268e6 | |
| 22 | ||
| 23 | // ------------------------------------------------------------------------ physics | |
| 24 | export const G0 = 9.80665 | |
| 25 | export const SOLAR_CONSTANT_W_M2 = 1361 | |
| 26 | /** Speed of light, for radiation pressure. */ | |
| 27 | export const C_M_S = 2.998e8 | |
| 28 | ||
| 29 | // ----------------------------------------------------------------------- geometry | |
| 30 | export const CIRCUMFERENCE_M = 2 * Math.PI * RADIUS_M | |
| 31 | export 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. */ | |
| 35 | export const OMEGA_RAD_S = Math.sqrt(G0 / RADIUS_M) | |
| 36 | export const SPIN_PERIOD_S = (2 * Math.PI) / OMEGA_RAD_S | |
| 37 | export 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. */ | |
| 39 | export const gravityAtRadius = (s: number): number => OMEGA_RAD_S ** 2 * s | |
| 40 | /** Gravity at height `h` above the floor. */ | |
| 41 | export 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 | */ | |
| 49 | export 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. */ | |
| 51 | export const LAND_AREA_M2 = CIRCUMFERENCE_M * LENGTH_M - SLAT_TOTAL_WIDTH_M * LENGTH_M | |
| 52 | ||
| 53 | // ------------------------------------------------------- sun system (design.md §1.3) | |
| 54 | export const BEAM_CIRCUMFERENCE_M = 10_000 | |
| 55 | export const BEAM_RADIUS_M = BEAM_CIRCUMFERENCE_M / (2 * Math.PI) | |
| 56 | export const BEAM_AREA_M2 = Math.PI * BEAM_RADIUS_M ** 2 | |
| 57 | /** Odeillo-class, and 11% of the étendue limit. See D-003. */ | |
| 58 | export const BEAM_CONCENTRATION = 5_000 | |
| 59 | export const BEAM_INTENSITY_W_M2 = SOLAR_CONSTANT_W_M2 * BEAM_CONCENTRATION | |
| 60 | export const BEAM_POWER_W = BEAM_AREA_M2 * BEAM_INTENSITY_W_M2 | |
| 61 | /** Thermodynamic ceiling on passive concentration at 1 AU (D-003). */ | |
| 62 | export const ETENDUE_LIMIT = 46_223 | |
| 63 | ||
9c891d2e 2026-09-08 Pavel Safronov | 64 | /** The sun's disc from Tower's orbit — 0.53°, and the reason the eclipse is total. */ |
| 65 | export const SUN_ANGULAR_DIAMETER_RAD = 0.53 * Math.PI / 180 | |
ec7e78a8 2026-09-07 Pavel Safronov | 66 | export const COLLECTOR_EFFICIENCY = 0.85 |
| 67 | export const COLLECTOR_AREA_M2 = BEAM_POWER_W / SOLAR_CONSTANT_W_M2 / COLLECTOR_EFFICIENCY | |
| 68 | export const COLLECTOR_DIAMETER_M = 2 * Math.sqrt(COLLECTOR_AREA_M2 / Math.PI) | |
9c891d2e 2026-09-08 Pavel Safronov | 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 | */ | |
| 74 | export 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 | */ | |
| 82 | export const COLLECTOR_ANGULAR_DIAMETER_RAD = | |
| 83 | 2 * Math.atan(COLLECTOR_DIAMETER_M / 2 / COLLECTOR_STANDOFF_M) | |
49b0d64d 2026-09-08 Pavel Safronov | 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 | */ | |
| 98 | export const COLLECTOR_RIM_M = 4000 | |
| 99 | ||
9c891d2e 2026-09-08 Pavel Safronov | 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 | */ | |
| 104 | export const COLLECTOR_UMBRA_RADIUS_M = | |
| 105 | COLLECTOR_DIAMETER_M / 2 - COLLECTOR_STANDOFF_M * (SUN_ANGULAR_DIAMETER_RAD / 2) | |
ec7e78a8 2026-09-07 Pavel Safronov | 106 | |
| 107 | // ---------------------------------------------------- diffuser swarm (design.md §1.3.1) | |
| 108 | export const MIRRORLET_EDGE_M = 0.012 | |
| 109 | export const MIRRORLET_AREA_M2 = MIRRORLET_EDGE_M ** 2 | |
| 110 | export const MIRRORLET_MASS_KG = 2.0e-6 | |
| 111 | /** Projected mirror area needed to divert the whole beam, tilted ~45°. */ | |
| 112 | export const SWARM_AREA_M2 = BEAM_AREA_M2 * Math.SQRT2 | |
| 113 | export const SWARM_COUNT = SWARM_AREA_M2 / MIRRORLET_AREA_M2 | |
| 114 | export const SWARM_MASS_KG = SWARM_COUNT * MIRRORLET_MASS_KG | |
| 115 | export 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. */ | |
| 117 | export const MIRRORLET_DIFFRACTION_RAD = 550e-9 / MIRRORLET_EDGE_M | |
| 118 | export 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. */ | |
| 122 | export const BRIGHTNESS_TWILIGHT_W_M2 = 30 | |
| 123 | export const BRIGHTNESS_TEMPERATE_W_M2 = 200 | |
| 124 | export const BRIGHTNESS_FULL_W_M2 = BEAM_POWER_W / INNER_AREA_M2 | |
da6bcb0e 2026-09-08 Pavel Safronov | 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 | */ | |
| 132 | export 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. */ | |
| 135 | export 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 | */ | |
| 140 | export const FAR_CAP_MIRROR_REFLECTIVITY = 0.999 | |
| 141 | export 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 | */ | |
| 150 | export const BEAM_UTILISATION_ONE_PASS = 1 - Math.exp(-SWARM_OPTICAL_DEPTH) | |
| 151 | export 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 | */ | |
| 162 | export const BEAM_RADIANCE_W_M2_SR = 779 | |
| 163 | export const BEAM_ANGULAR_WIDTH_RAD = 2 * Math.atan(BEAM_RADIUS_M / RADIUS_M) | |
| 164 | ||
392bb8a7 2026-09-08 Pavel Safronov | 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 | */ | |
| 171 | export const NIGHT_BEAM_FRACTION = 0.001 | |
| 172 | export const BRIGHTNESS_NIGHT_W_M2 = BRIGHTNESS_FULL_W_M2 * NIGHT_BEAM_FRACTION | |
ec7e78a8 2026-09-07 Pavel Safronov | 173 | |
2bb3e0de 2026-09-08 Pavel Safronov | 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 | |
59c12827 2026-09-28 Pavel Safronov | 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). | |
2bb3e0de 2026-09-08 Pavel Safronov | 180 | */ |
| 181 | export const DAY_LENGTH_S = 86_400 | |
| 182 | /** | |
59c12827 2026-09-28 Pavel Safronov | 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. | |
2bb3e0de 2026-09-08 Pavel Safronov | 185 | */ |
59c12827 2026-09-28 Pavel Safronov | 186 | export const SUN_RAMP_H = 0.25 |
42b4554e 2026-09-29 Pavel Safronov | 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 | */ | |
| 199 | export const MOON_AT_FULL_OF_NIGHT = 1 | |
| 200 | export const MOON_RADIUS_M = BEAM_RADIUS_M | |
59c12827 2026-09-28 Pavel Safronov | 201 | /** The sun's radius on the axis: the beam's own, since it is the beam that is lit up. */ |
| 202 | export const SUN_RADIUS_M = BEAM_RADIUS_M | |
2bb3e0de 2026-09-08 Pavel Safronov | 203 | |
de65ab10 2026-09-08 Pavel Safronov | 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 | */ | |
| 210 | export const HULL_DEPTH_M = 1000 | |
| 211 | ||
ec7e78a8 2026-09-07 Pavel Safronov | 212 | // --------------------------------------------------- atmosphere (design.md §1.5) |
| 213 | export const SPECIFIC_GAS_CONSTANT = 287 | |
| 214 | export const TEMPERATURE_K = 288 | |
| 215 | export const FLOOR_PRESSURE_PA = 101_325 | |
| 216 | export const FLOOR_DENSITY_KG_M3 = FLOOR_PRESSURE_PA / (SPECIFIC_GAS_CONSTANT * TEMPERATURE_K) | |
| 217 | /** Rayleigh volume scattering coefficient at floor density, 550 nm. */ | |
| 218 | export const RAYLEIGH_FLOOR_PER_M = 1.16e-5 |