Update app.py
Browse files
app.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
# Guided scenarios (ACTIVE):
|
| 5 |
# A) Straight heading
|
| 6 |
# B) Variable heading & speed (beam search, BTO-first)
|
| 7 |
-
# C) Variable heading & speed (SE
|
| 8 |
#
|
| 9 |
# Key behavior:
|
| 10 |
# - Last radar spot FIXED: 18:22:00Z @ 6.578N, 96.341E
|
|
@@ -22,9 +22,9 @@
|
|
| 22 |
# PERFORMANCE:
|
| 23 |
# - Straight heading mode keeps Top-K polish.
|
| 24 |
# - Variable heading & speed uses beam search and skips polish by default (much faster).
|
| 25 |
-
# - SE mode reuses the same beam search, but
|
| 26 |
-
#
|
| 27 |
-
#
|
| 28 |
|
| 29 |
import os
|
| 30 |
import re
|
|
@@ -142,13 +142,18 @@ VAR_HEADING_DELTA_SET = [-6, -3, 0, 3, 6] # candidate changes per segment (deg)
|
|
| 142 |
VAR_BEAM_WIDTH = 12 # keep top-N partial paths each segment
|
| 143 |
VAR_SMOOTH_PENALTY_US_PER_DEG = 1.5 # small penalty to avoid wiggles (still BTO-first)
|
| 144 |
|
| 145 |
-
# ===== SE-
|
| 146 |
# Only applied to the last two segments (22:40→00:10, 00:10→00:20).
|
| 147 |
-
#
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
# Search area colors (optional)
|
| 154 |
SEARCH_AREA_COLORS = {
|
|
@@ -1650,9 +1655,15 @@ def _solve_guided_variable_core(method, alt_ft, vs_fpm, descent_start_choice, se
|
|
| 1650 |
|
| 1651 |
# choose heading deltas:
|
| 1652 |
# - normal: VAR_HEADING_DELTA_SET for all segments
|
| 1653 |
-
# - SE mode: after 22:40 (segments 4 and 5),
|
| 1654 |
use_se_bias = bool(se_bias_after_2240 and seg_i >= SE_EAST_DIVERGE_START_SEG_INDEX)
|
| 1655 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1656 |
|
| 1657 |
for st in beam:
|
| 1658 |
h_prev = float(st["h_prev"])
|
|
@@ -1660,8 +1671,14 @@ def _solve_guided_variable_core(method, alt_ft, vs_fpm, descent_start_choice, se
|
|
| 1660 |
cand_h = []
|
| 1661 |
for d in delta_set:
|
| 1662 |
h_try = h_prev + float(d)
|
| 1663 |
-
h_try = _clamp(h_try,
|
| 1664 |
cand_h.append(h_try)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1665 |
cand_h = sorted(list({round(x, 6): x for x in cand_h}.values()))
|
| 1666 |
|
| 1667 |
for h_try in cand_h:
|
|
@@ -1684,7 +1701,7 @@ def _solve_guided_variable_core(method, alt_ft, vs_fpm, descent_start_choice, se
|
|
| 1684 |
abs_err = 0.0 if meas is None or (err_seg != err_seg) else abs(float(err_seg))
|
| 1685 |
smooth_pen = abs(float(h_try) - float(h_prev)) * VAR_SMOOTH_PENALTY_US_PER_DEG
|
| 1686 |
|
| 1687 |
-
#
|
| 1688 |
east_bias_pen = 0.0
|
| 1689 |
if use_se_bias:
|
| 1690 |
dh = float(h_try) - float(h_prev)
|
|
@@ -1782,13 +1799,14 @@ def _solve_guided_variable_core(method, alt_ft, vs_fpm, descent_start_choice, se
|
|
| 1782 |
]
|
| 1783 |
else:
|
| 1784 |
report_lines = [
|
| 1785 |
-
"**Guided mode: Variable heading & speed (SE
|
| 1786 |
-
"- Solver mode: **BTO-first ring-fit (beam search) +
|
| 1787 |
f"- Turn speed: **{best_global_info['v_turn']:.2f} kt** (range {TURN_SPEED_MIN_KT:.0f}–{TURN_SPEED_MAX_KT:.0f})",
|
| 1788 |
f"- Beam width: **{VAR_BEAM_WIDTH}**",
|
| 1789 |
f"- Normal heading deltas (pre-22:40): **{VAR_HEADING_DELTA_SET}°**",
|
| 1790 |
-
f"-
|
| 1791 |
-
f"-
|
|
|
|
| 1792 |
"",
|
| 1793 |
"**Per-segment heading & speed:**",
|
| 1794 |
f"- 18:40→19:40: **{hs[0]:.2f}°**, **{vs[0]:.2f} kt** (end err {es[0]:+.2f} µs)",
|
|
@@ -1803,7 +1821,7 @@ def _solve_guided_variable_core(method, alt_ft, vs_fpm, descent_start_choice, se
|
|
| 1803 |
f"- RMSE_BTO at enforced times: **{best_global_info['rmse_bto_us']:.2f} µs**",
|
| 1804 |
"",
|
| 1805 |
"*If 18:40 has no measured BTO in your satLoc, it is automatically not enforced.*",
|
| 1806 |
-
"*
|
| 1807 |
]
|
| 1808 |
|
| 1809 |
return best_global_legs, "\n".join(report_lines), start_dt
|
|
@@ -1911,7 +1929,7 @@ with gr.Blocks() as demo:
|
|
| 1911 |
f"**Southern speed bounds:** {SOUTH_SPEED_MIN_KT:.0f}–{SOUTH_SPEED_MAX_KT:.0f} kt\n"
|
| 1912 |
f"**Straight mode:** Top-K polish (top-{TOPK_POLISH})\n"
|
| 1913 |
f"**Variable mode:** beam search (width {VAR_BEAM_WIDTH})\n"
|
| 1914 |
-
f"**SE mode:**
|
| 1915 |
)
|
| 1916 |
|
| 1917 |
guided_mode = gr.Dropdown(
|
|
|
|
| 4 |
# Guided scenarios (ACTIVE):
|
| 5 |
# A) Straight heading
|
| 6 |
# B) Variable heading & speed (beam search, BTO-first)
|
| 7 |
+
# C) Variable heading & speed (SE after 22:40) (beam search, BTO-first + HARD heading band 175–180 after 22:40)
|
| 8 |
#
|
| 9 |
# Key behavior:
|
| 10 |
# - Last radar spot FIXED: 18:22:00Z @ 6.578N, 96.341E
|
|
|
|
| 22 |
# PERFORMANCE:
|
| 23 |
# - Straight heading mode keeps Top-K polish.
|
| 24 |
# - Variable heading & speed uses beam search and skips polish by default (much faster).
|
| 25 |
+
# - SE mode reuses the same beam search, but from 22:40 onward it HARD-CONSTRAINS
|
| 26 |
+
# the last two leg headings into 175–180° (more southeast), with an optional tiny
|
| 27 |
+
# penalty for heading increases within that band.
|
| 28 |
|
| 29 |
import os
|
| 30 |
import re
|
|
|
|
| 142 |
VAR_BEAM_WIDTH = 12 # keep top-N partial paths each segment
|
| 143 |
VAR_SMOOTH_PENALTY_US_PER_DEG = 1.5 # small penalty to avoid wiggles (still BTO-first)
|
| 144 |
|
| 145 |
+
# ===== SE-after-22:40 (HARD CONSTRAINT mode) =====
|
| 146 |
# Only applied to the last two segments (22:40→00:10, 00:10→00:20).
|
| 147 |
+
# We constrain headings into a SE band so the path *must* go more east after 22:40.
|
| 148 |
+
SE_EAST_DIVERGE_START_SEG_INDEX = 4 # seg indices: 0..5 ; seg 4 starts after 22:40
|
| 149 |
+
SE_POST2240_HDG_MIN = 175.0
|
| 150 |
+
SE_POST2240_HDG_MAX = 180.0
|
| 151 |
+
|
| 152 |
+
# Candidate deltas for post-22:40 segments: allow stronger "eastward" moves (lower heading)
|
| 153 |
+
SE_VAR_EAST_DELTA_SET = [-16, -12, -8, -6, -4, -2, 0, 2]
|
| 154 |
+
|
| 155 |
+
# Optional tiny penalty if heading increases after 22:40 (nudges toward the lower end of the band)
|
| 156 |
+
SE_EAST_BIAS_PENALTY_US_PER_DEG = 0.8
|
| 157 |
|
| 158 |
# Search area colors (optional)
|
| 159 |
SEARCH_AREA_COLORS = {
|
|
|
|
| 1655 |
|
| 1656 |
# choose heading deltas:
|
| 1657 |
# - normal: VAR_HEADING_DELTA_SET for all segments
|
| 1658 |
+
# - SE mode: after 22:40 (segments 4 and 5), HARD clamp heading into [175, 180]
|
| 1659 |
use_se_bias = bool(se_bias_after_2240 and seg_i >= SE_EAST_DIVERGE_START_SEG_INDEX)
|
| 1660 |
+
|
| 1661 |
+
if use_se_bias:
|
| 1662 |
+
delta_set = SE_VAR_EAST_DELTA_SET
|
| 1663 |
+
lo_h, hi_h = float(SE_POST2240_HDG_MIN), float(SE_POST2240_HDG_MAX)
|
| 1664 |
+
else:
|
| 1665 |
+
delta_set = VAR_HEADING_DELTA_SET
|
| 1666 |
+
lo_h, hi_h = float(VAR_HEADING_MIN), float(VAR_HEADING_MAX)
|
| 1667 |
|
| 1668 |
for st in beam:
|
| 1669 |
h_prev = float(st["h_prev"])
|
|
|
|
| 1671 |
cand_h = []
|
| 1672 |
for d in delta_set:
|
| 1673 |
h_try = h_prev + float(d)
|
| 1674 |
+
h_try = _clamp(h_try, lo_h, hi_h)
|
| 1675 |
cand_h.append(h_try)
|
| 1676 |
+
|
| 1677 |
+
# ensure band edges are always possible candidates in SE mode
|
| 1678 |
+
if use_se_bias:
|
| 1679 |
+
cand_h.append(lo_h)
|
| 1680 |
+
cand_h.append(hi_h)
|
| 1681 |
+
|
| 1682 |
cand_h = sorted(list({round(x, 6): x for x in cand_h}.values()))
|
| 1683 |
|
| 1684 |
for h_try in cand_h:
|
|
|
|
| 1701 |
abs_err = 0.0 if meas is None or (err_seg != err_seg) else abs(float(err_seg))
|
| 1702 |
smooth_pen = abs(float(h_try) - float(h_prev)) * VAR_SMOOTH_PENALTY_US_PER_DEG
|
| 1703 |
|
| 1704 |
+
# Optional tiny penalty in SE band: penalize heading increases (less SE)
|
| 1705 |
east_bias_pen = 0.0
|
| 1706 |
if use_se_bias:
|
| 1707 |
dh = float(h_try) - float(h_prev)
|
|
|
|
| 1799 |
]
|
| 1800 |
else:
|
| 1801 |
report_lines = [
|
| 1802 |
+
"**Guided mode: Variable heading & speed (SE after 22:40) + computed turn (18:22→18:40), clipped to 00:20**",
|
| 1803 |
+
"- Solver mode: **BTO-first ring-fit (beam search) + HARD SE heading band after 22:40**",
|
| 1804 |
f"- Turn speed: **{best_global_info['v_turn']:.2f} kt** (range {TURN_SPEED_MIN_KT:.0f}–{TURN_SPEED_MAX_KT:.0f})",
|
| 1805 |
f"- Beam width: **{VAR_BEAM_WIDTH}**",
|
| 1806 |
f"- Normal heading deltas (pre-22:40): **{VAR_HEADING_DELTA_SET}°**",
|
| 1807 |
+
f"- Post-22:40 heading band: **[{SE_POST2240_HDG_MIN:.1f}°, {SE_POST2240_HDG_MAX:.1f}°]**",
|
| 1808 |
+
f"- Post-22:40 deltas (inside band): **{SE_VAR_EAST_DELTA_SET}°**",
|
| 1809 |
+
f"- Smooth penalty: **{VAR_SMOOTH_PENALTY_US_PER_DEG:.2f} µs/deg** | Optional increase-penalty: **{SE_EAST_BIAS_PENALTY_US_PER_DEG:.2f} µs/deg**",
|
| 1810 |
"",
|
| 1811 |
"**Per-segment heading & speed:**",
|
| 1812 |
f"- 18:40→19:40: **{hs[0]:.2f}°**, **{vs[0]:.2f} kt** (end err {es[0]:+.2f} µs)",
|
|
|
|
| 1821 |
f"- RMSE_BTO at enforced times: **{best_global_info['rmse_bto_us']:.2f} µs**",
|
| 1822 |
"",
|
| 1823 |
"*If 18:40 has no measured BTO in your satLoc, it is automatically not enforced.*",
|
| 1824 |
+
"*SE mode guarantees 175–180° from 22:40 onwards (more southeast). If this makes BTO worse, widen the band slightly.*",
|
| 1825 |
]
|
| 1826 |
|
| 1827 |
return best_global_legs, "\n".join(report_lines), start_dt
|
|
|
|
| 1929 |
f"**Southern speed bounds:** {SOUTH_SPEED_MIN_KT:.0f}–{SOUTH_SPEED_MAX_KT:.0f} kt\n"
|
| 1930 |
f"**Straight mode:** Top-K polish (top-{TOPK_POLISH})\n"
|
| 1931 |
f"**Variable mode:** beam search (width {VAR_BEAM_WIDTH})\n"
|
| 1932 |
+
f"**SE mode:** beam search + HARD heading band **{SE_POST2240_HDG_MIN:.0f}–{SE_POST2240_HDG_MAX:.0f}°** from 22:40 onwards"
|
| 1933 |
)
|
| 1934 |
|
| 1935 |
guided_mode = gr.Dropdown(
|