← All notes

One Camera Sees a Plane

Here is a fact about watching something burn up in the atmosphere that I did not expect and that turns out to govern everything else.

If you stand in a field and watch a fireball cross the sky, you can describe the arc it made. You can say it started over there and ended over there, and you can be precise about it: azimuth and elevation at both ends, which is exactly what a fireball report form asks for.

That description does not tell you where the object was.

Your eye and the path it traced define a plane in space. The rock was somewhere on that plane. It could have been small and close or enormous and far away, and from where you stood those two possibilities look identical. You have constrained it to a surface, not to a line.

Two observers, far enough apart, each get their own plane. Two planes meet in a line. That line is the trajectory, and now you know the altitude it started at, the altitude it went dark at, how far it flew, and which direction it was heading.

That is the whole reason fireball networks exist as networks rather than as a collection of cameras. It is a geometric limit, not a software one, and there is no processing step that recovers the missing dimension from a single view.

I built a solver for this. It has a front end now, which is what these screenshots are. What follows is what the building taught me, which turned out to be less about astronomy than I expected.

A shallow fireball trajectory descending left to right toward the ground, a vertical dropline marking where it stopped glowing, four impact points on the ground below it, and two observer markers some distance apart

The method is older than the computers

The approach is plane intersection, and it goes back to Ceplecha in the 1980s. It is pleasingly direct.

For each station, take the two sightlines, one to where the fireball appeared and one to where it vanished. Their cross product is the normal of that station's plane. Do it again for the second station. The cross product of the two normals is the direction of the trajectory. Solve a small linear system for a point on it, and you have the line.

Then the arithmetic gives you back things you never measured. Feed in nothing but four angles from each of two positions and you get altitudes, a path length, a heading. That still strikes me as slightly unreasonable.

I tested it by not trusting it. Invent a trajectory: entering at 82 km over one point, going dark at 21 km over another. Compute what each station would have observed. Then hand the solver nothing but those observations and see whether it gives the trajectory back.

It recovers both altitudes to within 100 metres across a 112 km path. That is the only kind of test worth writing for geometry code, because geometry that is subtly wrong produces confident, plausible, completely incorrect numbers, and you will never catch it by reading the output.

After it goes dark, it is a re-entry problem

Somewhere around 15 to 20 km up, the object has shed enough speed that it stops glowing. Whatever survives is now an ordinary rock falling through an atmosphere, and this phase is called dark flight.

Anyone who has flown a rocket game will recognise the governing quantity immediately. It is the ballistic coefficient:

beta = m / (Cd * A)

Mass over drag area. Heavy and compact means a large beta, which means the fragment holds its speed and carries a long way downrange. Light and flat means a small beta, which means it sheds speed almost immediately and drops nearly straight down.

So a fireball that fragments does not scatter pieces in a circle. It lays them out in an ellipse sorted by mass, with the big ones at the far end. Running the same terminal conditions at four different masses:

Fragment Downrange Fall time Impact speed
10 kg 14.65 km 126 s 82 m/s
1 kg 9.71 km 200 s 55 m/s
100 g 5.98 km 307 s 37 m/s
10 g 3.44 km 463 s 25 m/s

Eleven kilometres of spread, from one point, from one event, purely because of mass. That is why people who hunt meteorites walk a line rather than circling a spot.

The four fragments as a line of points on the ground against a 20 km grid, heaviest nearest the dropline and lightest furthest downrange, with a search ellipse drawn around them

Notice the fall times too. The small fragments are in the air for nearly eight minutes after the light show is over, which is the other half of the problem.

Still air is an assumption, not a measurement

Those numbers are computed in still air, and still air does not exist at 20 km.

Upper level winds move a strewn field by kilometres. I tested it against the same case as the table above: a uniform 30 m/s wind moves the landing point of the one kilogram fragment by nearly six kilometres, and the lighter pieces move further still because they spend longer in it. That is a bigger displacement than the entire mass sorting between the 1 kg and 10 g fragments.

So the model accepts a wind profile, and it defaults to none, and the output says so rather than quietly presenting a still-air answer as a location. A strewn field computed without real atmospheric sounding data is a correct shape in the wrong place, which is worse than no answer because it looks like one.

The mistake, which is the actual point

My first version guarded against bad station geometry by checking for floating point collapse. If the cross product of the two plane normals came out near zero, the planes were parallel and there was no line to find, so I refused.

The self test caught it as a failure, and it was right to.

Two stations fifty metres apart still produce a cross product comfortably above any floating point epsilon. The code sailed through and returned an answer. The answer was garbage.

Error in the solved trajectory grows roughly as 1 / sin(convergence angle). As the two viewing planes approach parallel, the solution does not become unstable or throw or produce a NaN. It degrades smoothly and continuously into nonsense, while still looking exactly like a number with metres and degrees attached to it.

So the guard was in the wrong place. It is now on the physics rather than the arithmetic: below five degrees of convergence the solver refuses and tells you to move a station or find a third. The threshold is a judgement about acceptable error, not a property of IEEE 754.

I have now written about this same shape three times in a month, in three systems that have nothing to do with each other.

A contract address typed into a table, which looks authoritative because it is sitting right there in the code, and returns a real balance under a confident wrong label.

A honeypot field that caught real customers and answered every one of them with a success message, because a caught bot is a success and successes do not get logged.

And now a triangulation that has no valid solution and hands you one anyway, to the metre.

None of those crash. Not one produces an error, a stack trace, or a red line in a dashboard. Every one of them returns a well formed answer that happens to be false, and in all three cases the fix was the same: decide what "I do not know" looks like, and make the system capable of saying it.

That last part is the hard bit. unknown is a real answer and most software is not built to give it. It is easier to return something.

What it cannot do yet

The solver interface: latitude, longitude, altitude and four angles entered for each of two stations on the left, the solved trajectory drawn in 3D on the right

Velocity is currently an input. With synchronised timestamps at both stations it becomes an output, along with deceleration, and from deceleration you can work backwards toward the orbit the thing was on before it hit us. That is the part I actually want.

Fifty one checks now, across two suites, and they finish in about a third of a second. Twenty five of them pin the geometry and the dark flight against figures the original produced, which is how I know the port did not drift. The other twenty six pin the shape of the fireball data feed, written from the published schema by someone who could not reach the API to look, which is exactly the code that fails silently in production if nobody tests it.

The solver itself still touches no network and reads no data files. That is deliberate: one plain file runs in a browser, in a server route, and under bare node, so anyone can check the arithmetic without a build step. The app around it reaches the network for one thing only, which is the historical record.

And it has still never been pointed at a real event. Everything it has solved is synthetic truth, and I would rather say that plainly than imply otherwise.

If you ever do see a bright one: note the time, and note the direction and the height where it appeared and where it vanished. From one position that is a plane. But somebody else was probably watching too.

Gunnar

Founder, Tofte Ventures LLC