fix(libastro): use apparent sidereal time in EquatorialToHorizontal; add accuracy tests#2383
Conversation
07d776e to
45d6cac
Compare
…add accuracy tests EquatorialToHorizontal called ln_get_hrz_from_equ which uses mean sidereal time internally, while HorizontalToEquatorial's ln_get_equ_from_hrz uses apparent sidereal time. The mismatch introduced a fixed ~17" RA offset (equation of the equinoxes) in every round-trip. Fix: call ln_get_hrz_from_equ_sidereal_time with ln_get_apparent_sidereal_time(JD) explicitly, matching the inverse path. Five tests document the accuracy of the libnova coordinate pipeline: Reciprocity: J2000toObserved -> ObservedToJ2000 closes to 0.003" for Deneb at two epochs (2020, 2026). HorizontalAccuracy_vs_IMCCE: measures accuracy against IMCCE Miriade (INPOP19) for Vega and Polaris at four sites (Greenwich, Mitaka, Mauna Kea, Siding Spring). Observed errors: Vega: az 2-17", alt 1-8" Polaris: az 0.4-0.6", alt 0.6-1.0" Polaris is nearly on the celestial pole (polar distance 0.74°) so its position is dominated by precession and nutation in RA; those are well-corrected by the libnova nutation fix. Vega's residual errors reflect the IAU 1980 nutation accuracy floor. Per-case errors are logged; the assertion catches gross regressions which cause degree-level errors. ObserverLongitudeMatters: Vega altitude spans > 30° across sites covering 316° of longitude. ObserverLatitudeMatters: Polaris is above the horizon at Greenwich (51.5 N) and below it at Siding Spring (31.3 S). RoundTrip_HorizontalToEquatorial: after the sidereal time fix, the round-trip closes to sub-picosecond (was ~11" RA before the fix). Golden data generated by tools/generate_golden_files.py (IMCCE Miriade, INPOP19).
45d6cac to
eea107e
Compare
|
Thank you! This offset was never caught in many years! Btw, how would ERFA perform in comparison with libnova for such calculations? |
I was actually looking at ERFA this week. I could not explain some of the errors I was getting compared to IMCCE which I use as the external source of truth. So I started to look into the source of the errors and found the two issues (#2382 and #2383). I am still doing the investigation and these are my current numbers: ERFA is a bit better because it has a different nutation model. ERFA200A is the full model with the highest accuracy. I was concerned that it may be too expensive for smaller embedded systems, so I also looked into a simpler model ERFA 2000B. Both are closer to the IMCCE data, but the difference to libnova is in tenth of an arcsecond with my fixes. So from an accuracy perspective this may not matter. My bigger worry about libnova is that the maintenance story is unclear. i.e. can I upstream fixes somewhere? In this case I could work around that because we have the libastro abstraction sitting on top of libnova, but in other cases that is harder. e.g. I started looking into the accuracy of the planetary models (which ERFA does not cover btw) and the moon model used in libnova has this error because it is using an older model: Btw the size of the moon is 1800", so we will still find it even with the "large" error of nearly an arcminute. |
|
Thank you for the detailed investigation. I'm not entirely sure about the maintenance status of libnova. Since the accuracy is not a big issue yet, we may consider switching to ERFA later. We can technically fork libnova and apply the fixes there as well if the upstream is no longer maintained. |
Summary
Bug fix:
EquatorialToHorizontalcalledln_get_hrz_from_equwhich uses mean sidereal time internally, whileHorizontalToEquatorial'sln_get_equ_from_hrzuses apparent sidereal time. The mismatch introduced a fixed ~17" RA offset (equation of the equinoxes) in every round-trip. Fixed by callingln_get_hrz_from_equ_sidereal_timewithln_get_apparent_sidereal_time(JD)explicitly, matching the inverse path.New tests (
test/core/test_libastro.cpp): five tests documenting the accuracy of the libnova coordinate pipeline against external truth (IMCCE Miriade, INPOP19) and internal round-trip consistency.Accuracy results
Reciprocity (J2000 -> JNow -> J2000, Deneb): < 0.003"
Round-trip (Equatorial -> Horizontal -> Equatorial): sub-picosecond (was ~11" before fix)
vs IMCCE truth, Vega: az 2-17", alt 1-8"
vs IMCCE truth, Polaris: az 0.4-0.6", alt 0.6-1.0"
Polaris (polar distance 0.74°) is essentially at the celestial pole so its
position is dominated by precession and nutation in RA, which are well-corrected.
Vega's residuals reflect the IAU 1980 nutation accuracy floor of libnova.
Files changed
libs/indicore/libastro.cpp- sidereal time fixtest/core/test_libastro.cpp- new teststest/core/CMakeLists.txt- wire up new test executabletest/data/horizontal_golden.json- IMCCE truth data (8 cases)tools/generate_golden_files.py- script to regenerate golden dataTest plan