V 1.7.1 fix: Astro-Werte gegen USNO geprueft, Hoehenkorrektur entfernt
Die Pruefung in 1.7.0 lief gegen selbst geschriebene Referenzen desselben Algorithmus — ein gemeinsamer Denkfehler faellt so nicht auf. Jetzt gegen die Astronomical Applications API des U.S. Naval Observatory (JPL-Ephemeriden, gleiche Grundlage wie der Astronomical Almanac), und dabei zwei Fehler gefunden: - Hoehenkorrektur -2.076*sqrt(547)/60 entfernt. Sie gilt fuer den Blick von einer Erhebung auf einen fernen Meereshorizont; die Station liegt in ringsum aehnlich hohem Gelaende. Sie hat die Zeiten um 5-6 min verschoben, weg von Almanach und USNO. Rest-Abweichung jetzt <= 45 s ueber 365 Tage. - getMoonPhase() leitet die Zyklusposition aus der ekliptikalen Laengen- differenz Mond-Sonne ab statt aus dem Phasenwinkel. Das ist die Definition von Almanach und USNO; der Phasenwinkel laeuft davon ab, sobald der Mond weit vom Knoten steht. Neu-/Vollmond lagen dadurch bis zu 3,8 h daneben, jetzt <= 28 min. Die Viertel waren nie betroffen. Belegt durch astro.test.js gegen ein eingechecktes Fixture (365 Tage plus 50 Phasenereignisse 2026). Der Test geht nicht ins Netz; neu erzeugen laesst er sich mit scripts/fetch-usno-reference.mjs. Testrunner ist node:test, keine neue Abhaengigkeit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
// Holt Referenzwerte vom U.S. Naval Observatory und schreibt sie als Fixture
|
||||
// fuer astro.test.js. Muss nur laufen, wenn man das Referenzjahr wechselt —
|
||||
// der Test selbst geht nie ins Netz.
|
||||
//
|
||||
// node scripts/fetch-usno-reference.mjs [Jahr]
|
||||
//
|
||||
// Quelle: Astronomical Applications API v4 des USNO, https://aa.usno.navy.mil/data/api
|
||||
// Die API rechnet mit denselben JPL-Ephemeriden wie der Astronomical Almanac
|
||||
// und ist damit eine von unserer Implementierung unabhaengige Instanz.
|
||||
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
import { setTimeout as sleep } from 'node:timers/promises'
|
||||
|
||||
const YEAR = Number(process.argv[2] ?? 2026)
|
||||
|
||||
// Station Wetterstation — dieselben Werte wie STATION in App.jsx
|
||||
const LAT = 48 + 52 / 60 + 27 / 3600
|
||||
const LON = 9 + 35 / 60 + 46 / 3600
|
||||
|
||||
const API = 'https://aa.usno.navy.mil/api'
|
||||
const COORDS = `${LAT.toFixed(4)},${LON.toFixed(4)}`
|
||||
|
||||
// Pause zwischen den Requests. Es sind 365 Stueck an einen fremden Server —
|
||||
// nicht draengeln.
|
||||
const THROTTLE_MS = 200
|
||||
|
||||
const iso = d => d.toISOString().slice(0, 10)
|
||||
|
||||
async function getJson(url) {
|
||||
for (let versuch = 1; versuch <= 3; versuch++) {
|
||||
try {
|
||||
const res = await fetch(url, { signal: AbortSignal.timeout(30000) })
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
return await res.json()
|
||||
} catch (err) {
|
||||
if (versuch === 3) throw new Error(`${url}: ${err.message}`)
|
||||
await sleep(1000 * versuch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sonnenauf-/untergang fuer jeden Tag des Jahres, in UTC.
|
||||
//
|
||||
// tz=0&dst=false laesst die API in Weltzeit antworten. Das haelt das Fixture
|
||||
// frei von jeder Sommerzeit-Annahme: der Test vergleicht absolute Zeitpunkte,
|
||||
// die Zeitzone ist allein Sache der Anzeige.
|
||||
async function fetchSonne() {
|
||||
const sonne = {}
|
||||
const tag = new Date(Date.UTC(YEAR, 0, 1))
|
||||
|
||||
while (tag.getUTCFullYear() === YEAR) {
|
||||
const datum = iso(tag)
|
||||
const json = await getJson(
|
||||
`${API}/rstt/oneday?date=${datum}&coords=${COORDS}&tz=0&dst=false`
|
||||
)
|
||||
const daten = json?.properties?.data?.sundata ?? []
|
||||
const zeit = phen => daten.find(e => e.phen === phen)?.time ?? null
|
||||
|
||||
sonne[datum] = [zeit('Rise'), zeit('Set')]
|
||||
|
||||
if (tag.getUTCDate() === 1) console.error(` ${datum} ...`)
|
||||
tag.setUTCDate(tag.getUTCDate() + 1)
|
||||
await sleep(THROTTLE_MS)
|
||||
}
|
||||
return sonne
|
||||
}
|
||||
|
||||
// Alle Hauptphasen des Jahres — ein einziger Request. Die Zeiten sind UTC.
|
||||
async function fetchMondphasen() {
|
||||
const json = await getJson(`${API}/moon/phases/year?year=${YEAR}`)
|
||||
return json.phasedata.map(p => ({
|
||||
phase: p.phase,
|
||||
utc: `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}T${p.time}:00Z`,
|
||||
}))
|
||||
}
|
||||
|
||||
console.error(`Hole USNO-Referenz fuer ${YEAR} (${COORDS}) ...`)
|
||||
|
||||
const [sonne, mondphasen] = [await fetchSonne(), await fetchMondphasen()]
|
||||
|
||||
const fixture = {
|
||||
quelle: 'U.S. Naval Observatory, Astronomical Applications API v4 (https://aa.usno.navy.mil/data/api)',
|
||||
abgerufen: iso(new Date()),
|
||||
hinweis:
|
||||
'Alle Zeiten UTC. Die API rundet auf ganze Minuten — der Test rechnet das ein. '
|
||||
+ 'Auf-/Untergang nach Almanach-Konvention: Meereshorizont, ohne Beobachterhoehe.',
|
||||
jahr: YEAR,
|
||||
station: { lat: LAT, lon: LON },
|
||||
sonne,
|
||||
mondphasen,
|
||||
}
|
||||
|
||||
const ziel = new URL('../src/utils/__fixtures__/usno-reference.json', import.meta.url)
|
||||
await writeFile(ziel, JSON.stringify(fixture, null, 2) + '\n')
|
||||
|
||||
console.error(
|
||||
`Fertig: ${Object.keys(sonne).length} Tage, ${mondphasen.length} Mondphasen -> ${ziel.pathname}`
|
||||
)
|
||||
Reference in New Issue
Block a user