Files
mcm-26-b/project/q2/baseline.py
T
2026-09-12 16:58:25 +08:00

72 lines
2.6 KiB
Python

"""问题二基线实现:两个朴素但常见的对照。
- ``candidate_perp``:沿首次示向度垂直方向、距检测点约 1000 m 取点。
这是"尽量把交会角做成 90°"的教科书启发式,**但它忽略接收距离保证**:
真源可能落在首次角域的远端(≤1500 m),此时第二点距离可超过 1000 m,
第二次测量直接 ``no_signal``,几何收益落空。
- ``candidate_mec``:退到候选集最小包围圆圆心。它确实落在保证接收盘内
(ρ≤1000 时),但交会角可能接近 0°、后验几乎不收缩,代表"最保守"一端。
"""
from __future__ import annotations
import math
from mcm26b.config import ProblemConfig
from mcm26b.planner import safe_disk_radius
from project.common import Method, problem_config
from project.q2.region import first_bearing_region
PERP = Method(
key="baseline_perp",
name="垂直 1000 m 最大交会角",
kind="baseline",
note="忽略接收保证的几何启发式",
)
MEC = Method(
key="baseline_mec",
name="候选集 MEC 圆心",
kind="baseline",
note="保证接收但交会角最差的保守基线",
)
METHODS = (PERP, MEC)
def _region(case: dict, config: ProblemConfig):
return first_bearing_region(case, config)
def candidate_perp(case: dict, config: ProblemConfig | None = None) -> dict:
config = config or problem_config()
region = _region(case, config)
station = (case["station"][0], case["station"][1])
theta = math.radians(case["bearing_deg"] + 90.0)
distance = config.field.r_eff_min_m
position = (station[0] + distance * math.cos(theta),
station[1] + distance * math.sin(theta))
return {
"method": PERP.key,
"position": [round(position[0], 4), round(position[1], 4)],
"worst_posterior_radius_m": None, # 由 compare 统一评估
"move_cost_s": None,
"safe_disk_radius_m": safe_disk_radius(region, config),
"initial_radius_m": region.mec()[1],
"reason": "沿首次示向度法向 1000 m 取 90° 交会点",
}
def candidate_mec(case: dict, config: ProblemConfig | None = None) -> dict:
config = config or problem_config()
region = _region(case, config)
center, radius = region.mec()
return {
"method": MEC.key,
"position": [round(center[0], 4), round(center[1], 4)],
"worst_posterior_radius_m": None,
"move_cost_s": None,
"safe_disk_radius_m": safe_disk_radius(region, config),
"initial_radius_m": radius,
"reason": "取候选集最小包围圆圆心,保证接收但交会角可能最差",
}