Lunar Outpost One-Line

A 120 VDC microgrid with the reactor a kilometre out. The simulation runs in this page — scrub the clock or change the outpost and the diagram answers.

Phase as seen from Earth. A near-side equatorial site has local noon at full moon, so this disc reads the outpost's own clock.
0000 h lunar day

Energy signal — fleet reserve

1.0000
what a conventional controller watches

Power signal — headroom

+0.00 kW
what this project added

Estimator — battery charge

0.9500
inferred from voltage; no sensor reads this
Drawn from buildTopology(), not by hand — the feeder lengths, voltages and conductor areas shown are the ones the model used.

Clock

0 / 1439
100 m²

This 60-day run

Generated
—
Served
—
Unserved
—
Curtailed
—
Conductor loss
—
Converter loss
—
Controller actions
—

Power balance

Where the watts came from, hour by hour. Night is shaded.

PV Reactor Storage Demand

Storage reserves

The two-tier split. The shaded strip is the hysteresis dead band.

Fleet Battery Fuel cell

What no instrument can measure

There is no state-of-charge sensor. The dashed line is the truth the simulation knows; the solid line is what an EKF infers from terminal voltage and a current sensor biased by 2 A.

truth EKF estimate coulomb counting alone

Kalman gain — how much it believes the voltmeter

Near zero the filter has stopped listening and is coasting on its own arithmetic. The gain follows the OCV slope, so it collapses wherever the curve flattens — chemistry, not tuning.

gain K estimate − truth

Power headroom

The signal this project added. Below zero, the bus cannot meet demand.

Headroom Discharge ceiling Unserved

Load shedding

A bar marks every hour a load was disconnected. ECLSS never sheds.

rows ordered by priority — least important sheds first

What this is

An hour-by-hour simulation of the power system for an autonomous lunar outpost — a photovoltaic array, a fission reactor, a battery, a regenerative fuel cell, four loads, and a controller that decides what to switch off when the reserves run low. It runs 60 days, just over two full lunar cycles, and the whole thing is executing in this page.

The question it answers

A conventional microgrid controller watches one signal: state of charge. Run a reactor outage through this model in deep lunar night and that signal reports everything is fine while the outpost is already browning out.

FAILURE MODE — why the bad hours were bad energy-limited 0.0 h (reserve below 0.30) power-limited 1.0 h (100% of shortfall hours) worst power-limited SoC 0.6159 <- reserve looked this healthy while the bus was failing

Every hour of unserved power happened at a fleet reserve of 0.62 — comfortably above the 0.30 shed threshold, and rising. The mechanism is the two-tier storage: the battery is fast but shallow and empties about 36 hours into a 354-hour night; the fuel cell is deep but slow, holding 2090 kWh behind a 12 kW stack. The fleet can be full of energy and still unable to deliver it fast enough. Hence two signals rather than one — a capacity-weighted energy reserve and a measured power headroom, with the controller acting on whichever fires first.

How to read the diagram

The wire is not free

Switch the conductors and converters off and on to see this. Modelling them turns a run that met its load perfectly into one that does not:

60-day runUnservedLoss
Power balance only0.0 kWh—
Conductors10.3 kWh8.56 %
Converters142.1 kWh9.79 %
Both155.5 kWh18.10 %

The silicon costs more than the copper — fourteen times the unserved energy. Copper gets drawn on diagrams and attracts the attention; the power electronics are a box on a wall. Two further findings fall out of the same model: a conductor on the regolith runs near 400 K in sunlight and 100 K at night, so it is worst exactly when the array is pushing hardest; and running the reactor link at user-bus voltage instead of 1000 V would need 736 mm² of aluminium and 3975 kg — a busbar, not a cable.

Why you can believe the numbers

This page runs a JavaScript port of a Python model. A port that fails loudly is not the risk; one that diverges quietly is — a <= where a < belongs leaves two simulators and no way to say which is right. So the port is held to the Python original tick for tick:

scenario ticks fields checks worst rel result bare 1440 46 66240 4.63e-10 PASS topology 1440 46 66240 4.93e-10 PASS full 1440 46 66240 4.91e-10 PASS

198,720 comparisons. That 5e-10 is the reference file's storage format, not the model: at full precision one scenario is bit-identical and the others agree to 1.85e-16, under one ULP of a double. The diagram above is generated from the same buildTopology() the simulation uses, and the model inside this page is injected from the very bundle that passes those checks — so nothing here can drift from what was verified. On the Python side: 300 tests, plus a mutation check that reintroduces nine bugs the project actually shipped and confirms the suite catches eight, the ninth being a provably equivalent mutant.

Declared simplifications

Stated so absence is not mistaken for oversight: dust accumulation is a fixed derate rather than a mechanism that worsens over mission life; source impedance is not modelled, so fault currents are upper bounds; every fault is bolted, and a real arcing fault draws less current and is harder to detect; the linear temperature coefficient is optimistic near 100 K; and the controller has never actually run on a microcontroller, though it was written numpy-free so it could.

Source, tests and full write-up: github.com/troyfrancoceldran-ctrl/Autonomous-lunar-power-grid-simulation