Jupitersystem GRF verbessert

This commit is contained in:
2026-04-12 11:55:31 +02:00
parent 2f063658a5
commit ea9381f463
2 changed files with 119 additions and 5 deletions
+30 -4
View File
@@ -1,6 +1,32 @@
{
"refDate": "2026-04-13T00:31:40.897Z",
"refAngle": 312227.6287687423,
"calibratedAt": "2026-04-12T09:26:52+00:00",
"calibratedBy": "Eskimue"
"refDate": "2026-04-13T04:07:00.000Z",
"refAngle": 312229.88248732366,
"calibratedAt": "2026-04-12T09:35:41+00:00",
"calibratedBy": "Eskimue",
"history": [
{
"refDate": "2025-04-12T01:08:00.000Z",
"refAngle": 306668.75732167566,
"calibratedAt": "2026-04-12T09:33:58+00:00",
"calibratedBy": "Eskimue"
},
{
"refDate": "2026-01-01T09:49:00.000Z",
"refAngle": 310684.2913082397,
"calibratedAt": "2026-04-12T09:38:07+00:00",
"calibratedBy": "Eskimue"
},
{
"refDate": "2026-04-12T08:15:00.000Z",
"refAngle": 312217.3093069398,
"calibratedAt": "2026-04-12T09:32:29+00:00",
"calibratedBy": "Eskimue"
},
{
"refDate": "2026-04-13T04:07:00.000Z",
"refAngle": 312229.88248732366,
"calibratedAt": "2026-04-12T09:35:41+00:00",
"calibratedBy": "Eskimue"
}
]
}
+89 -1
View File
@@ -24,12 +24,26 @@ if (isset($_GET['grs_api'])) {
if (!$isAdmin) { http_response_code(403); echo json_encode(['error' => 'Nicht autorisiert']); exit; }
$body = json_decode(file_get_contents('php://input'), true);
if (!$body || !isset($body['refDate'], $body['refAngle'])) { http_response_code(400); echo json_encode(['error' => 'Ungültige Daten']); exit; }
$data = [
$existing = [];
if (file_exists($dataFile)) {
$existing = json_decode(file_get_contents($dataFile), true) ?? [];
}
$history = $existing['history'] ?? [];
$history[] = [
'refDate' => (string) $body['refDate'],
'refAngle' => (float) $body['refAngle'],
'calibratedAt' => date('c'),
'calibratedBy' => $_SESSION['username'] ?? 'admin',
];
usort($history, fn($a, $b) => strcmp((string) $a['refDate'], (string) $b['refDate']));
$latest = end($history);
$data = [
'refDate' => $latest['refDate'],
'refAngle' => $latest['refAngle'],
'calibratedAt' => $latest['calibratedAt'],
'calibratedBy' => $latest['calibratedBy'],
'history' => $history,
];
$written = file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
echo $written !== false ? json_encode(['ok' => true]) : json_encode(['error' => 'Schreibfehler – Dateiberechtigung prüfen']);
exit;
@@ -140,6 +154,15 @@ $bodyClass = 'solarsystem-page jupitersystem-page';
<button class="btn btn-secondary btn-full mt-md" id="grsBtnShadowRays">Schattenstrahlen anzeigen</button>
<button class="btn btn-primary btn-full mt-xs" id="grsBtnSave">Kalibrierung speichern</button>
<div id="grsCalibStatus" class="hint inline-fade mt-sm"></div>
<div id="grsDriftSection" style="display:none">
<div class="solarsystem-label mt-md">GRS Drift-Historie</div>
<p class="hint mt-2xs">Abweichung vom System-II-Rhythmus zwischen je zwei Abgleichen.</p>
<div id="grsDriftAvg" class="hint mt-2xs" style="color:var(--gold-pale)"></div>
<div style="overflow-x:auto;margin-top:0.5rem">
<table id="grsDriftTable" class="data-table" style="font-size:0.8rem;white-space:nowrap"></table>
</div>
</div>
</div>
</details>
</div>
@@ -779,6 +802,60 @@ function parseGrsTransitInput(str) {
return isNaN(d.getTime()) ? null : d;
}
function renderGrsDrift(history) {
const section = document.getElementById('grsDriftSection');
const table = document.getElementById('grsDriftTable');
const avgEl = document.getElementById('grsDriftAvg');
if (!section || !table || !avgEl || !Array.isArray(history) || history.length < 2) {
if (section) section.style.display = 'none';
return;
}
const RAD_TO_DEG = 180 / Math.PI;
let rows = '';
const driftRates = [];
for (let i = 1; i < history.length; i++) {
const prev = history[i - 1];
const curr = history[i];
const t1 = new Date(prev.refDate).getTime();
const t2 = new Date(curr.refDate).getTime();
const elapsedDays = (t2 - t1) / 86400000;
if (elapsedDays <= 0) continue;
const expectedDeg = (elapsedDays / GRS_SYSTEM_II_PERIOD_DAYS) * 360;
const actualDeg = (curr.refAngle - prev.refAngle) * RAD_TO_DEG;
// Drift auf den Bereich [-180, 180] normieren
let drift = ((actualDeg - expectedDeg) % 360 + 540) % 360 - 180;
const driftPerDay = drift / elapsedDays;
driftRates.push(driftPerDay);
const sign = driftPerDay >= 0 ? '+' : '';
const color = Math.abs(driftPerDay) < 0.05 ? 'var(--text-dim)' : (driftPerDay > 0 ? 'var(--gold-pale)' : 'var(--cyan)');
const dateStr = new Date(curr.refDate).toLocaleString('de-DE', { timeZone: 'UTC', dateStyle: 'short', timeStyle: 'short' });
rows += `<tr>
<td>${dateStr} UT</td>
<td>${elapsedDays.toFixed(1)} d</td>
<td style="color:${color};font-variant-numeric:tabular-nums">${sign}${drift.toFixed(2)}°</td>
<td style="color:${color};font-variant-numeric:tabular-nums">${sign}${driftPerDay.toFixed(3)}°/d</td>
</tr>`;
}
table.innerHTML = `<thead><tr>
<th>Abgleich</th><th>Abstand</th><th>Drift ges.</th><th>Drift/Tag</th>
</tr></thead><tbody>${rows}</tbody>`;
if (driftRates.length > 0) {
const avg = driftRates.reduce((s, v) => s + v, 0) / driftRates.length;
const sign = avg >= 0 ? '+' : '';
avgEl.textContent = `Ø Drift: ${sign}${avg.toFixed(3)}°/Tag`;
}
section.style.display = '';
}
function formatGrsStatus(data) {
if (!data.calibratedAt) return 'Noch keine Kalibrierung gespeichert.';
const at = new Date(data.calibratedAt).toLocaleString('de-DE', { timeZone: 'UTC', dateStyle: 'short', timeStyle: 'short' });
@@ -797,6 +874,7 @@ async function loadGrsCalibration() {
}
const statusEl = document.getElementById('grsCalibStatus');
if (statusEl) statusEl.textContent = formatGrsStatus(data);
renderGrsDrift(data.history);
} catch (e) {}
}
@@ -948,6 +1026,12 @@ function attachAdminHandlers() {
grsBtnRot5R.addEventListener('click', () => shiftGrsRotation(5));
grsBtnSave.addEventListener('click', async () => {
if (grsTransitInput.value.trim() === '') {
grsParseError.textContent = 'Bitte zuerst einen GRS-Transitzeitpunkt eingeben und auf „Auf diese Zeit setzen" klicken.';
grsParseError.classList.remove('is-hidden');
return;
}
const elapsedDays = (simDate - grsRefDate) / 86400000;
grsRefAngle = grsRefAngle + (elapsedDays / GRS_SYSTEM_II_PERIOD_DAYS) * Math.PI * 2;
grsRefDate = new Date(simDate);
@@ -956,6 +1040,10 @@ function attachAdminHandlers() {
grsCalibStatus.textContent = ok === true
? `Gespeichert: ${simDate.toISOString().slice(0, 16).replace('T', ' ')} UT\nFür alle Nutzer aktiv.`
: `Fehler: ${ok}`;
if (ok === true) {
const res = await fetch('jupitersystem.php?grs_api').catch(() => null);
if (res && res.ok) { const d = await res.json(); renderGrsDrift(d.history); }
}
});
}