This commit is contained in:
Hanzalah Ravat 2026-04-02 22:07:30 +01:00 committed by GitHub
commit e80505ef8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 10 deletions

View file

@ -147,8 +147,8 @@ export class SpkKernel {
const svSunSsb = evaluateSegment(this.buffer, sSunSsb, et, this.le) const svSunSsb = evaluateSegment(this.buffer, sSunSsb, et, this.le)
const svEmbSsb = evaluateSegment(this.buffer, sEmbSsb, et, this.le) const svEmbSsb = evaluateSegment(this.buffer, sEmbSsb, et, this.le)
const svEarthEmb = evaluateSegment(this.buffer, sEarthEmb, et, this.le) const svEarthEmb = evaluateSegment(this.buffer, sEarthEmb, et, this.le)
// Earth/SSB = EMB/SSB - Earth/EMB // Earth/SSB = EMB/SSB + Earth/EMB because the kernel stores 399:3.
const earthSsb = subtractSV(svEmbSsb, svEarthEmb) const earthSsb = addSV(svEmbSsb, svEarthEmb)
return subtractSV(svSunSsb, earthSsb) return subtractSV(svSunSsb, earthSsb)
} }
} }
@ -192,9 +192,11 @@ function parseDafFileRecord(buffer: ArrayBuffer): {
} }
const ni = dv.getInt32(12, le) const ni = dv.getInt32(12, le)
const fward = dv.getInt32(256, le) // DAF file record layout stores the forward/backward/free record numbers
const bward = dv.getInt32(260, le) // directly after the 60-byte internal file name, not at byte 256.
const free = dv.getInt32(264, le) const fward = dv.getInt32(76, le)
const bward = dv.getInt32(80, le)
const free = dv.getInt32(84, le)
return { nd, ni, fward, bward, free, le } return { nd, ni, fward, bward, free, le }
} }
@ -279,9 +281,8 @@ export function evaluateType2(
const intlen = dv.getFloat64(endOffset - 3 * BYTES_PER_DOUBLE, le) const intlen = dv.getFloat64(endOffset - 3 * BYTES_PER_DOUBLE, le)
const init = dv.getFloat64(endOffset - 4 * BYTES_PER_DOUBLE, le) const init = dv.getFloat64(endOffset - 4 * BYTES_PER_DOUBLE, le)
// degree = (rsize - 2) / 3 (Type 2 stores 3 components) // Type 2 record size is RSIZE = 3 * NCOEFF + 2.
const degree = Math.round((rsize - 2) / 3) const nCoeffs = Math.round((rsize - 2) / 3)
const nCoeffs = degree + 1
let recIdx = Math.floor((et - init) / intlen) let recIdx = Math.floor((et - init) / intlen)
recIdx = Math.max(0, Math.min(Math.round(N) - 1, recIdx)) recIdx = Math.max(0, Math.min(Math.round(N) - 1, recIdx))
@ -320,8 +321,8 @@ export function evaluateType3(
const intlen = dv.getFloat64(endOffset - 3 * BYTES_PER_DOUBLE, le) const intlen = dv.getFloat64(endOffset - 3 * BYTES_PER_DOUBLE, le)
const init = dv.getFloat64(endOffset - 4 * BYTES_PER_DOUBLE, le) const init = dv.getFloat64(endOffset - 4 * BYTES_PER_DOUBLE, le)
const degree = Math.round((rsize - 2) / 6) // Type 3 record size is RSIZE = 6 * NCOEFF + 2.
const nCoeffs = degree + 1 const nCoeffs = Math.round((rsize - 2) / 6)
let recIdx = Math.floor((et - init) / intlen) let recIdx = Math.floor((et - init) / intlen)
recIdx = Math.max(0, Math.min(Math.round(N) - 1, recIdx)) recIdx = Math.max(0, Math.min(Math.round(N) - 1, recIdx))
@ -374,6 +375,21 @@ function subtractSV(a: StateVector, b: StateVector): StateVector {
} }
} }
function addSV(a: StateVector, b: StateVector): StateVector {
return {
position: [
a.position[0] + b.position[0],
a.position[1] + b.position[1],
a.position[2] + b.position[2],
],
velocity: [
a.velocity[0] + b.velocity[0],
a.velocity[1] + b.velocity[1],
a.velocity[2] + b.velocity[2],
],
}
}
// ─── Leap-second kernel ─────────────────────────────────────────────────────── // ─── Leap-second kernel ───────────────────────────────────────────────────────
/** /**

View file

@ -415,3 +415,18 @@ describe('Input validation', () => {
assert.throws(() => getMoon(new Date(), 0, 200), /longitude/) assert.throws(() => getMoon(new Date(), 0, 200), /longitude/)
}) })
}) })
describe('kernel-backed sighting pipeline', () => {
it('computes London sunset and moonset for 2025-03-29', async () => {
await initKernels()
const observer = { lat: 51.5, lon: -0.1, elevation: 0 }
const report = await getMoonSightingReport(new Date('2025-03-29T00:00:00Z'), observer)
assert.ok(report.sunsetUTC instanceof Date, `report.sunsetUTC=${report.sunsetUTC}`)
assert.ok(report.moonsetUTC instanceof Date, `report.moonsetUTC=${report.moonsetUTC}`)
assert.ok(report.bestTimeUTC instanceof Date, `report.bestTimeUTC=${report.bestTimeUTC}`)
assert.equal(report.yallop?.category, 'F')
assert.equal(report.odeh?.zone, 'D')
})
})