Stabilize satellite live telemetry state

This commit is contained in:
James Smith
2026-03-19 21:09:03 +00:00
parent a8f73f9a73
commit 51b332f4cf
2 changed files with 84 additions and 44 deletions

View File

@@ -643,11 +643,11 @@ def get_satellite_position():
'visible': bool(alt.degrees > 0) 'visible': bool(alt.degrees > 0)
} }
if include_track: if include_track:
orbit_track = [] orbit_track = []
for minutes_offset in range(-45, 46, 1): for minutes_offset in range(-45, 46, 1):
t_point = ts.utc(now_dt + timedelta(minutes=minutes_offset)) t_point = ts.utc(now_dt + timedelta(minutes=minutes_offset))
try: try:
geo = satellite.at(t_point) geo = satellite.at(t_point)
sp = wgs84.subpoint(geo) sp = wgs84.subpoint(geo)
orbit_track.append({ orbit_track.append({
@@ -655,12 +655,13 @@ def get_satellite_position():
'lon': float(sp.longitude.degrees), 'lon': float(sp.longitude.degrees),
'past': minutes_offset < 0 'past': minutes_offset < 0
}) })
except Exception: except Exception:
continue continue
pos_data['track'] = orbit_track pos_data['track'] = orbit_track
pos_data['groundTrack'] = orbit_track
positions.append(pos_data)
positions.append(pos_data)
except Exception: except Exception:
continue continue

View File

@@ -1020,11 +1020,37 @@
return transmitterCache.get(String(noradId)) || null; return transmitterCache.get(String(noradId)) || null;
} }
function _isFiniteNumber(value) {
return Number.isFinite(value);
}
function normalizeLivePosition(pos, previous = latestLivePosition) {
if (!pos) return null;
const merged = {
...(previous || {}),
...pos,
};
const liveTrack = Array.isArray(pos.groundTrack)
? pos.groundTrack
: (Array.isArray(pos.track)
? pos.track
: (Array.isArray(previous?.groundTrack)
? previous.groundTrack
: (Array.isArray(previous?.track) ? previous.track : null)));
if (liveTrack) {
merged.groundTrack = liveTrack;
merged.track = liveTrack;
}
return merged;
}
function applyTelemetryPosition(pos, options = {}) { function applyTelemetryPosition(pos, options = {}) {
const { updateVisible = false, noradId = selectedSatellite } = options; const { updateVisible = false, noradId = selectedSatellite } = options;
if (!pos) return; if (!pos) return;
latestLivePosition = pos; const normalized = normalizeLivePosition(pos);
cacheLivePosition(noradId, pos); if (!normalized) return;
latestLivePosition = normalized;
cacheLivePosition(noradId, normalized);
const telLat = document.getElementById('telLat'); const telLat = document.getElementById('telLat');
const telLon = document.getElementById('telLon'); const telLon = document.getElementById('telLon');
@@ -1032,26 +1058,26 @@
const telEl = document.getElementById('telEl'); const telEl = document.getElementById('telEl');
const telAz = document.getElementById('telAz'); const telAz = document.getElementById('telAz');
const telDist = document.getElementById('telDist'); const telDist = document.getElementById('telDist');
if (telLat) telLat.textContent = (pos.lat ?? 0).toFixed(4) + '°'; if (telLat && _isFiniteNumber(normalized.lat)) telLat.textContent = normalized.lat.toFixed(4) + '°';
if (telLon) telLon.textContent = (pos.lon ?? 0).toFixed(4) + '°'; if (telLon && _isFiniteNumber(normalized.lon)) telLon.textContent = normalized.lon.toFixed(4) + '°';
if (telAlt) telAlt.textContent = (pos.altitude ?? pos.alt ?? 0).toFixed(0) + ' km'; if (telAlt && _isFiniteNumber(normalized.altitude ?? normalized.alt)) telAlt.textContent = (normalized.altitude ?? normalized.alt).toFixed(0) + ' km';
if (telEl) telEl.textContent = (pos.elevation ?? pos.el ?? 0).toFixed(1) + '°'; if (telEl && _isFiniteNumber(normalized.elevation ?? normalized.el)) telEl.textContent = (normalized.elevation ?? normalized.el).toFixed(1) + '°';
if (telAz) telAz.textContent = (pos.azimuth ?? pos.az ?? 0).toFixed(1) + '°'; if (telAz && _isFiniteNumber(normalized.azimuth ?? normalized.az)) telAz.textContent = (normalized.azimuth ?? normalized.az).toFixed(1) + '°';
if (telDist) telDist.textContent = (pos.distance ?? pos.dist ?? 0).toFixed(0) + ' km'; if (telDist && _isFiniteNumber(normalized.distance ?? normalized.dist)) telDist.textContent = (normalized.distance ?? normalized.dist).toFixed(0) + ' km';
if (selectedPass == null && (pos.azimuth ?? pos.az) != null && (pos.elevation ?? pos.el) != null) { if (selectedPass == null && _isFiniteNumber(normalized.azimuth ?? normalized.az) && _isFiniteNumber(normalized.elevation ?? normalized.el)) {
drawPolarPlotWithPosition( drawPolarPlotWithPosition(
pos.azimuth ?? pos.az, normalized.azimuth ?? normalized.az,
pos.elevation ?? pos.el, normalized.elevation ?? normalized.el,
satellites[selectedSatellite]?.color || '#00d4ff' satellites[selectedSatellite]?.color || '#00d4ff'
); );
} }
renderMapTrackOverlays(); renderMapTrackOverlays({ refreshPass: false, refreshLive: true });
updateMapTrackSummary(); updateMapTrackSummary();
if (updateVisible) { if (updateVisible) {
const visEl = document.getElementById('statVisible'); const visEl = document.getElementById('statVisible');
if (visEl && Number.isFinite(pos.visibleCount)) visEl.textContent = String(pos.visibleCount); if (visEl && Number.isFinite(normalized.visibleCount)) visEl.textContent = String(normalized.visibleCount);
} }
} }
@@ -1125,10 +1151,16 @@
} else if (newSats[25544]) { } else if (newSats[25544]) {
select.value = '25544'; select.value = '25544';
} }
selectedSatellite = parseInt(select.value); const nextSelectedSatellite = parseInt(select.value, 10);
_satelliteSelectionRequestToken += 1; const selectionChanged = nextSelectedSatellite !== selectedSatellite;
selectedSatellite = nextSelectedSatellite;
if (selectionChanged || forceDataRefresh) {
_satelliteSelectionRequestToken += 1;
}
_lastSatelliteCatalogRefresh = Date.now(); _lastSatelliteCatalogRefresh = Date.now();
clearTelemetry(); if (selectionChanged) {
clearTelemetry();
}
restoreSatelliteStateFromCache(selectedSatellite); restoreSatelliteStateFromCache(selectedSatellite);
updateMissionDrawerInfo(); updateMissionDrawerInfo();
const hasCachedPasses = !!getCachedPasses(selectedSatellite)?.passes?.length; const hasCachedPasses = !!getCachedPasses(selectedSatellite)?.passes?.length;
@@ -1525,10 +1557,13 @@
const pass = getSelectedPass(); const pass = getSelectedPass();
const live = latestLivePosition; const live = latestLivePosition;
const nextTime = pass?.aosTime ? new Date(pass.aosTime).toISOString().substring(11, 16) + ' UTC' : null; const nextTime = pass?.aosTime ? new Date(pass.aosTime).toISOString().substring(11, 16) + ' UTC' : null;
const liveElevation = _isFiniteNumber(live?.elevation ?? live?.el) ? (live.elevation ?? live.el).toFixed(1) + '°' : '--.-°';
const liveLat = _isFiniteNumber(live?.lat) ? live.lat.toFixed(2) + '°' : '--.--°';
const liveLon = _isFiniteNumber(live?.lon) ? live.lon.toFixed(2) + '°' : '--.--°';
if (mapViewMode === 'both' && pass && live) { if (mapViewMode === 'both' && pass && live) {
primary.textContent = `${pass.satellite} pass corridor plus live orbit context`; primary.textContent = `${pass.satellite} pass corridor plus live orbit context`;
secondary.textContent = `Next rise ${nextTime || '--:-- UTC'} · peak ${pass.maxEl ?? '--'}° · current elevation ${(live.elevation ?? 0).toFixed(1)}°`; secondary.textContent = `Next rise ${nextTime || '--:-- UTC'} · peak ${pass.maxEl ?? '--'}° · current elevation ${liveElevation}`;
return; return;
} }
if (mapViewMode === 'pass' && pass) { if (mapViewMode === 'pass' && pass) {
@@ -1538,7 +1573,7 @@
} }
if (mapViewMode === 'live' && live) { if (mapViewMode === 'live' && live) {
primary.textContent = `${satellites[selectedSatellite]?.name || 'Selected satellite'} live orbit track`; primary.textContent = `${satellites[selectedSatellite]?.name || 'Selected satellite'} live orbit track`;
secondary.textContent = `Subpoint ${(live.lat ?? 0).toFixed(2)}°, ${(live.lon ?? 0).toFixed(2)}° · elevation ${(live.elevation ?? 0).toFixed(1)}°`; secondary.textContent = `Subpoint ${liveLat}, ${liveLon} · elevation ${liveElevation}`;
return; return;
} }
if (pass) { if (pass) {
@@ -1557,10 +1592,10 @@
function renderMapTrackOverlays(options = {}) { function renderMapTrackOverlays(options = {}) {
if (!groundMap) return; if (!groundMap) return;
const { fit = false } = options; const { fit = false, refreshPass = true, refreshLive = true } = options;
if (trackLine) { groundMap.removeLayer(trackLine); trackLine = null; } if (refreshPass && trackLine) { groundMap.removeLayer(trackLine); trackLine = null; }
if (orbitTrack) { groundMap.removeLayer(orbitTrack); orbitTrack = null; } if (refreshLive && orbitTrack) { groundMap.removeLayer(orbitTrack); orbitTrack = null; }
if (satMarker) { groundMap.removeLayer(satMarker); satMarker = null; } if (satMarker) { groundMap.removeLayer(satMarker); satMarker = null; }
const bounds = []; const bounds = [];
@@ -1568,22 +1603,29 @@
const showPass = mapViewMode !== 'live'; const showPass = mapViewMode !== 'live';
const showLive = mapViewMode !== 'pass'; const showLive = mapViewMode !== 'pass';
if (showPass && pass) { if (showPass && pass && (refreshPass || !trackLine)) {
const renderedPass = renderPassTrackLayer(pass); const renderedPass = renderPassTrackLayer(pass);
if (renderedPass) { if (renderedPass) {
trackLine = renderedPass.layer; trackLine = renderedPass.layer;
trackLine.addTo(groundMap); trackLine.addTo(groundMap);
bounds.push(...renderedPass.bounds); bounds.push(...renderedPass.bounds);
} }
} else if (trackLine) {
bounds.push(...(getSelectedPass()?.groundTrack || []).map(p => [p.lat, p.lon]));
} }
if (showLive && latestLivePosition) { if (showLive && latestLivePosition && (refreshLive || !orbitTrack)) {
const renderedLive = renderLiveOrbitLayer(latestLivePosition); const renderedLive = renderLiveOrbitLayer(latestLivePosition);
if (renderedLive) { if (renderedLive) {
orbitTrack = renderedLive.layer; orbitTrack = renderedLive.layer;
orbitTrack.addTo(groundMap); orbitTrack.addTo(groundMap);
bounds.push(...renderedLive.bounds); bounds.push(...renderedLive.bounds);
} }
} else if (orbitTrack) {
const liveTrack = Array.isArray(latestLivePosition?.groundTrack)
? latestLivePosition.groundTrack
: (Array.isArray(latestLivePosition?.track) ? latestLivePosition.track : []);
bounds.push(...liveTrack.map(p => [p.lat, p.lon]));
} }
const satColor = satellites[selectedSatellite]?.color || '#00d4ff'; const satColor = satellites[selectedSatellite]?.color || '#00d4ff';
@@ -1696,12 +1738,12 @@
_pageTearingDown = false; _pageTearingDown = false;
_satelliteSelectionRequestToken += 1; _satelliteSelectionRequestToken += 1;
renderPacketPanels(); renderPacketPanels();
loadTrackedSatelliteCatalog();
loadReceiverDevices();
loadDashboardSatellites();
setupEmbeddedMode(); setupEmbeddedMode();
const usedShared = applySharedObserverLocation(); const usedShared = applySharedObserverLocation();
initGroundMap(); initGroundMap();
loadTrackedSatelliteCatalog();
loadReceiverDevices();
loadDashboardSatellites();
updateClock(); updateClock();
_clockTimer = setInterval(updateClock, 1000); _clockTimer = setInterval(updateClock, 1000);
_countdownTimer = setInterval(updateCountdown, 1000); _countdownTimer = setInterval(updateCountdown, 1000);
@@ -1712,9 +1754,6 @@
} }
startTelemetryPolling(); startTelemetryPolling();
loadAgents(); loadAgents();
calculatePasses(selectedSatellite, _satelliteSelectionRequestToken);
loadTransmitters(selectedSatellite, _satelliteSelectionRequestToken);
fetchCurrentTelemetry(selectedSatellite, _satelliteSelectionRequestToken);
scheduleDashboardDataRetry(3500); scheduleDashboardDataRetry(3500);
if (!usedShared) { if (!usedShared) {
getLocation(); getLocation();
@@ -2358,10 +2397,10 @@
if (telLat) telLat.textContent = Number.isFinite(pos.lat) ? pos.lat.toFixed(4) + '°' : '---.----'; if (telLat) telLat.textContent = Number.isFinite(pos.lat) ? pos.lat.toFixed(4) + '°' : '---.----';
if (telLon) telLon.textContent = Number.isFinite(pos.lon) ? pos.lon.toFixed(4) + '°' : '---.----'; if (telLon) telLon.textContent = Number.isFinite(pos.lon) ? pos.lon.toFixed(4) + '°' : '---.----';
if (telAlt) telAlt.textContent = Number.isFinite(pos.alt) ? pos.alt.toFixed(0) + ' km' : '--- km'; if (telAlt && Number.isFinite(pos.alt)) telAlt.textContent = pos.alt.toFixed(0) + ' km';
if (telEl) telEl.textContent = Number.isFinite(pos.el) ? pos.el.toFixed(1) + '°' : '--.-'; if (telEl && Number.isFinite(pos.el)) telEl.textContent = pos.el.toFixed(1) + '°';
if (telAz) telAz.textContent = Number.isFinite(pos.az) ? pos.az.toFixed(1) + '°' : '---.-'; if (telAz && Number.isFinite(pos.az)) telAz.textContent = pos.az.toFixed(1) + '°';
if (telDist) telDist.textContent = Number.isFinite(pos.dist) ? pos.dist.toFixed(0) + ' km' : '---- km'; if (telDist && Number.isFinite(pos.dist)) telDist.textContent = pos.dist.toFixed(0) + ' km';
} }
function updateCountdown() { function updateCountdown() {