Fix map detail panel: update weights, add PWAT, show duct info
- Update all 9 hardcoded weights to match recalibrated values - Add missing PWAT factor (11.3% weight) to FACTOR_META and FACTOR_ORDER - Reorder factors by weight (highest first) - Fix pressure explanation (low pressure is better, not rising) - Add PWAT factor explanation (beneficial vs harmful by band) - Show duct info panel when native data detects ducting layers (count, thickness, minimum trapped frequency)
This commit is contained in:
parent
a1d787b26f
commit
58a99de3cd
1 changed files with 42 additions and 14 deletions
|
|
@ -1,21 +1,24 @@
|
||||||
import topbar from "../vendor/topbar"
|
import topbar from "../vendor/topbar"
|
||||||
import { updateGridOverlay } from "./maidenhead_grid"
|
import { updateGridOverlay } from "./maidenhead_grid"
|
||||||
|
|
||||||
|
// Weights must match BandConfig.weights() in band_config.ex
|
||||||
|
// Recalibrated 2026-04-11 via gradient descent (loss 0.42 → 0.12)
|
||||||
const FACTOR_META = {
|
const FACTOR_META = {
|
||||||
humidity: { label: "Humidity", weight: 0.20, unit: "g/m\u00b3" },
|
rain: { label: "Rain", weight: 0.1362, unit: "" },
|
||||||
time_of_day: { label: "Time of Day", weight: 0.20, unit: "" },
|
humidity: { label: "Humidity", weight: 0.1243, unit: "g/m\u00b3" },
|
||||||
td_depression: { label: "Td Depression", weight: 0.12, unit: "\u00b0F" },
|
pwat: { label: "PWAT", weight: 0.1128, unit: "mm" },
|
||||||
refractivity: { label: "Refractivity", weight: 0.10, unit: "N/km" },
|
season: { label: "Season", weight: 0.1112, unit: "" },
|
||||||
sky: { label: "Sky Cover", weight: 0.10, unit: "%" },
|
refractivity: { label: "Refractivity", weight: 0.1049, unit: "N/km" },
|
||||||
season: { label: "Season", weight: 0.10, unit: "" },
|
pressure: { label: "Pressure", weight: 0.1032, unit: "mb" },
|
||||||
rain: { label: "Rain", weight: 0.08, unit: "" },
|
td_depression: { label: "Td Depression", weight: 0.0978, unit: "\u00b0F" },
|
||||||
wind: { label: "Wind", weight: 0.06, unit: "kts" },
|
sky: { label: "Sky Cover", weight: 0.08, unit: "%" },
|
||||||
pressure: { label: "Pressure", weight: 0.04, unit: "mb" }
|
wind: { label: "Wind", weight: 0.08, unit: "kts" },
|
||||||
|
time_of_day: { label: "Time of Day", weight: 0.0496, unit: "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
const FACTOR_ORDER = [
|
const FACTOR_ORDER = [
|
||||||
"humidity", "time_of_day", "td_depression", "refractivity",
|
"rain", "humidity", "pwat", "season", "refractivity",
|
||||||
"sky", "season", "rain", "wind", "pressure"
|
"pressure", "td_depression", "sky", "wind", "time_of_day"
|
||||||
]
|
]
|
||||||
|
|
||||||
function scoreTier(score) {
|
function scoreTier(score) {
|
||||||
|
|
@ -90,10 +93,20 @@ function factorExplanation(key, score, detail) {
|
||||||
if (score >= 90) return "No rain — no path attenuation"
|
if (score >= 90) return "No rain — no path attenuation"
|
||||||
if (score >= 50) return "Light rain — minor attenuation"
|
if (score >= 50) return "Light rain — minor attenuation"
|
||||||
return "Heavy rain — significant path loss"
|
return "Heavy rain — significant path loss"
|
||||||
|
case "pwat":
|
||||||
|
if (beneficial) {
|
||||||
|
if (score >= 80) return "High column moisture — strong refractivity"
|
||||||
|
if (score >= 50) return "Moderate PWAT — some refractivity enhancement"
|
||||||
|
return "Low PWAT — limited moisture for ducting"
|
||||||
|
} else {
|
||||||
|
if (score >= 80) return "Low column moisture — minimal absorption"
|
||||||
|
if (score >= 50) return "Moderate PWAT"
|
||||||
|
return "High PWAT — significant absorption at this frequency"
|
||||||
|
}
|
||||||
case "pressure":
|
case "pressure":
|
||||||
if (score >= 70) return "Rising pressure — increasing stability favors inversions"
|
if (score >= 70) return "Low pressure — frontal boundaries favor ducting"
|
||||||
if (score >= 55) return "Steady pressure — stable conditions"
|
if (score >= 45) return "Normal pressure — average conditions"
|
||||||
return "Falling pressure — instability weakens inversions"
|
return "High pressure — stable ridge, inversions cap at wrong altitude"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -344,11 +357,26 @@ function buildPopupHTML(detail, viewshedLoading) {
|
||||||
<div style="font-size:10px;font-weight:700;opacity:0.5;margin-bottom:4px;text-transform:uppercase;letter-spacing:0.5px;">Analysis</div>
|
<div style="font-size:10px;font-weight:700;opacity:0.5;margin-bottom:4px;text-transform:uppercase;letter-spacing:0.5px;">Analysis</div>
|
||||||
${explanations}
|
${explanations}
|
||||||
</div>
|
</div>
|
||||||
|
${detail.factors.duct_info ? buildDuctInfoHTML(detail.factors.duct_info) : ""}
|
||||||
${detail.forecast ? buildForecastSvg(detail.forecast) : ""}
|
${detail.forecast ? buildForecastSvg(detail.forecast) : ""}
|
||||||
${viewshedStatus}
|
${viewshedStatus}
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDuctInfoHTML(duct) {
|
||||||
|
const freq = duct.best_duct_freq_ghz != null ? `${duct.best_duct_freq_ghz.toFixed(1)} GHz` : "—"
|
||||||
|
const thick = duct.max_duct_thickness_m != null ? `${Math.round(duct.max_duct_thickness_m)} m` : "—"
|
||||||
|
return `
|
||||||
|
<div style="padding:4px 10px 6px;border-top:1px solid rgba(255,255,255,0.15);">
|
||||||
|
<div style="font-size:10px;font-weight:700;opacity:0.5;margin-bottom:3px;text-transform:uppercase;letter-spacing:0.5px;">Ducting</div>
|
||||||
|
<div style="font-size:12px;display:flex;gap:12px;">
|
||||||
|
<span><strong>${duct.duct_count}</strong> layer${duct.duct_count !== 1 ? "s" : ""}</span>
|
||||||
|
<span>Thickness: <strong>${thick}</strong></span>
|
||||||
|
<span>Traps \u2265 <strong>${freq}</strong></span>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
|
||||||
// --- Hook ---
|
// --- Hook ---
|
||||||
|
|
||||||
export const PropagationMap = {
|
export const PropagationMap = {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue