Astrolabe Follow-Up: Apparently “Accurate Enough” Wasn't
A HomeSeer plugin’s unexpected journey from twilight to precision astronomy
Down the Accuracy Rabbit Hole
How chasing a few arcseconds uncovered clocks, relativity, Earth wobble, and mountains on the Moon
A little follow-up to my earlier Astrolabe post.
When I first wrote about the plugin, the astronomy engine was already considerably more elaborate than anything HomeSeer really needs in order to turn lights on at sunset.
It calculated twilight, lunar events, planets, eclipses, occultations, satellite passes, and a growing collection of other things.
And the accuracy was already quite good.
Which should probably have been the end of that particular discussion.
Instead, I made the mistake of asking:
How much better could it be?
That has gone about as expected.
If I'm going to calculate it, why knowingly use the older model?
The original implementation used several astronomical models that were entirely adequate for home automation and, frankly, quite a bit beyond adequate.
But once I started looking carefully at where the remaining errors came from, I found myself making a different decision.
If a modern model is available, practical to implement, and measurably more accurate, there is not much reason to knowingly stay with the older approximation.
So Astrolabe got an accuracy overhaul.
Not because HomeSeer events require sub-arcsecond astronomy.
They emphatically do not.
Mostly because now I know I can.
The observation that changed the plan
My first instinct was simply to keep more terms.
The planetary code used a reduced set of orbital elements, so the obvious upgrade was the full analytical series, VSOP87 for the planets and something similarly comprehensive for the Moon.
Then I started looking more closely at where those series came from.
VSOP87 was published in 1988, and its integration constants were determined by fitting to JPL's DE200 numerical ephemeris.
Adding more terms makes the analytical theory converge more faithfully on the ephemeris and observational framework it was built around.
What it cannot do is somehow incorporate the decades of spacecraft ranging, laser ranging, astrometry, and other observations collected afterward.
That reframed the whole exercise.
The question was no longer:
How many coefficients can I afford to evaluate?
It became:
What is the best practical description of where these objects actually are?
That led somewhere considerably different.
So the planets and Moon both moved to DE440
JPL's DE440 planetary and lunar ephemeris was published in 2021.
Unlike an analytical series such as VSOP87, DE440 is based on numerical integration of the solar system and is fitted to a much newer body of observational data.
That includes spacecraft ranging from missions such as Juno at Jupiter and Cassini at Saturn, along with decades of Lunar Laser Ranging and other observations that simply did not exist when the older analytical theories were developed.
And the pleasant surprise was that improving the astronomy actually simplified the code.
I had expected to write two large coefficient generators, one for the planets and another for the Moon.
Instead, one DE440 reader of roughly 350 lines replaced three separate models:
the planetary model
the lunar series
and:
the solar series
all at once.
Against the DE440 reference, the numerical error in Astrolabe's underlying position calculations dropped from roughly 60 arcseconds for the planets and 10 arcseconds for the Moon to around the milliarcsecond level.
There is a cost.
And it is not subtle.
The plugin package went from:
835 kB
to:
31 MB.
That is almost entirely the ephemeris.
It ships with the plugin because the astronomy is supposed to work whether or not anything else does.
Thirty megabytes seemed a fairly reasonable price for carrying a small numerical model of the solar system around inside HomeSeer.
The old models became independent witnesses
The older analytical engines are still there.
Not as dead code.
As witnesses.
Each one is tested against DE440 to make sure it remains within the accuracy it is supposed to have.
And separately, the test suite makes sure the old and new implementations disagree by something.
That second test is important.
If two supposedly independent implementations suddenly produce exactly the same result, there is a possibility that one of them has quietly started calling the other.
At that point the cross-check becomes worthless.
So I actually test for disagreement.
There is something mildly entertaining about having a test whose failure message is effectively:
These two calculations agree suspiciously well.
But independence matters.
Two implementations only corroborate one another if they are genuinely two implementations.
The reference-frame machinery got modernized too
Rather than adding individual corrections separately to each astronomical feature, I also moved the underlying coordinate machinery onto the modern framework:
IAU 2006 precession
with:
IAU 2000A nutation.
That means planets, the Moon, stars, twilight calculations, altitude and azimuth, and the other astronomical features all use the same transformation machinery.
That may be the most important improvement architecturally.
The goal was not merely:
Make Jupiter more accurate.
It was:
Make the entire astronomical engine agree with itself about what coordinate system it is using.
That tends to be healthier.
Then Earth had to become a moving target
Of course, once you start chasing fractions of an arcsecond, Earth itself becomes inconvenient.
Its rotation is not perfectly uniform.
Its pole wanders.
The actual celestial pole does not sit exactly where the theoretical model predicts.
Normally, these are extremely small effects.
Normally, that would be an excellent reason to ignore them.
We have apparently left normally behind.
So when Internet access is allowed, Astrolabe obtains current Earth Orientation Parameters from IERS data, including:
UT1−UTC
polar motion
and:
celestial-pole offsets.
That lets it refine the theoretical Earth-orientation model with current observational data.
If that data is unavailable, nothing breaks.
Astrolabe falls back to the best locally available values and continues.
That has become an important rule throughout the plugin.
Five things I was not looking for
Here is the part I did not expect.
I went into this intending to upgrade the astronomical models.
The larger wins turned out to be errors that were simply sitting there, and none of them had much to do with which planetary theory I had chosen.
Delta T was about six seconds wrong
The difference between uniform time and Earth-rotation time had been coming from a published polynomial whose extrapolation no longer follows the Earth's recent rotation particularly well.
The resulting error had been growing:
about 2.3 seconds in 2020
about 4.1 seconds in 2023
and roughly:
6 seconds now.
That error sat inside every phase instant and every eclipse contact the plugin reported.
The single largest error in the system was not in the orbit of the Moon.
It was in the clock.
That was instructive.
Aberration was missing entirely
Light takes time to arrive.
And while it is arriving, the observer is moving around the Sun at roughly 29.8 km/s.
That changes the apparent direction of celestial objects by as much as about:
20.5 arcseconds.
The planet code already accounted for the target's movement during light travel time.
It did not account for the observer's motion.
Twenty arcseconds is larger than nearly everything I had been enthusiastically trying to improve by upgrading the ephemeris.
Sometimes the most productive optimization is discovering the correction you forgot to apply.
Gravitational light deflection was missing too
I found this one almost by accident.
I was checking five bright stars against a reference implementation.
Four agreed to within a few thousandths of an arcsecond.
Regulus was off by about 0.37 arcseconds.
That is exactly the sort of result that gets my attention.
Four stars right.
One wrong.
On the test date, Regulus happened to be sitting only about 1.2 degrees from the Sun.
The Sun's gravity was bending the incoming starlight by almost exactly the discrepancy I was seeing.
Nothing was wrong with Regulus.
General relativity had simply entered the bug report.
And:
Four right and one wrong is a much better bug report than five slightly wrong.
Sidereal time was the mean kind
The altitude and azimuth calculations had another subtle problem.
An apparent hour angle is measured from the true equinox.
The code was using mean sidereal time instead of apparent sidereal time.
That was worth roughly 8.8 arcseconds in the case I was examining.
Separately, the calculation was being handed UTC where it actually needed UT1, adding another error of roughly 13 arcseconds.
Again, neither problem was exotic.
They were just hiding comfortably underneath a larger error budget.
Once the larger errors disappeared, they became obvious.
That became something of a theme.
The Moon's altitude was being measured from the centre of the Earth
This one turned up because I asked whether we were finished.
We were not.
Every altitude the plugin displayed was geocentric, computed as though the observer were standing at the centre of the Earth rather than on its surface.
For distant objects, that makes very little practical difference.
The Sun's parallax is under nine arcseconds.
The Moon is a different matter entirely.
At one instant from my location:
Geocentric altitude: 26.2969°
Topocentric altitude: 25.4834°
A difference of:
48.8 arcminutes.
That is larger than the Moon itself appears in the sky.
And it had gone unnoticed for an excellent reason:
My reference application reports geocentric altitude as well.
Both programs agreed beautifully.
And both were answering a question no observer had asked.
Two programs agreeing is not the same as two programs being right.
Fixing it immediately broke moonrise by about six minutes.
That initially looked alarming.
Then the reason became obvious.
The standard lunar rise threshold quietly folds in the Moon's mean parallax on the assumption that the altitude being compared against it is geocentric.
Once Astrolabe began applying topocentric parallax to the Moon itself, leaving that same parallax embedded in the threshold counted it twice.
The test suite caught that within about a minute.
Which is rather the point of the test suite.
Connected data is an enhancement, never a requirement
I still want Astrolabe to function completely without depending on an outside service.
The astronomy belongs in the plugin.
So the fundamental calculations remain local:
planetary positions
lunar positions
precession and nutation
twilight
coordinate transformations
eclipse geometry
occultations
and:
satellite propagation.
All of that still works with Internet access disabled.
Satellites carry one honest asterisk.
The propagation mathematics is entirely local, but orbital element sets have to come from somewhere.
Offline, the mathematics remains perfectly happy.
It simply has nothing recent to propagate unless recent orbital data has already been obtained.
If the user permits Internet access, Astrolabe can improve certain calculations with information that genuinely benefits from being current.
The distinction is:
Models live locally. Observations can be refreshed.
And if an observation is unavailable, the model keeps going.
Connectivity can improve the answer. It is never permission to produce one.
I rather like that rule.
The atmosphere is getting involved now too
Atmospheric refraction was another obvious accuracy improvement.
Astrolabe now publishes both:
geometric altitude
and:
apparent altitude.
Those are not the same thing.
Near the horizon, refraction can move the apparent position of an object by roughly half a degree.
That rather dwarfs the arcseconds I have been enthusiastically chasing everywhere else.
A standard atmosphere provides a perfectly reasonable approximation.
But when Internet access is allowed, Astrolabe uses current weather data to improve the calculation, specifically:
temperature
and:
surface atmospheric pressure.
The important word there is surface.
Not pressure corrected to sea level.
The atmosphere causing the refraction is the atmosphere where the observer is actually standing.
A site at a few hundred meters elevation may be experiencing something nearer 975 hPa, even though the same weather report expresses the sea-level-equivalent pressure as roughly 1013 hPa.
Using the wrong one creates a systematic error in every refraction calculation.
So if the weather service says it is 31 °C with a surface pressure of 968 hPa, Astrolabe uses those conditions instead of pretending it is 10 °C at standard sea-level pressure.
Thin, warm air matters more than I expected.
Under those example conditions, horizon refraction drops from around 34 arcminutes under standard assumptions to roughly 28 arcminutes.
At sunrise or sunset, that difference translates into tens of seconds.
And if the weather feed is unavailable?
Standard atmosphere.
Calculation continues.
No drama.
Weather becomes useful for more than refraction
Once the weather data is available, it can also help answer the more practical observing question.
Astrolabe already knows things such as:
Is it astronomically dark?
Where is the Moon?
How bright is it?
Which planets are above the horizon?
Is a satellite pass occurring?
Is the satellite illuminated?
Now it can also know about:
cloud cover
and:
current atmospheric conditions.
So eventually the plugin can distinguish:
Saturn is beautifully placed tonight.
from:
Saturn is beautifully placed behind several thousand feet of cloud.
Both statements are astronomically true.
Only one is useful.
Local weather may eventually be even better
Because this is HomeSeer, there is another possibility I want to leave open.
If the user already has:
a weather station,
a barometer,
an outdoor temperature sensor,
or other trustworthy environmental sensors connected to HomeSeer,
those may provide better local inputs than a regional weather feed.
So the atmospheric-data layer is deliberately separate from its source.
Astrolabe asks:
What are the temperature and pressure at the observer?
It does not fundamentally care whether the answer came from:
a local HomeSeer sensor,
a weather-data service,
or:
a standard-atmosphere fallback.
That also means the plugin can report where the value came from.
Which leads to another improvement.
Accuracy should have provenance
Once the calculations get this detailed, I do not want Astrolabe simply presenting a number with six decimal places and silently implying absolute authority.
I want it to know how it arrived there.
So every input that can vary in source or quality carries its provenance with it.
Delta T knows whether its value came from:
live IERS data
a published determination
a forecast
an extrapolation beyond the shipped table
or:
a historical value.
The atmosphere knows whether its inputs were current or assumed.
The Earth-orientation data knows how current it is.
The ephemeris knows whether it loaded successfully.
That makes troubleshooting much more meaningful.
It also helps distinguish:
the astronomical model is wrong
from:
the observational input is stale
from:
the atmosphere is simply doing something interesting today.
Those are very different problems.
And then there is validation
The other major change was methodological.
I did not want to rely on statements such as:
This theory should be accurate to approximately one arcsecond.
I wanted to measure it.
So every important layer is now checked against an authoritative independent reference rather than against its own reputation.
The coordinate machinery is compared against the standard astronomical reference library, including nutation to eleven decimal places and the full transformation matrix element by element.
The ephemeris reader is compared against an independent reader of the same DE440 file.
Star positions are checked against independent stellar-position routines, and their catalog data comes from a professional astronomical database rather than from values copied from memory or assorted web pages.
The test suite went from:
368 checks
to:
527.
And the packaging script refuses to build the plugin if any of them fail.
Those additional tests now include things such as:
topocentric parallax
observer elevation
diurnal aberration
and:
grazing-occultation handling.
Full error distributions across many epochs are still on the list:
averages,
percentiles,
maximum errors,
behavior over time,
and object-by-object comparisons.
That part is not done yet.
But even now, this is considerably more useful than simply repeating the nominal accuracy quoted for an algorithm.
If I am going to obsess over arcseconds, I may as well collect receipts.
Proper motion made the list too
I also realized that the handful of bright stars used for lunar-occultation work were effectively being treated as though their catalog coordinates never changed.
They do.
Slowly.
Aldebaran has moved by roughly 5 arcseconds since 2000.
Regulus by roughly 6.5 arcseconds.
But once we have reached the point where tenths of an arcsecond are interesting, ignoring a quarter-century of stellar motion becomes rather inconsistent.
So those stars now get:
proper motion
annual parallax
and, as discussed above:
aberration.
There are only a handful of them.
The computational burden is effectively zero.
At this point, leaving the error in place would require more explanation than removing it.
There are still limits
None of this means Astrolabe can predict the exact visible instant of sunrise to a fraction of a second.
That would confuse mathematical precision with physical predictability.
Atmospheric refraction varies.
Temperature gradients matter.
Pressure matters.
The actual horizon matters.
Mountains have opinions.
And there is now a much more specific limit that I rather enjoy, because it is no longer really an astronomical-model problem at all.
The biggest remaining error is the shape of the Moon
Astrolabe currently models the Moon's limb as a sphere.
The real Moon has mountains and valleys.
Those features can place the actual limb two or three kilometers inward or outward from the mean reference surface.
Seen from Earth, that can amount to roughly:
1.6 arcseconds.
That is around a thousand times larger than the numerical position error underneath it.
And that physical lunar profile determines the actual timing of occultation disappearances, reappearances, and eclipse contacts.
It is also why grazing occultations exist in the first place.
Fixing that is no longer a matter of choosing another elegant formula.
It requires a lunar limb profile derived from spacecraft topography.
That is a dataset.
Not an equation.
So, for now, the limitation is documented rather than solved.
Though not entirely.
Within about 1.6 arcseconds of the limb, the terrain does not merely shift the timing.
It can decide whether the occultation happens at all.
So Astrolabe stopped asserting.
Events passing that close to the edge are now flagged as:
grazing
and reported, in effect, as:
The Moon's mountains decide this one.
rather than as a confident hit or miss.
Because:
A confident wrong answer is worse than an honest “too close to call.”
Which feels like the right place to have arrived.
The thing limiting me is no longer the model I chose.
It is terrain.
I suspect I know how this story eventually ends.
But not today.
And one limit that is not the Moon's fault
While confirming all of this, I compared the coordinates from my GPS time source against those from my phone, sitting about thirty feet apart.
They differed by:
7.9 meters.
Which is correct.
They are genuinely that far apart, and both instruments resolved it.
At this level of precision, roughly 38 meters of movement on the ground corresponds to about one arcsecond of the Moon's apparent position.
So walking from my office to the GPS antenna changes the answer by more than the diurnal aberration correction I had just spent the evening adding.
That is a wonderfully grounding result.
The honest final limit is not merely the ephemeris.
Or the reference frame.
Or even the lunar terrain.
It is that:
“Where am I?”
stops having a single useful answer at approximately the same scale as some of the corrections I am now chasing.
There is something pleasing about an accuracy project that ends by running out of place rather than running out of mathematics.
The goal was never a heroic accuracy number
So I do not want to summarize all of this by saying:
Every astronomical event is now accurate to 0.1 arcseconds.
That would be misleading.
Accuracy depends on the object.
The coordinate being reported.
The observer's location.
The epoch.
The quality of the observational data.
Atmospheric conditions.
And, apparently, whether a mountain happens to be sticking out from the edge of the Moon.
The goal is something I trust considerably more:
Use the best practical modern model for the part we can calculate.
Use current observations when they genuinely improve the result.
Track where those inputs came from.
Validate the implementation independently.
And be honest about what remains uncertain.
I like that definition of accuracy much better.
This still does not require the Internet
I keep coming back to this because it matters to me.
If Internet access is disabled:
Astrolabe still works.
It calculates the sky locally.
If Internet access is enabled, Astrolabe can refine those calculations with:
current Earth-orientation data,
atmospheric measurements,
fresh satellite elements,
weather conditions,
and eventually things such as:
space weather.
If any one of those sources disappears, Astrolabe falls back gracefully.
No external service becomes a single point of failure for the astronomy engine.
The plugin should never respond to:
Where is Jupiter?
with:
Unable to connect to weather server.
That would be an architectural failure of a fairly spectacular kind.
So this has escalated slightly
The original goal was basically:
Give HomeSeer better astronomical information than sunrise and sunset.
The list now includes:
A modern numerical ephemeris for every major body.
IAU 2006 precession and IAU 2000A nutation.
Measured Earth orientation, including polar motion and celestial-pole offsets.
Apparent sidereal time, aberration, gravitational light deflection, and diurnal aberration.
Topocentric geometry, including observer elevation.
Atmospheric refraction using current pressure and temperature.
Proper motion, parallax, and aberration for the occultation stars.
Validation against independent reference implementations at every stage.
Grazing-event recognition when lunar topography becomes the deciding factor.
Live satellite elements.
And:
weather-aware observing advice.
There was probably a perfectly reasonable point somewhere in that progression where I could have stopped.
I have not identified it.
And I am increasingly okay with that.
The nice thing is that none of this complexity has to leak into normal use.
HomeSeer can still simply ask:
Is it dark?
Is the Moon up?
Is Saturn visible?
Is there a satellite pass tonight?
The fact that the answer may quietly involve Earth's current polar motion, the observer's elevation, the actual barometric pressure outside, and exactly which side of the office I am standing on is Astrolabe's problem.
That is exactly where the complexity belongs.
So, why?
Because apparently:
Good enough for home automation
and:
As accurate as I can reasonably make it
are two very different design goals.
Astrolabe started with the first one.
I seem to be enjoying the second one more.
The underlying philosophy has become pretty simple:
Use modern models, and understand where they actually came from.
Use live observational data when Internet access is allowed and it genuinely improves the result.
Fall back gracefully when it is not available.
Keep the fundamental astronomy local.
Carry the provenance of the important inputs.
And measure the accuracy rather than merely claiming it.
Is all of this necessary to turn on the porch lights at civil dusk?
Absolutely not.
But I already knew how to do that.
This is considerably more fun. 🔭