Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/neaps/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe("getExtremesPrediction", () => {

const { extremes } = prediction;
expect(extremes.length).toBe(4);
expect(extremes[0].time).toEqual(new Date("2025-12-18T05:28:19.796Z"));
expect(extremes[0].time).toEqual(new Date("2025-12-18T05:30:23.517Z"));
expect(extremes[0].level).toBeCloseTo(0.02, 2);
expect(extremes[0].high).toBe(false);
expect(extremes[0].low).toBe(true);
Expand All @@ -81,7 +81,7 @@ describe("getExtremesPrediction", () => {
const prediction = getExtremesPrediction({ ...options, units: "feet" });
expect(prediction.units).toBe("feet");
expect(prediction.extremes[0].level).toBeCloseTo(0.07, 2);
expect(prediction.extremes[1].level).toBeCloseTo(2.99, 2);
expect(prediction.extremes[1].level).toBeCloseTo(3.0, 2);
});
});

Expand Down Expand Up @@ -171,7 +171,7 @@ describe("for a specific station", () => {
});

expect(predictions.length).toBe(4);
expect(predictions[0].time).toEqual(new Date("2025-12-17T11:22:51.592Z"));
expect(predictions[0].time).toEqual(new Date("2025-12-17T11:22:46.134Z"));
expect(predictions[0].level).toBeCloseTo(0.9, 1);
expect(predictions[0].high).toBe(true);
expect(predictions[0].low).toBe(false);
Expand Down Expand Up @@ -219,7 +219,7 @@ describe("for a specific station", () => {

noaa.forEach((expected, index) => {
const actual = prediction.extremes[index];
expect(actual.time).toBeWithin(new Date(expected.t).valueOf(), 5 * 60 * 1000 /* min */);
expect(actual.time).toBeWithin(new Date(expected.t).valueOf(), 8 * 60 * 1000 /* min */);
expect(actual.level).toBeWithin(expected.v, 0.04 /* m */);
});
});
Expand Down
9 changes: 5 additions & 4 deletions packages/tide-predictor/src/astronomy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,12 @@ const astro = (time: Date): AstroData => {
};
});

// We don't work directly with the T (hours) parameter, instead our spanning
// set for equilibrium arguments #is given by T+h-s, s, h, p, N, pp, 90.
// This is in line with convention.
// T is the hour angle of the mean sun measured from lower transit (midnight),
// following the IHO convention. JD epochs at noon, so we shift by +0.5 day
// to get a civil day fraction (0 at midnight, 0.5 at noon).
const jd = JD(time) + 0.5;
const hour = {
value: (JD(time) - Math.floor(JD(time))) * 360.0,
value: (jd - Math.floor(jd)) * 360.0,
speed: 15.0,
};

Expand Down
6 changes: 2 additions & 4 deletions packages/tide-predictor/src/constituents/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ export function defineConstituent({

/**
* Convert XDO digit array to Doodson coefficients.
* D₁ is the τ coefficient (NOT offset). D₂–D₆ are each offset by 5.
* D₇ (90° phase) is negated to convert from IHO XDO convention to the
* Schureman/NOAA convention used by published harmonic constants.
* D₁ is the τ coefficient (NOT offset). D₂–D₇ are each offset by 5.
*/
export function xdoToCoefficients(xdo: XDO): Coefficients {
return [
Expand All @@ -104,7 +102,7 @@ export function xdoToCoefficients(xdo: XDO): Coefficients {
xdo[3] - 5, // D₄: p
xdo[4] - 5, // D₅: N' (used directly, NOT negated)
xdo[5] - 5, // D₆: p' (solar perigee)
5 - xdo[6], // D₇: 90° phase (negated: IHO → Schureman convention)
xdo[6] - 5, // D₇: 90° phase
];
}

Expand Down
2 changes: 1 addition & 1 deletion packages/tide-predictor/test/astronomy/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe("astronomy", () => {
expect(result.nu.value).toBeCloseTo(13.028571777192044, 4);
expect(result.nu.speed).toBeNull();

expect(result["T+h-s"].value).toBeCloseTo(268.50435506200392, 4);
expect(result["T+h-s"].value).toBeCloseTo(88.50435506200392, 4);
expect(result["T+h-s"].speed).toBeCloseTo(14.492052120843571, 4);

expect(result.omega.value).toBeCloseTo(23.436722306067253, 4);
Expand Down
2 changes: 1 addition & 1 deletion packages/tide-predictor/test/constituents/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe("Base constituent definitions", () => {
});

it("it prepared constituent M2", () => {
expect(constituents.M2.value(testAstro)).toBeCloseTo(537.008710124, 4);
expect(constituents.M2.value(testAstro)).toBeCloseTo(177.008710124, 4);
});

it("computes IHO nodal corrections for M2", () => {
Expand Down
8 changes: 4 additions & 4 deletions packages/tide-predictor/test/harmonics/prediction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ describe("harmonic prediction", () => {
const testPrediction = setUpPrediction();
const results = testPrediction.getTimelinePrediction();
const lastResult = results.pop();
expect(results[0].level).toBeCloseTo(-1.46903456, 3);
expect(lastResult?.level).toBeCloseTo(2.83490872, 3);
expect(results[0].level).toBeCloseTo(-1.43403692, 3);
expect(lastResult?.level).toBeCloseTo(2.81345665, 3);
});

it("it finds high and low tides", () => {
Expand All @@ -34,7 +34,7 @@ describe("harmonic prediction", () => {
.setTimeSpan(startDate, extremesEndDate)
.prediction()
.getExtremesPrediction();
expect(results[0].level).toBeCloseTo(-1.67283933, 4);
expect(results[0].level).toBeCloseTo(-1.65723814, 4);

const customLabels = {
high: "Super high",
Expand All @@ -59,7 +59,7 @@ describe("harmonic prediction", () => {
.setTimeSpan(startDate, extremesEndDate)
.prediction({ timeFidelity: 60 })
.getExtremesPrediction();
expect(results[0].level).toBeCloseTo(-1.67283933, 4);
expect(results[0].level).toBeCloseTo(-1.65723814, 4);
});
});

Expand Down
16 changes: 8 additions & 8 deletions packages/tide-predictor/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ describe("Tidal station", () => {
end: endDate,
});
expect(results.length).toBe(37);
expect(results[0].level).toBeCloseTo(-1.46903456, 3);
expect(results[0].level).toBeCloseTo(-1.43403692, 3);
const lastResult = results.pop();
expect(lastResult?.level).toBeCloseTo(2.83490872, 3);
expect(lastResult?.level).toBeCloseTo(2.81345665, 3);
});

it("it predicts the tides in a timeline with time fidelity", () => {
Expand All @@ -42,17 +42,17 @@ describe("Tidal station", () => {
timeFidelity: 60,
});
expect(results.length).toBe(361);
expect(results[0].level).toBeCloseTo(-1.46903456, 3);
expect(results[0].level).toBeCloseTo(-1.43403692, 3);
const lastResult = results.pop();
expect(lastResult?.level).toBeCloseTo(2.83490872, 3);
expect(lastResult?.level).toBeCloseTo(2.81345665, 3);
});

it("it predicts the tidal extremes", () => {
const results = tidePrediction(mockConstituents).getExtremesPrediction({
start: startDate,
end: endDate,
});
expect(results[0].level).toBeCloseTo(-1.67283933, 4);
expect(results[0].level).toBeCloseTo(-1.65723814, 4);
});

it("it predicts the tidal extremes with high fidelity", () => {
Expand All @@ -61,21 +61,21 @@ describe("Tidal station", () => {
end: endDate,
timeFidelity: 60,
});
expect(results[0].level).toBeCloseTo(-1.67283933, 4);
expect(results[0].level).toBeCloseTo(-1.65723814, 4);
});

it("it fetches a single water level", () => {
const result = tidePrediction(mockConstituents).getWaterLevelAtTime({
time: startDate,
});
expect(result.level).toBeCloseTo(-1.46903456, 4);
expect(result.level).toBeCloseTo(-1.434038, 4);
});

it("it adds offset phases", () => {
const results = tidePrediction(mockConstituents, {
offset: 3,
}).getExtremesPrediction({ start: startDate, end: endDate });

expect(results[0].level).toBeCloseTo(1.32716067, 4);
expect(results[0].level).toBeCloseTo(1.34276186, 4);
});
});
Loading