Merge pull request #1350 from rudycelekli/fix/cyclone-movement-knots

fix(cyclones): convert NHC movement speed from mph to knots
This commit is contained in:
Sameh Khamis authored and GitHub committed 2026-10-24 21:39:26 -07:00
commit 2fc9ca8516
4 files changed
+13 -2

No files matched your search

@@ -0,0 +1,3 @@
- Convert NHC cyclone movement speed from miles per hour to knots, so
`movement.speedKt` in cyclone query results is no longer about 15% high
(rudycelekli, #1350).
+2
View File
@@ -417,6 +417,8 @@ than relabeling older geometry. The cone represents forecast center uncertainty,
not storm size or the full hazard area. Successful empty and unavailable states
are distinct. One owned native Cesium data source preserves polygon holes and
geographic seams and releases on disable; forecast animation is not implied.
NHC movement speed is converted from miles per hour to rounded knots by the
proxy; advisory wind intensity is already in knots and is passed through.
Cyclone markers, labels, tracks and cones are hidden beyond the horizon on every map source.
Consult the linked official advisory for safety decisions.
+6 -1
View File
@@ -43,6 +43,11 @@ function number(value, min, max) {
const n = Number(value);
return Number.isFinite(n) && n >= min && n <= max ? n : null;
}
// CurrentStorms.json reports movementSpeed in miles per hour (intensity is in
// knots); convert so `speedKt` means what it says.
function knotsFromMph(mph) {
return mph === null ? null : Math.round(mph * 0.868976);
}
// NHC stamps an advisory with its nominal time (e.g. 03:00Z) and publishes it
// up to about half an hour before; allow that, but not a clock far ahead.
const EARLY_ADVISORY_MS = 90 * 60_000;
@@ -120,7 +125,7 @@ export function parseCycloneStatus(payload, now = Date.now()) {
pressureHpa: number(raw.pressure, 800, 1100),
movement: {
directionDegrees: number(raw.movementDir, 0, 360),
speedKt: number(raw.movementSpeed, 0, 200),
speedKt: knotsFromMph(number(raw.movementSpeed, 0, 200)),
},
advisoryUrl: officialLink(forecast.url),
outlookUrl: raw.id.startsWith('al')
+2 -1
View File
@@ -115,7 +115,8 @@ test('status retains official clocks, knots, source links and finite current pos
assert.equal(storm.issuedAt, TIME);
assert.equal(storm.positionAt, TIME);
assert.deepEqual(storm.position, { longitude: -125.8, latitude: 15.5 });
assert.deepEqual(storm.movement, { directionDegrees: 255, speedKt: 12 });
// NHC publishes movementSpeed in mph: 12 mph is 10 kt.
assert.deepEqual(storm.movement, { directionDegrees: 255, speedKt: 10 });
assert.equal(storm.windKt, 25);
assert.equal(storm.pressureHpa, 1006);
assert.match(storm.advisoryUrl, /^https:\/\/www\.nhc\.noaa\.gov\/text\//);