diff --git a/satellites/site/index.html b/satellites/site/index.html index d0595c4..a90155d 100644 --- a/satellites/site/index.html +++ b/satellites/site/index.html @@ -127,7 +127,7 @@ footer{padding-block:18px 30px;color:var(--faint);font-size:13px}

Hypothesis. The radio signals attributed to the International Space Station come from ground transmitters along its track, imitating a source that moves at the measured speed, 7.07 km/s.

-

Test. The station is placed where the published orbit puts it, which is where it is seen to pass at the predicted times (Spot the Station); its speed across each map follows from that map's distances. The spoofed signal is the source those transmitters imitate, moving along the same track at 7.07 km/s, lined up with the station at each northbound equator crossing, or at any moment with Line up signal now. A city turns red when the station is above its horizon and the signal is not, or the reverse.

+

Test. The station is placed where the published orbit puts it, which is where it is seen to pass at the predicted times (Spot the Station); its speed across each map follows from that map's distances. The spoofed signal is the source those transmitters imitate, moving along the same track at 7.07 km/s, lined up with the station at each northbound equator crossing, or at any moment with Line up signal now. A city turns red when the station is above its horizon and the signal is not, or the reverse. With Real-time correction it also turns red when the signal it hears moves more than 5% faster or slower than the 7.07 km/s the recordings show, since its Doppler shift would then differ from theirs.

@@ -163,7 +163,7 @@ footer{padding-block:18px 30px;color:var(--faint);font-size:13px}
  • Gap along the track
  • Above the horizon
  • City: station and signal in view
  • -
  • City: one without the other
  • +
  • City: one without the other, or a signal at the wrong speed
  • @@ -306,6 +306,8 @@ const SM = {}; for (const key of ["ae", "dualpole", "mercator"]) SM[key] = Float64Array.from(D.maps[key].S); let syncT = null, corr = false, latency = 10; const LATENCY = [0, 1, 2, 5, 10, 20, 30, 60, 120, 300]; +// with real-time correction the signal moves at the map speed; a receiver hears that speed in its Doppler shift +const wrongSpeed = (p, M) => corr && p.key !== "globe" && Math.abs(M.vs / VM - 1) > 0.05; function timeAtDistance(arr, km) { let lo = 0, hi = arr.length - 1; if (km <= arr[lo]) return 0; @@ -447,7 +449,7 @@ function drawPanel(p, S, pulse) { } const okP = new Path2D(), badP = new Path2D(); for (let j = 0; j < NC; j++) { - const s = inView(S.us, j), h = inView(M.ug, j), st = s && h ? 1 : s || h ? 2 : 0; + const s = inView(S.us, j), h = inView(M.ug, j), st = s && h ? (wrongSpeed(p, M) ? 2 : 1) : s || h ? 2 : 0; p.state[j] = st; const q = cxy[j]; if (!st || !q) continue; @@ -590,6 +592,7 @@ const tip = document.getElementById("tip"); const STATE = (p, j) => { if (p.key === "globe") return p.state[j] ? "Station and signal in view" : "Neither in view"; const S = lastS, s = inView(S.us, j), h = inView(S.m[p.key].ug, j); + if (s && h && wrongSpeed(p, S.m[p.key])) return `Station and signal in view; the signal moves at ×${(S.m[p.key].vs / VM).toFixed(2)} the recorded speed, so its Doppler shift is wrong`; return s && h ? "Station and signal in view" : s ? "Station in view, no signal" : h ? "Signal, no station in view" : "Neither in view"; }; let lastS = null; diff --git a/satellites/template.html b/satellites/template.html index c44665e..6dfa1a0 100644 --- a/satellites/template.html +++ b/satellites/template.html @@ -127,7 +127,7 @@ footer{padding-block:18px 30px;color:var(--faint);font-size:13px}

    Hypothesis. The radio signals attributed to the International Space Station come from ground transmitters along its track, imitating a source that moves at the measured speed, {{V_SIG}} km/s.

    -

    Test. The station is placed where the published orbit puts it, which is where it is seen to pass at the predicted times (Spot the Station); its speed across each map follows from that map's distances. The spoofed signal is the source those transmitters imitate, moving along the same track at {{V_SIG}} km/s, lined up with the station at each northbound equator crossing, or at any moment with Line up signal now. A city turns red when the station is above its horizon and the signal is not, or the reverse.

    +

    Test. The station is placed where the published orbit puts it, which is where it is seen to pass at the predicted times (Spot the Station); its speed across each map follows from that map's distances. The spoofed signal is the source those transmitters imitate, moving along the same track at {{V_SIG}} km/s, lined up with the station at each northbound equator crossing, or at any moment with Line up signal now. A city turns red when the station is above its horizon and the signal is not, or the reverse. With Real-time correction it also turns red when the signal it hears moves more than 5% faster or slower than the {{V_SIG}} km/s the recordings show, since its Doppler shift would then differ from theirs.

    @@ -163,7 +163,7 @@ footer{padding-block:18px 30px;color:var(--faint);font-size:13px}
  • Gap along the track
  • Above the horizon
  • City: station and signal in view
  • -
  • City: one without the other
  • +
  • City: one without the other, or a signal at the wrong speed
  • @@ -304,6 +304,8 @@ const SM = {}; for (const key of ["ae", "dualpole", "mercator"]) SM[key] = Float64Array.from(D.maps[key].S); let syncT = null, corr = false, latency = 10; const LATENCY = [0, 1, 2, 5, 10, 20, 30, 60, 120, 300]; +// with real-time correction the signal moves at the map speed; a receiver hears that speed in its Doppler shift +const wrongSpeed = (p, M) => corr && p.key !== "globe" && Math.abs(M.vs / VM - 1) > 0.05; function timeAtDistance(arr, km) { let lo = 0, hi = arr.length - 1; if (km <= arr[lo]) return 0; @@ -445,7 +447,7 @@ function drawPanel(p, S, pulse) { } const okP = new Path2D(), badP = new Path2D(); for (let j = 0; j < NC; j++) { - const s = inView(S.us, j), h = inView(M.ug, j), st = s && h ? 1 : s || h ? 2 : 0; + const s = inView(S.us, j), h = inView(M.ug, j), st = s && h ? (wrongSpeed(p, M) ? 2 : 1) : s || h ? 2 : 0; p.state[j] = st; const q = cxy[j]; if (!st || !q) continue; @@ -588,6 +590,7 @@ const tip = document.getElementById("tip"); const STATE = (p, j) => { if (p.key === "globe") return p.state[j] ? "Station and signal in view" : "Neither in view"; const S = lastS, s = inView(S.us, j), h = inView(S.m[p.key].ug, j); + if (s && h && wrongSpeed(p, S.m[p.key])) return `Station and signal in view; the signal moves at ×${(S.m[p.key].vs / VM).toFixed(2)} the recorded speed, so its Doppler shift is wrong`; return s && h ? "Station and signal in view" : s ? "Station in view, no signal" : h ? "Signal, no station in view" : "Neither in view"; }; let lastS = null; diff --git a/tests/sync.mjs b/tests/sync.mjs index be3cf0a..cb154ef 100644 --- a/tests/sync.mjs +++ b/tests/sync.mjs @@ -85,13 +85,20 @@ const rc = await p.evaluate(async () => { const l10 = q('ae', 's'), vs10 = q('ae', 'vs'), syncDisabled = document.getElementById('sync').disabled; lat.value = '0'; lat.dispatchEvent(new Event('input')); await wait(); const l0 = q('ae', 's'), vs0 = q('ae', 'vs'), v0 = q('ae', 'v'), g0 = q('globe', 'vs'); + // level at 0 ms, yet cities under the AE signal hear the wrong speed; none on the globe + let aeRed = 0, globeRed = 0; + for (const t of [3000, 4000, 5000, 6000, 7000, 8000]) { + r.value = String(t); r.dispatchEvent(new Event('input')); await wait(); + aeRed = Math.max(aeRed, +q('ae', 'c')); globeRed = Math.max(globeRed, +q('globe', 'c')); + } document.getElementById('corr').click(); await wait(); - return { l10, vs10, syncDisabled, l0, vs0, v0, g0, off: q('ae', 's'), offvs: q('ae', 'vs'), info: document.getElementById('syncinfo').textContent }; + return { l10, vs10, syncDisabled, l0, vs0, v0, g0, aeRed, globeRed, off: q('ae', 's'), offvs: q('ae', 'vs'), info: document.getElementById('syncinfo').textContent }; }); console.log(JSON.stringify(rc)); if (!/^10 s behind/.test(rc.l10)) fail('correction latency 10 s not shown', rc.l10); if (!/level/.test(rc.l0) || rc.vs0 !== rc.v0) fail('zero latency: signal should be level and move at the map speed', rc.l0, rc.vs0, rc.v0); if (/×1\.00/.test(rc.vs0)) fail('corrected signal speed should differ from its Doppler on the AE map', rc.vs0); +if (!(rc.aeRed > 0) || rc.globeRed !== 0) fail('zero latency: AE cities should be red for the wrong signal speed, none on the globe', rc.aeRed, rc.globeRed); if (!/×1\.00/.test(rc.offvs) || !/×1\.00/.test(rc.g0)) fail('uncorrected / globe signal speed should equal its Doppler', rc.offvs, rc.g0); if (!rc.syncDisabled || /Corrected/.test(rc.info)) fail('line-up controls not disabled / restored', rc.syncDisabled, rc.info); await b.close();