diff --git a/assets/js/propagation_map_hook.js b/assets/js/propagation_map_hook.js
index 82d45e5a..8429b3cf 100644
--- a/assets/js/propagation_map_hook.js
+++ b/assets/js/propagation_map_hook.js
@@ -363,17 +363,23 @@ function buildPopupHTML(detail, viewshedLoading) {
`
}
-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` : "—"
+function buildDuctInfoHTML(info) {
+ const layers = info.ducts || []
+ let layerRows = ""
+ if (layers.length > 0) {
+ layerRows = layers.map((d, i) => {
+ const baseFt = Math.round(d.base_m * 3.281)
+ const topFt = Math.round(d.top_m * 3.281)
+ const freq = d.min_freq_ghz != null ? `\u2265${d.min_freq_ghz.toFixed(1)} GHz` : ""
+ return `
+ Layer ${i + 1}: ${baseFt}\u2013${topFt} ft (${d.thickness_m} m) ${freq}
+
`
+ }).join("")
+ }
return `
-
Ducting
-
- ${duct.duct_count} layer${duct.duct_count !== 1 ? "s" : ""}
- Thickness: ${thick}
- Traps \u2265 ${freq}
-
+
Ducting — ${info.duct_count} layer${info.duct_count !== 1 ? "s" : ""}
+ ${layerRows}
`
}
diff --git a/lib/microwaveprop/propagation.ex b/lib/microwaveprop/propagation.ex
index aea545f4..ec60bbac 100644
--- a/lib/microwaveprop/propagation.ex
+++ b/lib/microwaveprop/propagation.ex
@@ -96,7 +96,8 @@ defmodule Microwaveprop.Propagation do
%{
duct_count: hrrr_profile[:duct_count],
best_duct_freq_ghz: hrrr_profile[:best_duct_freq_ghz],
- max_duct_thickness_m: hrrr_profile[:max_duct_thickness_m]
+ max_duct_thickness_m: hrrr_profile[:max_duct_thickness_m],
+ ducts: hrrr_profile[:ducts] || []
}
end
diff --git a/lib/microwaveprop/weather/hrrr_native_client.ex b/lib/microwaveprop/weather/hrrr_native_client.ex
index 377ed6d8..2373a498 100644
--- a/lib/microwaveprop/weather/hrrr_native_client.ex
+++ b/lib/microwaveprop/weather/hrrr_native_client.ex
@@ -196,14 +196,25 @@ defmodule Microwaveprop.Weather.HrrrNativeClient do
if profile.level_count >= 3 do
duct_result = Duct.analyze(profile)
+ ducts_summary =
+ Enum.map(duct_result.ducts, fn d ->
+ %{
+ base_m: round(d.base_m),
+ top_m: round(d.top_m),
+ thickness_m: round(d.thickness_m),
+ min_freq_ghz: Duct.min_trapped_frequency_ghz(d)
+ }
+ end)
+
%{
native_min_gradient: min_m_gradient(profile),
best_duct_freq_ghz: duct_result.best_duct_band_ghz,
max_duct_thickness_m: max_duct_thickness(duct_result.ducts),
- duct_count: length(duct_result.ducts)
+ duct_count: length(duct_result.ducts),
+ ducts: ducts_summary
}
else
- %{native_min_gradient: nil, best_duct_freq_ghz: nil, max_duct_thickness_m: nil, duct_count: 0}
+ %{native_min_gradient: nil, best_duct_freq_ghz: nil, max_duct_thickness_m: nil, duct_count: 0, ducts: []}
end
end