34 Commits
Author SHA1 Message Date
Horldsence d975309a81 holy fuking shit 2026-09-12 01:56:34 +08:00
Horldsence 36f354736c 1919810 2026-09-11 23:07:42 +08:00
Horldsence 5c96699b70 1 2026-09-11 21:07:21 +08:00
Horldsence 1725cd0891 114514 2026-09-11 21:00:39 +08:00
sloray 2a3ead5d3d Merge branch 'q3-bayes' of git.simba-robotics.com:HelixCopex/mcm-26-b into q3-bayes 2026-09-11 17:56:08 +08:00
sloray 4d224e586a 强化学习第二版 2026-09-11 17:56:03 +08:00
Horldsence 7026277a8d Merge branch 'q3-bayes' of https://git.simba-robotics.com/HelixCopex/mcm-26-b into q3-bayes 2026-09-11 17:25:45 +08:00
Horldsence b15db59ac3 14 2026-09-11 17:24:29 +08:00
sloray 30df22e8b2 13 2026-09-11 17:24:07 +08:00
sloray 4699b0d45f 强化学习第一版 2026-09-11 16:56:39 +08:00
Horldsence 2bc4c7ed82 Merge branch 'q3-bayes' of https://git.simba-robotics.com/HelixCopex/mcm-26-b into q3-bayes 2026-09-11 11:37:22 +08:00
Horldsence a18a139a1d 6 2026-09-11 11:36:08 +08:00
Horldsence 2d2a9a4e6a feat: 5 2026-09-11 11:35:47 +08:00
sloray fd48064000 第四次运行 2026-09-11 11:28:36 +08:00
sloray 7dedcd0629 4000s上限优化 2026-09-11 11:16:23 +08:00
sloray 9cf94281a9 论文/3batch 2026-09-11 09:52:05 +08:00
Horldsence f3dfa9c2a1 feat: 修复大粪扫描频率 2026-09-11 09:50:56 +08:00
Horldsence bd479b6d9d Merge remote-tracking branch 'origin/gpt' into q3-bayes 2026-09-11 09:12:24 +08:00
Horldsence 9c9ab451e5 feat(q3): 消融基准(14场景-19.5%)+Optuna调参脚本+文档;run 默认策略切 bayes 2026-09-11 09:11:21 +08:00
Horldsence e0665c73fb feat(q3): 贝叶斯网格粒子滤波闭环(PF负观测+信息增益选点+2-opt调度)
- particles.py: 网格幸存集滤波,Voronoi 裕量保证真源保留(缺席证明/网格清除证书/跳测规则)
- planner/bayes_loop.py: 统一任务循环(站点/定位/清除滚动 2-opt 排序)、期望后验半径选点
- planner/seven.py: 七点覆盖策略族提升为库代码
- cli: mcm26b run --strategy {grid,seven,bayes}
- BayesConfig 参数组;tests +24 项(真源保留/证书/端到端),129 全绿
2026-09-11 09:02:28 +08:00
sloray 52c69b1276 模拟器细节特征对齐 2026-09-11 08:29:56 +08:00
Horldsence 7930eb65bf feat: 3 2026-09-11 03:33:36 +08:00
Horldsence fc70d6edfd feat: 3 2026-09-11 03:32:05 +08:00
sloray 78d52ff81c 第三问的垃圾算法 2026-09-11 03:26:20 +08:00
sloray 846b45e420 Merge branch 'gpt' of git.simba-robotics.com:HelixCopex/mcm-26-b into gpt 2026-09-11 02:34:16 +08:00
sloray 12da6aafd2 Tex 配方预设/论文列表 2026-09-11 02:33:19 +08:00
Horldsence 4f91f242fe 2 2026-09-11 02:32:31 +08:00
sloray 8c18a1f499 Merge branch 'gpt' of git.simba-robotics.com:HelixCopex/mcm-26-b into gpt 2026-09-11 01:26:35 +08:00
Horldsence a6308fd40c 1 2026-09-11 01:19:38 +08:00
sloray dbf4feec4e 编译错误修复 2026-09-10 23:44:13 +08:00
Horldsence 83d2e24448 refactor(arch): redesign the code structure 2026-09-10 22:38:27 +08:00
sloray 21e8a8bf52 合并完成 2026-09-10 21:37:28 +08:00
Horldsence c57865edf5 Merge branch 'gpt' of https://git.simba-robotics.com/HelixCopex/mcm-26-b into gpt 2026-09-10 21:14:46 +08:00
Horldsence 0dac40d348 paper 2026-09-10 21:13:45 +08:00
238 changed files with 60393 additions and 2292 deletions
Vendored
BIN
View File
Binary file not shown.
+16 -1
View File
@@ -11,4 +11,19 @@ wheels/
# Sim # Sim
Jammers*/ Jammers*/
tmp/ tmp/
# LaTeX build artifacts
docs/paper/build/
docs/paper/*.aux
docs/paper/*.log
docs/paper/*.out
docs/paper/*.fls
docs/paper/*.fdb_latexmk
docs/paper/*.xdv
docs/paper/*.synctex.gz
# pytest
.pytest_cache/
# 1
output/
+37
View File
@@ -0,0 +1,37 @@
{
"latex-workshop.latex.workingDirectory": "%DIR%",
"latex-workshop.latex.tools": [
{
"name": "xelatex",
"command": "xelatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"%DOC%"
]
},
{
"name": "latexmk (xelatex)",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-xelatex",
"%DOC%"
]
}
],
"latex-workshop.latex.recipes": [
{
"name": "xelatex",
"tools": ["xelatex"]
},
{
"name": "latexmk (xelatex)",
"tools": ["latexmk (xelatex)"]
}
],
"latex-workshop.latex.recipe.default": "first"
}
@@ -0,0 +1,60 @@
# 修复计划:7 项 P2 问题 + 3 项规划调整
已核实:7 个问题的定位与审核报告一致;另确认关联缺陷 `planner/__init__.py:392` 用 `>` 判断遮挡预算(实际放行 5 个被遮挡探点,注释口径为 4)。用户已确认:环探保留启发式+重写依据;误差场采用逐点白噪声哈希。
## 修改一:模拟器固定误差场(问题1)
文件 `src/mcm26b/sim/simulator.py`:
- 新增 `_bearing_error(channel, pos)`:`sha256(f"{error_seed}|{channel}|{round(x,6)}|{round(y,6)}")` 前 8 字节映射到 `[-error_half_deg, +error_half_deg)`。同一(源频道, 位置)读数恒定,不同点独立。
- `_observe`(L193)改为调用它;删除顺序随机流 `self._rng`(构造参数 `error_seed` 保留)。
- 模块 docstring 更新:同位置误差固定;分布仍是测试假设。
- 新增测试:同位置重复测量(不同 request_id)svd_deg 相同;同种子两次构造结果一致。
## 修改二:Q4 对跖探点公式(问题2)
文件 `src/mcm26b/planner/__init__.py`(L440-447):
- L447:`dx / norm * scale` → `dx * scale`(dy 同理),使偏移模长 = `min(norm, safe)`。圆心为原点、原探点 (200,0)、safe≥200 时返回 (-200,0)。
- L444 退化分支:`min(safe, 1.0)` → `safe`(方向 +x),不再钳到 1m。
- 新增单测:对跖点坐标(safe≥norm 与 safe<norm 两种)。
## 修改三:环探依据重写 + 预算一致(问题3,保留启发式)
- `planner/__init__.py` 模块 docstring、`DirectionalExtension` docstring、`_next_probe` docstring(L428-431):删除"≥180° 弧"声称,改为诚实表述:源位于环上且朝向沿外切线时可见弧可退化为单点,固定 45° 步进无最坏命中保证;梯子只提高提前命中率,完备性完全由后备清除兜底。
- `docs/协议规则表与状态机.md` §7(L166-172)同步重写。
- L392 `>` → `>=`,`config.py:85` 注释与文档同步为"4 个被遮挡探点(选点/对跖/环探×2)"。
- 新增 `scripts/benchmark_q4.py`:批量种子扫描(`--problem 4`,可配源数/定向数/种子范围/输出路径),逐局记录 measures、clears、后备清除格数与 attempts、virtual_time、completed,落盘 `output/q4/benchmark.json` 并打印汇总表——用于验证修复后的后备清除成本(审核"验证后备成本"要求),同时为论文问题4结果表提供可复现数字。
## 修改四:通信失败可靠收尾(问题4)
文件 `planner/__init__.py` `run()`(L195-205):
- `client.enter()` 纳入 try;except 顺序:`DeadlineExceeded` → `(TransportError, ProtocolError, InconsistentBelief)` → `Exception` 兜底;stop_reason 分别记 `real_budget_exhausted` / `transport_failure` / `protocol_error` / `inconsistent_belief` / `unexpected_error`,summary 增 `abort_detail`(异常类型+消息,截断)。
- `/exit` 改为尽力而为:`client.exit()` 失败不再中断收尾;`_summary` 接受 `info=None`(`exit_reason="exit_unreachable"`,virtual_time 取 `client.state.virtual_time_s`)。
- summary 增 `channel_status` 快照(每频道状态 + 候选 MEC 半径,约 20 条)——即"保存未完成状态";`--log` 的 JSONL 本就有全过程留痕。
- cli.py 无需改(`completed=false` 已映射退出码 1)。
- 新增测试:注入连续三次传输失败(若 `ScriptedFaultTransport` 不支持持久失败则扩展其故障类型),断言 `run()` 正常返回 summary 不抛异常、有 /exit 尝试留痕、退出码路径为 1。
## 修改五:Q1 近平行退化情形(问题5)
文件 `src/mcm26b/geometry/localization.py`(L216-226):
- 衰退方向判定改为对浮点平面系数的精确有理数运算(`Fraction`):候选方向仍枚举各平面法线的垂直方向 `(b,-a)/(-b,a)`;先用浮点快速预筛(max > 1e-9 直接排除,浮点误差远小于该阈值),近零候选再用 Fraction 精确检验 `∀(d,e,f): d·dir_x + e·dir_y ≤ 0`。平面系数本身是 float(精确有理数),故结论对量化输入精确,消除 2e-14 阈值与顶点过滤 eps=1e-9 的口径错配导致的漏判。
- 顶点枚举与 `PARALLEL_EPS` 预筛保持现状。
- 回归测试:审核复现输入 `[(0,0,1°), (0,0.01,358.99999999999°)]` → `status=unbounded`、`diameter_infinite=true`、不给清除保证;`scripts/benchmark_q1.py` 两档结果不回归。
## 修改六:默认舍入裕量统一(问题6)
- `config.py:75`:`bearing_rounding_margin_deg` 默认 `0.0` → `0.005`,注释改为"覆盖服务器两位小数舍入偏差(≤0.005°);库默认与 CLI 默认一致"。
- `q1` 子命令与 `geometry/__main__.py` 的 `--rounding-margin-deg` 默认保持 0(离线敏感性分析语义不变,审核未要求改)。
- 新增断言 `SearchConfig().bearing_rounding_margin_deg == 0.005`,并用默认配置复跑"边缘读数保留真源"场景;检查显式传参的现有测试不受影响;README 如有默认值描述一并更新。
## 修改七:后验评分补 near 分支(问题7)
文件 `planner/__init__.py` `_worst_posterior_radius`(L93-110):
- 增加 near 分支:`probe.clip_disk(q, field.near_radius_m, search.polygon_sides)`,多边形非空则纳入 max;direction 端点分支保留,docstring 说明 safe 盘内 no_signal 不可能故不枚举。
- 调用点(粗评/加密复评两处)传入 `near_radius_m` 与 `polygon_sides`。
- 新增测试:候选集 `[(-4,0),(4,0)]`(两点退化区域)、q=原点 → 最坏后验 ≈ 4m(修复前报 2m);`test_loop_q3/q4` 场景回归(选点可能变化,但断言均为清除状态类,预期无碍)。
## 规划调整落地
- **A(第二问定位)**:`docs/algo-2.md` §13(L231 附近)明确交付为"安全选点的启发式基线":解析安全盘证书已实现并证明;§10 区间上界未实现,采样最大值仅作粗筛,不得称严格最坏上界。
- **B(第三问)**:无代码改动;顺序约束(先修改一/四,再官方演练)在 `docs/B题建模分析与实施计划.md` 演练清单处注明。
- **C(第四问预算口径)**:`_summary` 增 `total_requests`(measures+clears);`DirectionalExtension._summary` 增 `fallback_clear_attempts`(Σ attempts);`docs/协议规则表与状态机.md` §7 后备清除段注明"后备 /clear 请求计入总请求与现实预算"。
## 测试与验收
- 每项修改配单测(新增约 10-12 项),全套 pytest 通过(95 → ~107 项)。
- 冒烟:`uv run mcm26b sim-check`;`uv run mcm26b run --problem 3/4 --self-test` 若干种子。
- 运行 `scripts/benchmark_q4.py` 记录修复后后备成本,输出落盘。
## 执行顺序
修改一(模拟器)→ 修改四(收尾)→ 修改六 → 修改七 → 修改二 → 修改三 → 修改五 → 文档同步 → 全量回归。
@@ -0,0 +1,87 @@
# 分层强化学习(HRL)实施计划 — 2026 高教社杯 B 题第三、四问
## 0. 现状与复用决策
仓库已有生产级基建,**全部复用、不重写**:
| 现有组件 | 位置 | 用途 |
|---|---|---|
| `SimulatorClient`(HTTP+JSON、幂等重试、截止时钟、JSONL 日志) | `src/mcm26b/protocol/` | 模拟器对接(prompt 第 1 步已完成) |
| 本地评测机(内存回环,一局秒级) | `referee/` + `harness.LocalSimTransport` | 本地简化环境内核 |
| 网格幸存集滤波(真源保留定理已证明) | `src/mcm26b/particles.py` | 每频道信念后验 |
| 凸候选集 + 五状态机 | `src/mcm26b/belief/` | 频道状态观测 |
| 信息增益选点、TSP 2-opt、六边形覆盖、清除证书、后备清除 | `src/mcm26b/planner/` | 候选生成器 + 证书审批兜底 + 启发式基线 |
| 单步 MaskablePPO 全套(特征/掩码/BC/训练/审计) | `src/mcm26b/rl/` + `scripts/` | 代码模式模板 + 端到端对照基线 |
**改进方向**(来自 v2 审计文档已知局限):单步 RL 只做选点、学不到全场调度;Q4 后备清除偏多、尾部退化(13778s→11797s,距 4000s 目标远)。HRL 高层正是补**跨频道全场调度**决策。
**已确认的三个决策**:① 代码集成到 `src/mcm26b/hrl/`(README 给出与 prompt 目录树的映射表);② 低层为字面 8 方向 PPO + 直线控制器对照(诚实预期:部署时只提交终点,低层对虚拟时间增益≈0,价值在架构完整性与消融验证);③ 本次跑通全流程 + 短程训练(1–2h),完整课程训练交付脚本由用户自行启动。
## 1. 新建文件
```
src/mcm26b/hrl/
├── __init__.py
├── constants.py # HRL 接口常量:N_CANDIDATES=96、观测维度,feature_version=3
├── candidates.py # 高层候选生成:待清除源/信息增益探索点/覆盖验证点/Q4 扇区探测点 + 动作掩码
├── features.py # 高层观测(20 频道×14 统计 + 全局标量 + 96×6 候选特征 ≈864 维)、低层观测
├── policy.py # HighLevelPolicy/LowLevelPolicy 加载器(沿用 PointSelectionPolicy 元数据校验模式)
├── low_level_env.py # 低层训练环境:随机起点→子目标,Discrete(8),逐步计费,奖励=−Δd−转向+到达
├── hierarchical_env.py # 高层整场环境:10–16 源,动作=子目标槽位,内嵌低层执行器,域随机化+课程参数
└── executor.py # 子目标执行器:低层 PPO 步进(本地计费)或直线控制器(可切换),终点提交模拟器
scripts/
├── train_hrl_low.py # 低层:BC 克隆直线控制器热启动 → MaskablePPO 微调;直线对照评估
├── train_hrl_high.py # 高层:4 阶段课程(--stage --resume --timesteps),SubprocVecEnv 并行
├── pretrain_hrl_expert.py # 可选:从 BayesLoop 调度器克隆 (obs, 子目标) 对热启动高层
├── tune_hrl.py # Optuna TPE(prompt §10 搜索空间,预算 15–20 trials,初值复用 bayes 已调参数)
├── benchmark_hrl.py # 配对消融:HRL vs bayes/directional/单步 PPO,dev(700-702)/val(91000-91005)/stress 固定场景
└── ablate_hrl.py # 四项消融:无信息增益奖励/无动作掩码/无课程/无粒子滤波
src/mcm26b/planner/hrl_loop.py # HRLLoop 运行时闭环(Q3/Q4),保留证书审批与异常留痕
src/mcm26b/cli.py # 新增 --strategy hrl / --q4-strategy hrl / --hrl-model
tests/test_hrl.py # 特征布局、掩码、环境形状、奖励恒等式、训练-部署观测一致性
docs/hrl.md # 设计文档 + prompt 目录树映射表
docs/paper/ 增补 # 算法流程图、伪代码、超参表、训练曲线
```
## 2. 核心设计
**高层动作空间** Discrete(96) + 掩码:槽位按固定顺序填充(已定位待清除源 ≤16 → PF 驱动探索点 → 覆盖网格未验证点 → Q4 扇区探测点),空槽/已清除频道/接收盘外候选掩码 −∞。
**高层观测**(≈864 维,参照 v2 的 401 维布局模式):20 频道 × 14 特征(六状态 one-hot、MEC μx/μy、σx/σy/ρ、log 幸存格数、期望信息增益、距离、频道号)+ 全局 8 维(位置、时间比例、已清除数、最近检测结果编码/示向度/距离)+ 96×6 候选特征。
**step 语义**:高层选子目标 → executor 步进(低层 8 方向,每步 ≤100m,本地按 Δd/5 计费;部署时仅终点调模拟器)→ 按子目标类型执行 /measure 或 /clear → belief+PF 更新 → 奖励。
**奖励**:`r = −Δ虚拟耗时/100 + 100·清除 + 5·新检测 + w_info·ΔH − 冗余惩罚`,主口径与目标函数(虚拟时间)一致;w_info 可消融。
**课程 4 阶段**(prompt §7.1):1 源/5 频道/无噪 → 3 源/10 频道/±0.5° → 8 源/16 频道/±1° → 10–16 源/20 频道/±1°;每阶段迁移上阶段权重,Q4 从 Q3 权重微调(定向比例递增),域随机化贯穿(源位置/频道/r_eff/朝向/噪声种子)。
**运行时闭环 HRLLoop**:初始覆盖相位(快速发现信号)→ 主循环高层决策(证书达标自动 /clear,与 BayesLoop 同语义)→ 全清即 /exit。不触碰候选集更新与清除判定的守恒性(真源保留定理依赖),异常留痕兜底保留。
## 3. 实施顺序(对应 prompt §12)
1. `constants.py` + `candidates.py` + `features.py`(候选/掩码/观测)+ 单元测试
2. `low_level_env.py` + `train_hrl_low.py`:低层短程训练,验证收敛到近直线(报告与直线最优的差距)
3. `hierarchical_env.py` + `executor.py` + `hierarchical_env` 单元测试(奖励恒等式:回合回报 = f(虚拟时间、清除数))
4. `train_hrl_high.py` + 课程 + 域随机化 + SubprocVecEnv;`pretrain_hrl_expert.py` BC 热启动
5. 短程课程训练(每阶段 2–5 万步,总计 1–2h),产出训练曲线
6. `hrl_loop.py` + CLI 接入,`--local-judge` 本地演练验证全清正确性
7. `benchmark_hrl.py` 配对对比(沿用 benchmark_rl.py 的 all_valid 有效口径)+ `ablate_hrl.py` 四项消融
8. `tune_hrl.py` 受限 Optuna;产出最佳超参表
9. 本地 referee 演练 ×3/题,表 1 格式结果(案例编码/清除数/平均定位清除时间/程序运行时间),日志 JSONL 原样归档 `output/hrl/`
10. `docs/hrl.md`、README 更新、论文素材(流程图/伪代码/超参表/对比分析,含"为什么分层 PPO、为什么非端到端、为什么非多智能体"论证)
## 4. 验收标准
- 全部 pytest 通过(现有 243 项 + 新增 HRL 测试)
- `benchmark_hrl.py` 输出 all_valid=true(真值全清、缺席无误判、零异常、正常 exit、计时复算一致)
- 短程训练下 Q4 HRL 相对 directional 有可测改进方向(对标单步 RL 的 −14.38%);Q3 如实报告与 bayes 的差距(v2 审计口径:Q3 RL 无稳定增益)
- 所有实验固定种子、命令可复现;消融表含均值±方差(≥5 种子)
- 完整训练只需用户执行 `scripts/train_hrl_high.py --full` 级别的命令
## 5. 风险与对策
- **高层整场回合过长(100–200 决策步)不收敛** → γ=1 + 密集 Δcost 奖励 + BC 从 bayes 调度器热启动
- **低层增益≈0** → 如实消融报告(直线对照差异≈0),论文定位为架构必要性验证而非性能来源
- **Q3 可能无增益** → 与 v2 口径一致如实报告,主打 Q4 调度收益;两种策略可共存(HRL 不改默认策略,仅在胜出后由用户决定切换默认)
@@ -0,0 +1,80 @@
# 目标
在新分支 **`q3-bayes`**(基于当前 `gpt`)实现第三问新算法:**网格化贝叶斯粒子滤波(含负观测更新)+ 信息增益选点 + 开放路径 2-opt 任务排序 + 七点覆盖兜底 + Optuna 离线调参**。评分口径 = 虚拟总时间(A2 基线:官方演练 12 源 5232s、109 次检测);硬性要求全清率 100%、缺席证明正确、零异常。
# 关键设计
## 1. 粒子滤波 `src/mcm26b/particles.py`(新建)
与用户方案的差异点:本项目要求清除证书/缺席证明**严格**(A2 靠保守几何证书做到 100% 清除率),软核概率 PF 有删掉真源的风险。因此采用**网格幸存集滤波**(= 硬似然 PF + Voronoi 裕量,与用户"|θ̂−θ|>1° 权重置零"的设定一致但更严格):
- 每频道一组 Ω 上间距 h≈30m 的网格粒子(约 1.1 万格,alive 用整数索引集合;空间哈希加速邻域查询)
- 保守 kill 判定(margin = h·√2/2,保证真源所在格必活):
- `no_signal`@s:kill dist(g,s) ≤ 1000 − margin(题面 r_eff ≥ 1000 ⟹ 可严格排除该盘)
- `direction`@s 读数 θ:kill 角向偏差超出 δ_eff=1.005°(含余量)或 dist > 1500 + margin 的格
- `near`@s:kill dist(g,s) > 5 + margin
- 证书全部由此推导:清除证书 = MEC(alive).R + margin ≤ 20 − clear_margin;**缺席证明 = alive 为空集**(无需额外像素覆盖检查);跳测规则 = min dist(alive, s) > 1500 + margin ⟹ 必 no_signal,跳过省 6s/次
- 信息增益:对候选点用子采样(≤500 粒子)× K 个代表假设做 MC 期望熵减估计;复用 `smallest_enclosing_circle`(Welzl) 求 MEC
## 2. 新策略 `BayesLoop(OmnidirectionalLoop)`(`src/mcm26b/planner/bayes_loop.py`)
复用基类 run() 骨架、异常收尾、summary、anomaly、预算机制,重写阶段逻辑:
- **发现阶段**:原点起扫(频道排序省换频)→ 站点 = 七点环 ∪ PF 高价值点,按"期望发现数 − λ·移动时间"贪心选站;每站批量扫频时跳过"PF 判定必 no_signal"的 (站,频道) 对与已证缺席频道;每站扫完即服务已发现频道(SevenBatch 风格)
- **定位服务**:选点 = 保证接收盘内候选环采样 + 信息增益评分(ΔH − λ·移动 − μ·检测),有证书即清除;步数上限沿用 `max_localize_steps`
- **清除调度**:待服务任务(定位+清除 ≤20 节点)开放路径最近邻 + 2-opt,纯标准库,每个决策点滚动重排
- **收尾**:全部 CLEARED/ABSENT → all_resolved;清满 16 提前停;persistent_search 沿用现有配置语义(实现时对照 `run_q3_seven_practice.py` 保持官方演练停止行为一致)
## 3. 配置 `config.py`
新增 `BayesConfig` frozen dataclass([工程]):particle_spacing_m、λ/μ 权重、MC 代表数/子采样、skip_margin、站点环半径、2-opt 开关/迭代数等;挂到 `ProblemConfig.bayes`。默认值不改变现有策略行为。
## 4. 七点覆盖提升为库代码 `src/mcm26b/planner/seven.py`
把 `scripts/benchmark_q3_search.py` 的 `seven_points()/SevenImmediate/SevenBatch` 移入 src(旧脚本改 import,消融结果可复现),供 CLI 与新基准复用。
## 5. CLI `cli.py`
`mcm26b run --strategy {grid,seven,bayes}`,默认 grid;**若基准通过则默认改为 bayes**(用户已确认)。
## 6. 基准 `scripts/benchmark_q3_bayes.py`
配对消融 {seven_batch, bayes} ×(seeds 0..5 × 10/16 源 + 边界源 + 0 源纯缺席场景),复用现有 run_case/LocalSimulator 模式;输出 `output/q3/bayes-ablation/`(benchmark.json + report.md):全清率、correct_absence、异常、accounted/total 虚拟时间、配对降幅、实机 compute_wall_s。
## 7. Optuna 调参 `scripts/tune_q3_bayes.py`
- `uv add --group dev optuna`(仅调参脚本用,生产零新增依赖)
- TPE,目标 = 场景子集平均虚拟时间 + 10⁶×失败惩罚;场景与 error_seed 多样化防过拟合
- 搜索空间:h、λ/μ、skip margin、候选环、2-opt 开关等
- optuna 不可用时自动退化为随机搜索;最优参数写 JSON,复跑基准确认后合入 config.py 默认值
## 8. 测试
- `tests/test_particles.py`:真源保留性(随机场景 × LocalSimulator 误差场,任意更新序列后真源邻域格必活);证书正确性(alive=∅ ⟺ 真缺席;MEC 证书清除必成功);跳测规则永不漏检
- `tests/test_bayes_loop_q3.py`:端到端 LocalSimulator(10/16/0 源、边界源、预算耗尽、故障注入):全清 + 缺席正确 + 无异常 + 正常退出
- 现有 105 项测试保持绿
## 9. 文档
`docs/algo-3-bayes.md`(Voronoi 裕量严格性论证、信息增益与调度设计、与 A2 对比数据);README 策略表加行;`docs/algo-3.md` 加交叉引用。
# 执行顺序
1. `git checkout -b q3-bayes`
2. BayesConfig → particles.py(含单测)→ seven.py 提升
3. bayes_loop.py + CLI 接入 → pytest 全绿
4. 跑配对消融基准
5. Optuna 调参 → 回填参数复跑基准
6. 若达标(全清 100% 且配对均值更优):`mcm26b run` 默认切 bayes + 文档更新
7. 分支上分阶段 commit(不 push)
# 验收标准
- 基准全部场景:all_cleared 100%、correct_absence 100%、anomalies 空、normal_exit、单局实机计算 < 60s
- 配对平均虚拟时间优于 seven_batch(目标降幅 ≥5%;参考量级 A2=5232s/12 源)
- `uv run pytest` 全绿;`mcm26b run --self-test --problem 3` 通过
# 风险与对策
- PF 实机计算耗时 → 空间哈希 + MC 子采样,基准记录 compute_wall_s,超预算先降 MC 规模(实机预算 1200s,A2 仅用 3.4s,余量巨大)
- LocalSimulator 误差场确定性 → 调参与基准用多 error_seed
- 负观测删点的正确性 → Voronoi 裕量定理 + 随机化真源保留性测试兜底
-152
View File
@@ -1,152 +0,0 @@
下面把现有《B题建模分析与实施计划》拆成可执行任务,并逐项检查设计思路。总体结论:**主线设计是对的,四问串联、保守几何、覆盖证明、协议幂等这些方向都合理;但有几个关键点需要补强,尤其是问题2候选区域非空性、定向源朝向不确定性、现实20分钟窗口下的请求数控制,以及正式测试时间安排。**
---
## 一、总体判断
现有方案的最大优点是:
1. **四问没有割裂**:问题1的定位区域和包围圆服务于问题2选点,问题3的覆盖发现与清除框架延伸到问题4。
2. **坚持保守性**:用有界误差、半平面交、最小包围圆、49点覆盖证明,避免“看起来能清”但实际漏源。
3. **协议与状态意识强**:强调 `accepted=false` 不更新状态、重试复用 `request_id`、`/clear` 不切换频道、虚拟时间公式。
4. **停止条件严格**:没有把“发现10个源”或“连续无信号”当成功。
主要风险:
- **问题2的候选区域 $\mathcal{Q}$ 可能为空**,需要补非空判断和退化策略。
- **定向源第4问中 `no_signal` 不能直接删除空间候选点**,现有基线保守但效率低,需明确后备清除的规模和请求预算。
- **现实20分钟窗口**下,49点×20频道最多980次检测,可能请求数过大;虚拟时间不是瓶颈,网络延迟和程序运行时间才是。
- **正式测试机会少**,9月13日截止,必须尽早演练并保留正式机会。
---
## 二、任务拆分:可执行清单
建议按下面 P0–P7 拆分,每阶段都有明确交付和验收。
| 阶段 | 任务 | 交付物 | 验收标准 | 优先级 |
|---|---|---|---|---|
| P0 规则固定 | 核对题目、附件1/2、协议、计时、日志要求 | 规则表、状态机、字段表 | 计时示例能逐步得到附件给定值;`/clear` 不切换频道;`accepted=false` 不更新 | 最高 |
| P1 协议基线 | 实现 `/enter`、`/detect`、`/clear`、`/exit`;串行、幂等重试、超时 | 可运行客户端、自建回放测试 | 失败重试不污染状态;虚拟时间与公式一致;能主动退出 | 最高 |
| P2 几何内核 | 角域半平面表示、半平面交、凸多边形、直径、最小包围圆 | `geometry` 模块、测试用例 | 处理 $0^\circ/360^\circ$ 跨界、空集/单点/线段/无界;等边三角形反例通过 | 最高 |
| P3 问题2选点 | 构造 $K_1$,计算候选区域 $\mathcal{Q}$,采样评估后验包围圆 | 第二检测点策略、候选区域算法 | 保证收到信号;$\mathcal{Q}$ 为空时有退化方案;`near` 分支处理 | 高 |
| P4 问题3全向闭环 | 49点覆盖、逐频道覆盖记录、发现—定位—清除—停止 | 全向演练版本、统计脚本 | 10源和16源都能正确退出;边界朝外不漏;停止条件正确 | 最高 |
| P5 问题4定向扩展 | 定向源覆盖证明、失去信号处理、20m圆盘后备清除 | 定向演练版本 | 边界朝外定向源能发现;失去信号后能清除;不误删真源 | 高 |
| P6 加速与消融 | 共享检测、自适应覆盖、目标排序、提前清除 | 消融实验记录 | 全清不退化;虚拟时间/请求数有改善证据 | 中 |
| P7 正式与论文 | 演练、正式各3次、日志原名、表1、论文 | 6次正式记录、原始日志 | 案例编码、程序版本、统计一致;日志上传成功 | 最高 |
时间紧时,**P6 可删减,P0–P5 必须保留**。
---
## 三、设计思路逐项检查
| 设计点 | 判断 | 需要补强/注意 |
|---|---|---|
| 四问统一框架 | 合理 | 问题1和2的几何结果要直接复用到3、4,避免重复建模 |
| 有界误差 $\pm 1^\circ$、示向度两位小数 | 正确 | 实现可加 $\pm 1.005^\circ$ 保守裕量,但不能写成题面规定 |
| 同地点误差固定 | 正确 | 不能原地重复测量取平均 |
| 角域半平面交 | 正确 | 必须处理 $0^\circ/360^\circ$ 跨界;区分空集、单点、线段、有限多边形、无界 |
| 直径枚举 | 正确 | 小规模枚举顶点对即可;无界区域不能截断后声称直径 |
| 以直径为直径的圆覆盖区域 | **不能保证** | 等边三角形反例正确;保证清除要用最小包围圆 $\rho(K)\le 20$ |
| 问题2候选区域 $\mathcal{Q}$ | 方向正确 | $K_1$ 应加 $\Omega$ 和 $B(s_1,1500)$ 约束;$\mathcal{Q}$ 可能为空,需退化策略 |
| 外包圆候选 $B(c,1000-r)$ | 正确 | 仅当 $r<1000$ 时非空;若 $r$ 接近 1000,区域很小 |
| “候选点距第一次检测点不超过1000米” | 错误表述 | 计划已指出,正确是“到 $K_1$ 中任意可能位置距离不超过 1000 米” |
| 49点覆盖 | 证明成立 | 需实现网格边/顶点规则;全向和定向都适用;全 no_signal 可证明该频道不存在 |
| 49点扫描规模 | 估算合理 | 虚拟时间约3.665小时,但现实20分钟受请求延迟约束 |
| 定向源 `no_signal` | 不能直接删除空间候选点 | 基线可只记录覆盖,不删点;加速版再维护朝向可行集合 |
| 定向源后备清除 | 思路可靠 | 候选集合有界后,用边长 20 米小方格中心,中心到格内点的距离满足 $d\le 10\sqrt{2}<20$ 米,逐点 `/clear` |
| 停止条件 | 严格正确 | 清除16个不同频道,或每频道清除成功/完整覆盖证明不存在 |
| `/clear` 不切换频道 | 正确 | 清除后当前测向频道不变,影响下一次切换耗时 |
| 协议幂等 | 正确 | 重试同 `request_id` 和完全相同内容;`accepted=false` 不更新状态 |
| 现实预算 | 关键风险 | 用 `remaining_real_duration_s` 管理;预留退出和故障恢复;日志不超过 2 MB |
| 正式测试 | 时间紧 | 问题3和4各3次;建议9月13日15:30前完成,17:30后不能启动新测试 |
---
## 四、重点补强建议
### 1. 问题2:候选区域必须明确非空处理
建议把第一次测向后的候选集合写清楚:
$$
K_1=\Omega\cap W(s_1,\theta_1\pm\delta)\cap B(s_1,1500)
$$
其中 $W$ 是角域,$\delta$ 取 $1.005^\circ$ 保守裕量。
然后:
$$
\mathcal{Q}=\left\{q:\max_{g\in K_1}\lVert q-g\rVert\le 1000\right\}
$$
若 $\mathcal{Q}\neq\varnothing$,在其中采样选点,评估最坏后验包围圆半径和移动成本。
若 $\mathcal{Q}=\varnothing$,则退化为:
$$
q^*=\arg\min_q\max_{g\in K_1}\lVert q-g\rVert
$$
即选一个使最坏接收距离最小的点,同时结合交会角筛选。
若 $K_1$ 的外包圆为 $B(c,r)$ 且 $r<1000$,则 $B(c,1000-r)$ 是更简单的充分候选区域。
### 2. 问题4:定向源不要过早依赖 `no_signal` 删点
第4问中,`no_signal` 只说明“当前位置、接收半径、朝向”联合假设下不可见,不能单独排除位置。
基线策略建议:
- 用49点覆盖保证发现;
- 发现后主动测向缩小候选;
- 若失去信号,不再强行靠 `direction` 追踪,而是对当前有界候选集合做20m圆盘覆盖,逐点 `/clear`;
- 若时间允许,再维护朝向可行集合,减少无效检测。
### 3. 现实20分钟:请求数比虚拟时间更关键
49点×20频道最多980次检测,若每次网络延迟0.5–1秒,现实时间可能超过8–16分钟。
建议:
- 已清除频道不再检测;
- 已发现待定位频道可暂停覆盖扫描;
- 共享检测位置:到一个点后顺便测多个未知频道;
- 自适应覆盖:根据 no_signal 覆盖记录跳点,但必须保持证明完整;
- 正式测试前实测接口延迟、日志大小、总请求数。
### 4. 问题1:直径圆覆盖判断可给更明确算法
对凸多边形 $P$:
- 先求直径 $D=\max_{i,j}\lVert v_i-v_j\rVert$;
- 枚举所有顶点对作为候选直径,检查其余顶点是否都在以该对为直径的圆内;
- 若存在一个直径对使所有顶点在圆内,则覆盖;否则不覆盖;
- 但保证清除时不要用直径圆,要用最小包围圆 $\rho(K)\le 20$。
---
## 五、建议的最小可行路线
如果时间不足,按这个顺序做:
1. **P0+P1**:协议、计时、状态更新、幂等重试。
2. **P2**:角域交、直径、最小包围圆。
3. **P3**:问题2候选区域和选点。
4. **P4**:问题3全向闭环,49点覆盖,发现—定位—清除—停止。
5. **P5**:问题4定向扩展,后备清除。
6. **P7**:演练后尽早正式测试。
可删减:P6中的复杂调度、朝向联合维护、学习型策略。
不可删减:覆盖证明、停止条件、协议幂等、日志、正式测试。
---
## 六、结论
现有设计思路**整体可行且偏保守**,适合竞赛中“先保证全清,再优化时间”的目标。
最需要立即补强的是:
1. 问题2中 $K_1$ 和 $\mathcal{Q}$ 的严格定义及空集处理;
2. 问题4中定向源朝向不确定性和 `no_signal` 的正确使用;
3. 现实20分钟窗口下的请求数控制;
4. 正式测试时间安排,务必尽早演练并保留正式机会。
下一步最有价值的工作仍然是:**协议计时基线 + 几何内核 + 全向闭环**。完成这条链路后,再用演练数据决定是否加入加速策略。
+182 -20
View File
@@ -1,29 +1,191 @@
# B题问题一 交会定位 # mcm26b — CUMCM 2026 B题:无线电干扰源的快速自动定位与清除
给定同一干扰源的检测点坐标及带 $\pm 1^\circ$ 误差的示向度,计算前向角域交集、定位区域直径、直径圆覆盖判断与最小包围圆。 统一框架:有界误差几何定位、主动选点、带覆盖证明的搜索、按真实动作耗时调度。
分析依据 `issue/B题.pdf`、附件1《模拟器使用说明》、附件2《通信接口说明及编程指南》。
- [完整中文解答与算法证明](docs/问题一解答.md) - [四问建模分析与 P0–P7 实施计划](docs/B题建模分析与实施计划.md)
- [修订后的四问思路与P0–P7计划](B题建模分析与实施计划.md) - [协议规则表、字段表与状态机(P0 交付)](docs/协议规则表与状态机.md)
- [核心代码](geometry/localization.py) - [问题一完整解答](docs/问题一解答.md)
- [离线交互模拟](output/q1/question1.html) - [问题三搜索与总耗时改进方案(含七点覆盖证明和自建消融)](docs/algo-3.md)
- [官方演练观测与原始记录](output/q1/practice/) - [问题3/4 强化学习选点(PPO + CUDA)](docs/algo-rl.md)
- [优化与舍入敏感性报告](output/q1/optimization_report.json) - [强化学习审核、修复与独立验证(2026-09-11)](docs/强化学习适用性审核与改进-20260911.md)
- [HRL 优化方案与 Sol 执行指南(含当前缺口、命令和验收门槛)](docs/hrl-sol-execution.md)
- [HRL P0+P1 执行报告(本轮实际命令、smoke 与多轮本地测试)](docs/hrl-p1-execution-report.md)
- [论文](docs/paper/main.tex)
Python3.10及以上,核心算法和演示生成无需安装第三方库。 ## 项目结构
```powershell ```
python -m geometry examples/q1/triangle.json referee/ # 独立评测机包(mcm26b-referee):模拟器引擎+机器狗接口+WebUI,
python main.py examples/q1/normal.json -o output/q1/result.json # 零第三方依赖、不依赖本队代码;题意符合性对照见 referee/README.md
python -m geometry examples/q1/normal.json --rounding-margin-deg 0.005 src/mcm26b/
python -m unittest discover -s tests -v ├── config.py # 参数中心:题面常量[题面] + 工程参数[工程],唯一字面量来源
python scripts/build_q1_demo.py ├── protocol/ # P0/P1 字段表、计时模型、状态机、串行幂等客户端(已完工)
python scripts/benchmark_q1.py ├── geometry/ # P2 角域交会、直径、MEC、问题二安全候选盘证书(已完工)
├── belief/ # P3 逐频道候选集合 K_c:保守外包多边形 + 半平面裁剪(已完工)
├── coverage/ # P4 49点覆盖账本(网格生成 + 逐频道记录)
├── planner/ # P3 保证接收盘选点器 / P4 全向闭环 / P5 混合源定向闭环(已完工)
│ # P6b RL 接入:planner/rl_loop.py(PPO 选点,惰性加载 torch)
├── rl/ # P6b 强化学习扩展:训练环境、观测/候选特征、PPO 模型加载(可选依赖)
├── evaluation/ # 日志复算与统计(已完工)
└── harness/ # 测试侧适配:评测机<->Transport 内存回环、故障注入、回放、场景
tests/ # pytest(含解耦守卫:运行时零导入 referee + 规则表不漂移)
scripts/ # 采集、基准、可视化与校核脚本(含问题四批量仿真 benchmark_q4.py、
# RL 训练 train_rl.py 与 RL 配对消融 benchmark_rl.py)
output/ examples/ # 演练证据、算例与生成产物
``` ```
用浏览器打开 `output/q1/question1.html`。可选择合成反例或官方演练,逐个加入测点,切换全景与定位区域放大。 ## 独立评测机与 WebUI(referee/)
输出新增直径圆覆盖反例顶点、最大超出距离和 20 米清除余量;默认仍为题设 $\pm 1^\circ$,舍入裕量须显式启用。最小包围圆使用可复现的随机增量算法,原枚举法保留作独立对照。`geometry.first_bearing_candidate_disk` 提供问题二首次测向安全区域的解析证书;问题二选点优化器及问题三、四的全清闭环仍待实现。 评测机已抽成独立包:`referee/`(uv workspace 成员,`uv sync` 自动挂载为 dev 依赖)。
参赛队运行时代码**零导入** referee,双方仅通过附件2 的 HTTP 协议耦合——
评测机可独立服务任何客户端,参赛队代码对接官方模拟器无需任何改动。
可视化事件检查使用Node.js:`node scripts/verify_visualization.cjs`。可选PNG重绘使用Pillow及Windows微软雅黑字体:`python scripts/render_q1_figures.py`;这些只用于图形校核,不是核心求解依赖。 ```bash
uv run python -m referee # WebUI http://127.0.0.1:8026,接口 :2026
uv run python -m referee --port 2026 --ui-port 8026 --data-dir referee-data
uv run mcm26b run --robot-id 2026001 --local-judge # 一键:起评测机→开演练局→闭环→汇总
```
本项目只使用官方**演练**采集了问题一所需观测,未使用正式测试。采集器不会启动测试,必须先在界面确认“问题3演练”、接口已就绪,再提供 `--practice-confirmed` 和本局案例编码。参见完整解答中的采集说明。 - **WebUI 完全按附件1 §4 复现官方界面语义**:四个测试模块(演练不限次/正式各3次、
启动即占用、正式前再次确认)、确认开始→数据准备→5秒倒计时→25分钟窗口开放接口、
"指令与反馈"默认最新1000条(100..5000 可调)、中止测试两次确认、结束原因显示、
案例编码、演练结束显示 总数/全向/定向(正式任何界面不显示真值)、行为日志导出
(2MB 上限告警)、空闲时可改端口、只监听本机回环。
- **回放器**("回放"Tab):以本局行为日志 JSONL 驱动,在 Ω 圆上动画复现运动与
扫描过程——移动按 5m/s 展开、检测以雷达扫描动画呈现(direction 附实测示向度
射线)、清除先光学定位再清除;支持播放/暂停、逐步±、1×~300× 倍速快进、
滚轮缩放/拖拽平移、带动作刻度的进度条任意定位;兼容 CSV 式逐事件信息面板。
**支持手动选定 JSONL 回放**:点击"选择 JSONL 文件"或直接拖拽导入任意行为日志
(评测机日志含真值;参赛队客户端会话日志取 accepted 事件,无真值),纯前端解析。
- 引擎与协议:`referee.simulator`(观测判定/幂等/并发409/微秒计时/截止断连)、
`referee.interface`(附件2 §5 完整语法边界,HTTP 服务器与内存直连共用),
一致性由 `referee/tests` 90 项测试与真实 HTTP 测试固化。
- 自建差异(题面未规定)均在 referee/README.md 声明:联网登录/官方校时/17:30
截止/加密上传属官方服务器侧策略,本地不实现;示向度误差场与场景分布是测试假设。
## 快速开始
Python ≥ 3.10,运行时依赖仅 `requests`;测试/自检另需 `pytest` 与独立评测机
包(`uv sync` 一并安装)。
```bash
uv sync # 安装(可编辑挂载本包与 referee)
uv sync --group rl --group dev # 追加 RL 依赖:torch(CUDA)+stable-baselines3+gymnasium
uv run pytest # 全部测试(含 referee 90 项 + 解耦守卫)
uv run python -m referee # 起本地评测机(可选,配合 WebUI 回放)
uv run mcm26b sim-check # P0 自检:复现附件计时示例 105/111/194/199
uv run mcm26b run --robot-id 2026001 --self-test # 问题3自检:随机全向场景闭环(不连官方)
uv run mcm26b run --robot-id 2026001 --self-test --problem 4 # 问题4自检:混合定向源场景
# RL 策略(需先安装 rl 依赖组并训练模型;详见 docs/algo-rl.md):
uv run python scripts/train_rl.py --problem 3 --timesteps 120000 # PPO + CUDA 训练 Q3 选点
uv run python scripts/pretrain_rl_expert.py --problem 4 --episodes 3000 # 自建模拟器专家行为克隆
uv run python scripts/train_rl.py --problem 4 --timesteps 40000 --init output/rl/q4_ppo_bc_init.zip
uv run mcm26b run --robot-id 2026001 --self-test --strategy rl # 问题3 RL 闭环
uv run mcm26b run --robot-id 2026001 --self-test --problem 4 --q4-strategy rl # 问题4 RL 闭环
uv run python scripts/benchmark_rl.py --seeds 5 # RL vs 手写策略配对消融
uv run python scripts/verify_rl_practice.py output/rl/official-practice/q4/20260911-rl-bc-01
uv run python scripts/benchmark_hrl.py --variants hrl_heuristic,bayes,directional \
--manifest output/hrl/manifests/dev.json --output output/hrl/p1-heuristic
uv run python scripts/train_hrl_high.py --problem 3 --stage 1 --timesteps 2048 \
--envs 1 --vec-env dummy --device mps --config-profile production \
--reward-profile time --model output/hrl/p1-smoke/q3.zip --eval-episodes 2
# 训练前端(本地回环 Web UI):实时进程/进度/参数收敛曲线,详见 docs/training-ui.md
uv run python -m mcm26b.training_ui --ui-port 8036 # http://127.0.0.1:8036
uv run mcm26b run --robot-id 2026001 --self-test --strategy hrl \
--hrl-model output/hrl/p1-smoke/q3.zip --hrl-device mps
# 自检默认:源数按题面 10~16 随机;实机预算 30 分钟(--real-budget-s 可改,仅自检生效);
# 找全后持续复扫未清除频道直到限时(--config 关闭 persistent_search 可回到"找全即退")
uv run mcm26b run --robot-id <队号> --log output/run/session.jsonl # 对接模拟器正式/演练
uv run mcm26b run --robot-id <队号> --base-url http://127.0.0.1:2026 # 对接本地 referee
uv run mcm26b run --robot-id 2026001 --local-judge # 一键本地评测:自动起 referee+开演练局
# 端口被占时主动询问换端口(非交互自动改空闲端口);WebUI 可实时观战并在"回放"Tab
# 逐步回看;结束自动汇总结束原因/真值统计/全清校验(--judge-no-ui 可关闭界面)
uv run mcm26b q1 examples/q1/normal.json # 问题一求解(等价 python -m mcm26b.geometry ...)
uv run python main.py examples/q1/triangle.json --rounding-margin-deg 0.005
```
## 问题一(P2,已完工)
给定同频道多个检测点及 ±1° 误差示向度,计算前向角域交集(半平面交)、
定位区域直径、直径圆覆盖判断(含反例顶点与超出距离)与最小包围圆、20m 清除余量。
```bash
uv run mcm26b q1 examples/q1/normal.json -o output/q1/result.json
uv run python scripts/build_q1_demo.py # 重建离线交互可视化 output/q1/question1.html
uv run python scripts/benchmark_q1.py # MEC 基准与舍入敏感性
```
离线交互页:`output/q1/question1.html`。可选 PNG 重绘需要 Pillow 与 Windows
雅黑字体:`python scripts/render_q1_figures.py`;事件校核需要 Node.js:
`node scripts/verify_visualization.cjs`。二者仅为图形校核,非求解依赖。
## 协议基线(P0/P1,已完工)
- `protocol.rules`:四条指令的字段表、结果码与错误语义(可执行表格);
- `protocol.timing`:纯计时模型,逐步复现附件示例 105/111/194/199;
- `protocol.state.RobotState`:位置/频道/虚拟时刻状态机;accepted=false 不更新,
`/clear` 不切频道,虚拟时刻以 accepted 响应为准;
- `protocol.client.SimulatorClient`:串行发送、幂等重试(同 ID 同内容原样重发)、
连接/读超时、基于 `remaining_real_duration_s` 的本地截止时钟与退出预留、JSONL 会话日志;
- 独立包 `referee`:按附件语义复现评测机(观测门限、定向覆盖角、幂等回放、
整数微秒计时、现实/虚拟截止、并发409和请求校验),真值只对评测机/测试端开放;
`harness.LocalSimTransport` 内存回环挂载(与 referee HTTP 服务器共用同一边界),
`harness.ScriptedFaultTransport` 注入断连/超时/500,`harness.PlaybackTransport`
回放官方演练日志。
本地模拟器默认执行至多1200秒程序预算、1500秒接口开放窗口,截止后通过
`SimulatorClosed` 模拟连接关闭,已登记动作可以完成。可注入 `clock`、`wall_clock`
和 `window_started_at` 测试迟到与超时。CLI `--self-test` 显式使用 `stress_mode=True`,
保留默认1800秒压力预算并扩展窗口;这不是官方演练时限。
内存传输不实现TCP连接限流、UI或日志上传;场景均匀分布及逐点哈希误差仍是测试假设。
```python
from mcm26b.protocol import SimulatorClient
client = SimulatorClient("参赛队号") # 默认 http://127.0.0.1:2026
client.enter()
outcome = client.measure((300, 400), 1) # MeasureOutcome(result, svd_deg, ...)
client.exit()
```
## 阶段状态(对照 P0–P6 计划)
| 阶段 | 状态 |
| --- | --- |
| P0 规则固定(规则表/状态机/字段表,示例逐步 105/111/194/199) | ✅ 完成 |
| P1 协议基线(客户端 + 自建回放/故障注入测试) | ✅ 完成 |
| P2 几何内核(角域交、直径、MEC、证书) | ✅ 完成(迁入 `mcm26b.geometry`) |
| P3 问题二选点(K1、候选区域 Q、采样评估) | ✅ 完成(belief + 选点器,测试固化) |
| P4 问题3全向闭环(49点覆盖、定位队列、清除、停止) | ✅ 官方问题3演练单案例通过(10/10全清,[验证报告](output/q3/practice/20260911-port2026/report.md)) |
| P5 问题4定向扩展(联合约束、后备清除、预算) | ✅ 自建完成(官方演练待执行) |
| P6 加速与消融 | ✅ 七点批量(`--strategy seven`,官方演练 12/12)+ 贝叶斯闭环(`--strategy bayes` 默认,自建消融 −30.0%,[算法说明](docs/algo-3-bayes.md)) |
| P6b RL 选点 | ✅ PPO+CUDA 训练环境/闭环接入/官方+自建演练验证/专家 BC 初始化(Q3 `--strategy rl`,Q4 `--q4-strategy rl`,[算法说明](docs/algo-rl.md)) |
## 采集与正式测试约束
改进版 A2(七点覆盖+本站批量扫频)已通过官方案例 `J4ER-Y9EP-Q379-UPFA`:
12/12源全清,109次检测,虚拟耗时5232.132109秒,现实耗时3.406秒。
[本局报告与运行方法](output/q3/practice/20260911-seven-batch-01/report.md)。
独立入口为 `scripts/run_q3_seven_practice.py`。
贝叶斯闭环 `bayes`(网格粒子滤波+负观测更新+信息增益选点+滚动 2-opt
调度,参数经 Optuna 回填)在自建模拟器配对消融中相对 SevenBatch 平均
虚拟时间再降 30.0%(14/14 场景全清零异常),算法与数据见
[algo-3-bayes.md](docs/algo-3-bayes.md),已是 `mcm26b run` 默认策略。
虚拟时间即成绩口径:找全证明后立即 `/exit`(`--persistent` 可显式开启
"扫到限时"的复扫保险模式)。
2026-09-11 已通过本机 2026 端口完成一次官方问题3演练:案例
`DHFK-PHD2-SR2P-FXK9`,10/10 源全清,540 次检测、10 次清除,现实耗时
7.629 秒。原始请求响应、官方产物及离线审计见上述验证报告。原计时复算的
541 处微秒精度误报也已记录;按官方整数微秒累计规则独立复算后,552 个
响应时刻全部吻合。生产计时复算函数保持原样。
```bash
uv run python scripts/verify_q3_practice.py output/q3/practice/20260911-port2026
```
本项目只使用官方**演练**采集观测,从未使用正式测试。`scripts/capture_practice.py`
不会启动测试:必须先在界面确认“问题3演练”、接口已就绪,再提供
`--practice-confirmed` 与本局案例编码。正式测试由团队按计划另行安排;
加密日志上传上限 2MB,程序避免异常高频循环。
@@ -187,13 +187,14 @@ AI 的适合用法是把这些模块逐一变成可测试程序、生成边界
| 阶段 | 交付与执行任务 | 验收门槛 | 当前状态 | | 阶段 | 交付与执行任务 | 验收门槛 | 当前状态 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| P0 规则固定 | 规则表、状态机、四类API字段与成本 | 示例逐步105/111/194/199秒;clear不切换频道 | 已核对规则,完整状态机待工程化 | | P0 规则固定 | 规则表、状态机、四类API字段与成本 | 示例逐步105/111/194/199秒;clear不切换频道 | 已完成:`protocol/rules+timing+state` 工程化,`sim-check` 与 `tests/test_protocol_timing.py` 固化 |
| P1 协议基线 | enter/measure/clear/exit客户端;串行、幂等、截止时间 | accepted=false和超时重试不污染状态;主动退出;故障注入回放 | 已有少量测向采集器及真实计时回放;完整客户端待实现 | | P1 协议基线 | enter/measure/clear/exit客户端;串行、幂等、截止时间 | accepted=false和超时重试不污染状态;主动退出;故障注入回放 | 已完成:`protocol/client`,`ScriptedFaultTransport`/`PlaybackTransport` 回放,`tests/test_protocol_client.py` 全过 |
| P2 几何内核 | 问题一解答、区域分类、直径圆证据、MEC、清除余量 | 跨界、退化、无界、解析反例、独立算法对照 | 已实现并优化,20项自动化测试通过 | | P2 几何内核 | 问题一解答、区域分类、直径圆证据、MEC、清除余量 | 跨界、退化、无界、解析反例、独立算法对照 | 已实现并优化,20项自动化测试通过 |
| P3 问题二选点 | $K_1$ 先验、安全候选盘、后验半径采样与 `near` 分支 | 距离证书有效;采样加密;不把探索当接收保证 | 解析非空证明及证书已实现;选点器与实验待实现 | | P3 问题二选点 | $K_1$ 先验、安全候选盘、后验半径采样与 `near` 分支 | 距离证书有效;采样加密;不把探索当接收保证 | 已实现:`belief` 保守候选集 + `planner` 保证接收盘选点器(worst-posterior 采样、1/4 间距加密复核);策略对比实验待做 |
| P4 全向闭环 | 49点覆盖记录、定位队列、清除、停止、日志统计 | 10/16源、边界源和错误响应案例;官方演练全清并正常退出 | 待实现 | | P4 全向闭环 | 49点覆盖记录、定位队列、清除、停止、日志统计 | 10/16源、边界源和错误响应案例;官方演练全清并正常退出 | 自建闭环已完成:`planner.OmnidirectionalLoop`(10/16/0 源、近边界源、预算耗尽、故障注入测试通过);官方演练全清待团队执行 |
| P5 定向扩展 | no_signal联合约束、覆盖发现、有限清除后备与预算 | 朝外边界源不漏;真源不误删;格数与退出预算检查 | 已有证明和设计;闭环待实现 | | P5 定向扩展 | no_signal联合约束、覆盖发现、有限清除后备与预算 | 朝外边界源不漏;真源不误删;格数与退出预算检查 | 已实现:`planner.DirectionalExtension`(49点覆盖对定向源成立、保证接收盘内 no_signal 记为观测到定向、对跖+环探梯子、`fallback_clear_cells` 有限圆盘覆盖后备清除带格数/预算双硬顶);`tests/test_loop_q4.py` 全过;官方混合源演练待执行 |
| P6 加速消融 | 共享测点、自适应覆盖、目标排序、提前清除 | 配对案例全清不退化,时间/请求数改善可复算 | 可删减;复杂学习与朝向搜索后置 | | P6 加速消融 | 共享测点、自适应覆盖、目标排序、提前清除 | 配对案例全清不退化,时间/请求数改善可复算 | 可删减;闭环基线数据已可用于消融对照 |
| P6b RL 选点 | 问题3/4 测量点选择的 PPO+CUDA 训练环境与闭环接入 | 自建全清;与手写策略配对消融有可复算报告 | 已完成:`scripts/train_rl.py`/`benchmark_rl.py`,模型 `output/rl/q{3,4}_ppo.zip`,说明 `docs/algo-rl.md` |
| P7 正式与论文 | 固定版本、论文表1、日志原名、上传核查 | 问题3/4各3份正式记录与程序版本对应 | 团队后续安排;本任务不执行正式测试 | | P7 正式与论文 | 固定版本、论文表1、日志原名、上传核查 | 问题3/4各3份正式记录与程序版本对应 | 团队后续安排;本任务不执行正式测试 |
按2026年9月10日起的剩余时间,建议10日补齐P1并衔接P3,11日完成P4自建边界案例与全向演练,12日完成P5及混合源演练;未达验收就删减P6并优先修正闭环。演练不限3次,正式机会为问题3和4各3次。团队在版本稳定后自行安排正式记录,留出失败恢复和论文整理时间。附件建议9月13日15:30前完成正式测试,17:30后不能启动新的演练或正式测试;已进入上传队列的日志仍会继续上传。此处引用所给附件安排,运行前核对模拟器界面公告;这份排期不改变当前禁止使用正式测试的限制。 按2026年9月10日起的剩余时间,建议10日补齐P1并衔接P3,11日完成P4自建边界案例与全向演练,12日完成P5及混合源演练;未达验收就删减P6并优先修正闭环。演练不限3次,正式机会为问题3和4各3次。团队在版本稳定后自行安排正式记录,留出失败恢复和论文整理时间。附件建议9月13日15:30前完成正式测试,17:30后不能启动新的演练或正式测试;已进入上传队列的日志仍会继续上传。此处引用所给附件安排,运行前核对模拟器界面公告;这份排期不改变当前禁止使用正式测试的限制。
@@ -210,4 +211,28 @@ AI 的适合用法是把这些模块逐一变成可测试程序、生成边界
可复现报告见 `output/q1/optimization_report.json`,问题一证明、输入输出及数值限制见 `docs/问题一解答.md`。局部MEC基准只反映本地几何计算,不能据此宣称请求延迟、完整策略或官方成绩得到同样提升。 可复现报告见 `output/q1/optimization_report.json`,问题一证明、输入输出及数值限制见 `docs/问题一解答.md`。局部MEC基准只反映本地几何计算,不能据此宣称请求延迟、完整策略或官方成绩得到同样提升。
下一步优先补齐P1完整协议与故障回放,再实现P3选点器并接入P4“发现—定位—清除—证明完成—退出”闭环。P2已经具备可复用输入输出;不要重复开发几何内核或提前堆叠学习算法。以全向演练的实际请求、日志和耗时决定P5后备规模与P6加速投入。 P0–P5(自建部分)与 P2 均已交付:协议层(串行幂等客户端、状态机、预算截止、
故障回放)、几何内核、belief 保守候选集、保证接收盘选点器、`OmnidirectionalLoop`
全向闭环与 `DirectionalExtension` 混合源定向闭环(49 点覆盖对定向源同样成立、
no_signal 联合约束基线不删候选、对跖+环探遮挡梯子、`fallback_clear_cells`
有限圆盘覆盖后备清除,格数与现实预算双硬顶下不盲扫)。自建验收:
`uv run pytest`(105 项)与 `uv run mcm26b sim-check`;随机场景自检:
`uv run mcm26b run --robot-id <队号> --self-test`(问题4加 `--problem 4`)。
评审修订(2026-09-11):本地模拟器改为逐点固定误差场(同一"源×位置"读数
恒定,与官方演练实测一致);对跖复核探点公式修正(此前塌缩到 MEC 圆心 1m
内,浪费探点预算并推高后备清除);环探"≥180° 可见弧"依据删除(最坏可见弧
可退化为单点,梯子只是启发式,完备性由后备清除兜底);断连/协议错误中断后
仍尽力 /exit 并产出未完成 summary;库默认舍入裕量统一为 0.005°;后验评分
补 near 分支;问题一近平行细长区域保留远端顶点。后备清除成本用
`scripts/benchmark_q4.py` 批量种子扫描量化(结果落盘 `output/q4/`)。
下一步优先把两个闭环接入官方演练(问题3用全向、问题4用混合,先实测单请求
延迟与总请求数,核对 1200s 现实预算与 2MB 日志体积),再做 P6 消融对照。
顺序约束:上述模拟器与故障收尾修复先行合入,官方演练在修复后的版本上执行;
总请求口径必须计入后备清除(summary 的 `total_requests` 与
`fallback_clear_attempts`),仅统计检测次数会低估现实耗时。
基线量级供参照:10 源场景约 550–630 次检测、虚拟总时 1.4–1.7 万秒;16 源
场景约 200–320 次检测即触发数量上界停止。该数字说明共享测点与跳点策略
(P6)有明确改进空间。不要重复开发几何内核或提前堆叠学习算法;以官方演练
的实际请求、日志和耗时决定 P6 加速投入。
+191
View File
@@ -0,0 +1,191 @@
# 2026 高教社杯 B 题(无线电干扰源快速自动定位与清除)问题 3、4 相关论文列表
> 排序原则:与问题 3/4 直接应用方案越相关,排名越靠前。
> 标注:【Q3】主要支撑问题 3(全向干扰源:搜索→交会定位→逼近清除的整体策略);【Q4】主要支撑问题 4(定向干扰源、方向未知);【Q3·Q4】两者通用。
---
## 一、无线电信号源的移动机器人搜索与定位(与赛题任务框架最直接对应)
1. **Simultaneous Localization of Multiple Unknown and Transient Radio Sources Using a Mobile Robot** 【Q3】
D. Song, C. Y. Kim, J. Yi. *IEEE Transactions on Robotics*, 2012(被引 75)
移动机器人沿路径采集 RSS,在线同时定位**多个未知无线电源**——与问题 3“干扰源个数未知、机器狗边走边测”的设定几乎同构,可直接借鉴其多源数据关联与定位框架。
https://ieeexplore.ieee.org/abstract/document/6145760/ | [PDF](http://coewww.rutgers.edu/~jgyi/pdfs/IEEE_TRO_2012.pdf)
2. **Cooperative Search of Multiple Unknown Transient Radio Sources Using Multiple Paired Mobile Robots** 【Q3】
C. Y. Kim, D. Song, Y. Xu, J. Yi, X. Wu. *IEEE Transactions on Robotics*, 2014(被引 67)
上文的协同多机器人版本:成对机器人搜索多个未知瞬态无线电源,含**源匿名(信号不可区分)**处理——对应本题不同频道区分信号的思路对照。
https://ieeexplore.ieee.org/abstract/document/6857360/ | [PDF](https://jingangyi.rutgers.edu/pdfs/IEEE_TRO_2014.pdf)
3. **RSS Gradient-Assisted Frontier Exploration and Radio Source Localization** 【Q3·Q4】
J. N. Twigg, J. R. Fink, L. Y. Paul, B. M. Sadler. *ICRA*, 2012(被引 77)
用 RSS 梯度引导前沿探索(frontier exploration),让机器人高效逼近信号源而避免盲目遍历——可直接支撑问题 3/4 中“初探→逼近”的两阶段搜索策略设计。
https://ieeexplore.ieee.org/abstract/document/6225059/
4. **Radio Source Localization Using Sparse Signal Measurements from Uncrewed Ground Vehicles** 【Q3】
A. Perera, V. P. Tran, S. Anavatti, K. Kasmarik, et al. *arXiv:2312.03493*, 2023
地面无人车(与机器狗同类平台)在室外区域以稀疏采样定位无线电源,含完整仿真评估流程——与用模拟器演练测试的实验设计直接可参照。
https://arxiv.org/abs/2312.03493 | [PDF](https://arxiv.org/pdf/2312.03493)
5. **Particle Filter Based Localization of Access Points Using Direction of Arrival on Mobile Robots** 【Q3·Q4】
R. Parashar, R. Parasuraman. *IEEE VTC*, 2020(被引 13)
移动机器人利用**到达方向(DOA,即示向度)**+ 粒子滤波递推定位无线电源——对应本题“多次测向→逐步缩小定位区域”的序贯定位算法。
https://ieeexplore.ieee.org/abstract/document/9348813/
6. **Online Methods for Radio Signal Mapping with Mobile Robots** 【Q3】
J. Fink, V. Kumar. *ICRA*, 2010(被引 166)
移动机器人边走边在线构建信号场强地图并估计源位置,可支撑本题“场强仅随距离衰减”假设下的快速粗定位与路径在线修正。
https://ieeexplore.ieee.org/abstract/document/5509574/
7. **Distributed Algorithms for Stochastic Source Seeking with Mobile Robot Networks** 【Q3】
N. A. Atanasov, J. Le Ny, et al. *ASME JDSMC*, 2015(被引 117)
随机源搜索的分布式算法,以无线电源定位为应用背景,理论保证强,可作为逼近清除阶段的收敛性依据。
https://arxiv.org/pdf/1402.0051
8. **Cooperative Multi-Robot Estimation and Control for Radio Source Localization** 【Q3】
B. Charrow, N. Michael, V. Kumar. *IJRR*, 2014(被引 84)
仅测距射频下的多机器人协同估计与控制,信息论驱动( mutual information )选择测量动作——可迁移为“选哪个频道、去哪测”的决策准则。
https://journals.sagepub.com/doi/abs/10.1177/0278364913500542
9. **A Review of Radio Frequency Based Localisation for Aerial and Ground Robots with 5G Future Perspectives** 【Q3·Q4】
M. Kabiri, C. Cimarelli, H. Bavle, et al. *Sensors*, 2022(被引 48)
综述:RSS/AOA 等 RF 定位手段在空地机器人上的比较,适合写论文的“研究现状”部分并帮助选型。
https://www.mdpi.com/1424-8220/23/1/188
---
## 二、测向(Bearing-only/AOA)交会定位与观测点优化(第二检测点选择、定位区域收缩)
10. **Gathering Bearing Data for Target Localization** 【Q3】
H. Bayram, J. Vander Hook, V. Isler. *IEEE Robotics and Automation Letters*, 2016(被引 38)
给定若干潜在目标区域与不确定度要求,规划采集方位数据的机器人路径,归结为 **TSP with Neighborhoods 的信息路径规划**——与问题 3“多个待清除目标 + 逐个交会定位 + 总时间最短”的任务排序高度吻合。
https://ieeexplore.ieee.org/abstract/document/7390217/ | [PDF](https://conservancy.umn.edu/bitstreams/ff2d34bf-0056-4a29-be84-eb7355b527e4/download)
11. **Relationship Between Error Ellipse and Error Quadrilateral in Bearing-Only Localization** 【Q3·Q4】
B. Wang, Y. Hu, C. Yu, et al. *IEEE Access*, 2026
直接研究双站测向定位的**误差四边形**(即题目中的“定位区域”)与误差椭圆的关系,论证几何构型与精度的关系——与问题 1 的定位区域、问题 2/3 的测点选择理论完全对口。
https://ieeexplore.ieee.org/abstract/document/11677056/
12. **Bearing-Only Active Target Localization Strategies for a System of Two Communicating Mobile Robots** 【Q3】
J. Vander Hook, P. Tokekar. 技术报告, 2013
主动测向定位:规划“去哪测”以最优压缩目标位置不确定性,给出最优双机器人测量构型——第二检测点选择策略的系统性理论。
https://conservancy.umn.edu/items/38693c39-7a3b-400b-8926-f9aa194a8824
13. **Multi-UAV Trajectory Optimization for Bearing-Only Localization in GPS Denied Environments** 【Q3】
A. Sciacchitano, L. Mudrik, S. Kragelund, et al. *arXiv:2602.11116*, 2026
面向测向定位的轨迹优化,在视场等约束下优化测量构型——可借鉴其代价函数与滚动优化框架设计机器狗的测点序列。
https://arxiv.org/abs/2602.11116 | [PDF](https://arxiv.org/pdf/2602.11116)
14. **Optimal Sensor Placement for Multi-Source AOA Localisation with Distance-Dependent Noise Model** 【Q3·Q4】
M. Hamdollahzadeh, R. Amiri, et al. *IET Radar, Sonar & Navigation*, 2019(被引 37)
**多源** AOA 定位的最优布点,含递推 CRLB 表示——支撑多干扰源场景下测点位置的全局优化。
https://ietresearch.onlinelibrary.wiley.com/doi/abs/10.1049/iet-rsn.2018.5426
15. **Optimal Sensor Placement for Target Localization Using Hybrid RSS, AOA and TOA Measurements** 【Q3】
S. Xu, et al. *IEEE Communications Letters*, 2020(被引 110)
混合量测下最小化 tr(CRLB) 的最优传感器-目标几何,可用于论证“交会角接近 90°”等构型结论的严谨性。
https://ieeexplore.ieee.org/abstract/document/9097832/
16. **Geometry Influence on GDOP in TOA and AOA Positioning Systems** 【Q3·Q4】
X. Lv, K. Liu, P. Hu. *ICNSC*, 2010(被引 58)
基于 CRLB 分析新增观测点对 GDOP 的影响——回答“再加一个检测点值不值、放在哪”的定量依据。
https://ieeexplore.ieee.org/abstract/document/5480336/
17. **定向交叉定位配站问题与定位精度分析**(中文)【Q3·Q4】
张艳花. 《电讯技术》, 2008(被引 2)
中文文献,专门讨论测向交叉定位的配站(交会角)与精度关系,便于直接引用“交会角 90° 最优、30°~150° 可用”类结论。
(《电讯技术》2008 年刊,可通过知网/万方检索全文)
18. **Trajectory Planning for Multiple Robots in Bearing-Only Target Localisation** 【Q3】
C. Leung, S. Huang, G. Dissanayake, et al. *IROS*, 2005(被引 16)
早期经典:以定位精度为目标做测向机器人轨迹规划,适合作为主动定位问题的建模起点引用。
https://ieeexplore.ieee.org/abstract/document/1545322/
19. **Observer Path Planning for Bearings-Only Localization Considering Limited Field of View** 【Q3】
A. Nayebi Astaneh, N. Pariz, M. O. Naghibi Sistani. *Journal of Control*, 2014
考虑传感器视场约束的观测者实时路径规划——对应测向机需旋转天线搜索示向度的过程约束。
https://joc.kntu.ac.ir/browse.php?a_id=37&sid=1&slc_lang=en&ftxt=1
---
## 三、多目标搜索理论与任务规划(10–16 个未知目标的区域搜索框架)
20. **Multi-Vehicle Bayesian Search for Multiple Lost Targets** 【Q3·Q4】
E. M. Wong, F. Bourgault, T. Furukawa. *ICRA*, 2005(被引 193)
多目标贝叶斯搜索经典:概率图 + 贝叶斯更新 + 搜索资源分配——问题 3“干扰源个数未知、需确保全部清除”的终止判据与覆盖率论证可由此构建。
https://ieeexplore.ieee.org/abstract/document/1570598/
21. **MPC-Based Cooperative Multiagent Search for Multiple Targets Using a Bayesian Framework** 【Q3】
H. Xiao, R. Cui, D. Xu, Y. Li. *Journal of Field Robotics*, 2024(被引 9)
模型预测控制 + 贝叶斯框架的多目标搜索路径规划,滚动时域决策——适合借鉴为本题“边测边重规划”的在线策略。
https://onlinelibrary.wiley.com/doi/abs/10.1002/rob.22382
22. **Multi-Agent Informed Path Planning Using the Probability Hypothesis Density** 【Q3·Q4】
J. Olofsson, G. Hendeby, T. R. Lauknes, T. A. Johansen. *Autonomous Robots*, 2020(被引 27)
用 PHD(随机有限集)表示**目标个数与位置均未知**的场景并做信息路径规划——与“干扰源总数 10–16 但具体未知”的设定直接对应。
https://link.springer.com/article/10.1007/s10514-020-09904-1 | [PDF](https://torarnj.folk.ntnu.no/AURO2020a.pdf)
23. **Probabilistic Search for Tracking Targets: Theory and Modern Applications** 【Q3·Q4】
E. Kagan, I. Ben-Gal. Wiley, 2013(被引 27)
搜索论专著:最优搜索策略、马尔可夫决策模型,为搜索策略提供理论根基(Stone 最优搜索理论的应用版)。
https://onlinelibrary.wiley.com/doi/abs/10.1002/9781118596593
24. **Efficient Multi-Robot Search for a Moving Target** 【Q3】
G. Hollinger, S. Singh, J. Djugash, A. Kehagias. *IJRR*, 2009(被引 254)
多机器人高效搜索路径规划(ESPP)并提出可证明性能的近似算法;本题目标虽静止,其“最大化截获概率”的建模与保证思路可迁移。
https://journals.sagepub.com/doi/abs/10.1177/0278364908099853
---
## 四、定向干扰源定位(问题 4 特有:覆盖角 180°、方向未知)
25. **UAV-Based Efficient Joint Estimation of Directional Emitter Position and Transmission Orientation** 【Q4】
T. Ruan, Y. Huang, L. Zhou, Q. Wu, et al. *IEEE Wireless Communications Letters*, 2024(被引 2)
**联合估计定向发射源的位置与发射方向**(RSS-AOA 混合量测)——问题 4“定向方向未知”的最直接对应文献。
https://ieeexplore.ieee.org/abstract/document/10802920/
26. **Efficient Localization of Directional Emitters via Joint Beampattern Estimation** 【Q4】
F. Williams, A. Pemasiri, D. Jayalath, T. Martin, et al. *arXiv:2411.04364*, 2024
联合波束方向图估计实现定向发射源高效定位,并分析波束宽度/朝向对定位的灵敏度(CRLB)——可支撑定向源需从侧向多点探测的策略设计。
https://arxiv.org/abs/2411.04364 | [PDF](https://arxiv.org/pdf/2411.04364)
27. **Location Errors of Directional Emitters in AOA System for Non-Line-of-Sight Conditions** 【Q4】
J. M. Kelner, C. Ziółkowski, et al. *SPIE*, 2019
分析发射天线朝向对 AOA 示向度误差的影响——定向干扰源场景下误差建模的参考。
https://www.spiedigitallibrary.org/conference-proceedings-of-spie/11055/110551G/Location-errors-of-directional-emitters-in-AOA-system-for-non/10.1117/12.2525060.short
28. **ALRD: AoA Localization with RSSI Differences of Directional Antennas for Wireless Sensor Networks** 【Q4】
J. R. Jiang, C. M. Lin, F. Y. Lin, et al. *Int. J. of Distributed Sensor Networks*, 2013(被引 133)
利用定向天线朝向差分的 RSSI 做定位,对“信号只在 180° 覆盖角内可被接收”的探测盲区分析与补盲路径设计有参考价值。
https://journals.sagepub.com/doi/abs/10.1155/2013/529489
---
## 五、信息路径规划方法与综述(通用方法库)
29. **Information-Driven Path Planning** 【Q3·Q4】
S. Bai, T. Shan, F. Chen, L. Liu, B. Englot. *Current Robotics Reports*, 2021(被引 53)
信息驱动路径规划综述,梳理目标函数(信息增益、熵减)与平台约束,适合搭建问题 3 的总体算法框架。
https://link.springer.com/article/10.1007/s43154-021-00045-6
30. **Adaptive Informative Path Planning in Metric Spaces** 【Q3】
Z. W. Lim, D. Hsu, W. S. Lee. *IJRR*, 2016(被引 101)
带自适应性的信息路径规划,具次模性与近似保证——为“总时间越短越好”的目标函数设计提供理论工具。
https://journals.sagepub.com/doi/abs/10.1177/0278364915596378
31. **Informative Path Planning for Active Field Mapping Under Localization Uncertainty** 【Q3】
M. Popović, T. Vidal-Calleja, J. J. Chung, et al. *ICRA*, 2020(被引 62)
不确定性感知的信息路径规划,平衡探索与精度——对应本题“检测耗时 vs 路径耗时”的权衡。
https://ieeexplore.ieee.org/abstract/document/9197034/
32. **基于深度强化学习的短波自主检测与定位方法**(中文)【Q3】
冯祺玥, 唐涛, 张昀普, 王鼎, 吴志东. 《通信学报》, 2026
中文文献:多站测角交会定位 + 深度强化学习自主检测定位,提供国内无线电监测定位的表述与流程范式。
https://www.joconline.com.cn/rc-pub/front/front-article/download/155129217/lowqualitypdf/%E5%9F%BA%E4%BA%8E%E6%B7%B1%E5%BA%A6%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0%E7%9A%84%E7%9F%AD%E6%B3%A2%E8%87%AA%E4%B8%BB%E6%A3%80%E6%B5%8B%E4%B8%8E%E5%AE%9A%E4%BD%8D%E6%96%B9%E6%B3%95.pdf
---
### 使用建议
- **问题 3 算法主线**:以 1、3、10、20、22 为核心——贝叶斯概率图搜索(20/22)确定探测顺序与终止条件,DOA 序贯定位(5)+ 交会几何优化(10/11/15/17)选测点,RSS 梯度逼近(3)完成 20 m 内清除前逼近。
- **问题 4 增量**:在问题 3 框架上叠加 25/26 的“位置 + 方向”联合估计,并用 28 的思路设计覆盖角盲区的补测路径。
- **论文写作**:现状综述引用 9、29、32;精度理论引用 11、14、15、16。
+185
View File
@@ -0,0 +1,185 @@
# 问题一:有界测向误差下定位区域的直径与圆覆盖
## 摘要
针对同一干扰源在多个检测点处的带误差方位观测,建立前向角域交集模型,将定位区域表示为二维线性不等式组的可行域。首先推导角域的半平面表达,给出兼顾空集、点、线段和无界区域的几何构造算法;随后证明,有界定位区域的直径必由一对顶点取得,且判断是否存在直径等于区域直径的覆盖圆,只需检验任意一组最远顶点的中点。通过符合题设测向条件的等边三角形反例,说明直径圆一般不能覆盖定位区域。进一步以最小包围圆连接定位精度和后续清除条件,并给出算法复杂度、数值处理原则及既有演练观测的复算结果。全部结论以有界误差模型为前提,不引入误差独立、正态或均匀分布假设。
**关键词:** 交会定位;有界误差;半平面交;凸多边形直径;最小包围圆。
## 1. 问题界定与思路来源
题目要求由若干检测点坐标及同一干扰源的示向度,求交会定位多边形的直径,并判断以该直径为直径的圆能否覆盖定位区域。题面规定测向误差在 $[-1^\circ,1^\circ]$ 内,同一地点重复测量的误差不变;示向度从正东沿逆时针方向计量。[题面第1页、附录2第(1)、(3)项](C:/Users/HelixCopex/code/MATH/issue/B题.pdf)
由此得到三步建模思路。第一,单次观测不能确定一条精确射线,却可以确定一个包含真实方向的角域,因此采用集合相交而非直线最小二乘。第二,角域可以写成半平面交,问题随之转化为凸几何问题。第三,“两点最远距离”和“覆盖全部位置所需半径”是不同的优化量,应分别计算直径和最小包围圆。
半平面、凸组合和凸集交运算属于标准凸分析工具,其背景见 Boyd 与 Vandenberghe 的《Convex Optimization》第2章;本文针对测向模型给出独立推导,不将一般理论本身视为新的研究贡献。[文献2](https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf)
本文严格区分两个集合:问题一的 $P$ 仅表示测向角域之交;第二问及在线搜索中的 $K$ 可进一步结合源位置圆域和接收距离先验。向 $P$ 加入圆盘后,边界可能出现圆弧,不能继续把它当成原问题中的纯多边形。
## 2. 符号及基本假设
| 符号 | 含义 |
| --- | --- |
| $s_i=(s_{ix},s_{iy})$ | 第 $i$ 个检测点,坐标单位为米 |
| $\theta_i$ | 第 $i$ 次有效示向度 |
| $\delta_i$ | 误差半角,题设取 $1^\circ$ |
| $g=(x,y)$ | 未知干扰源位置 |
| $W_i$ | 第 $i$ 次测向对应的闭前向角域 |
| $P$ | 所有角域的交集 |
| $V=\{v_1,\ldots,v_m\}$ | 非空有界 $P$ 的顶点集 |
| $D(P)$ | 区域内任意两点距离的上确界 |
| $B(c,r)$ | 中心为 $c$、半径为 $r$ 的闭圆盘 |
| $\rho(P)$ | 覆盖 $P$ 的最小圆盘半径 |
假设各次有效示向度对应同一频道的同一个静止源。仅把 `direction` 观测代入角域模型,不能给 `near` 或 `no_signal` 人为赋予角度。理论推导允许 $0\le\delta_i<90^\circ$,用于讨论退化情况,题目主模型始终采用 $\delta_i=1^\circ$。
程序可额外计入两位小数舍入对应的 $0.005^\circ$ 裕量,但必须显式声明。题设的 $1^\circ$ 误差界与实现中的浮点容差是两个概念,均不能在结果解释时省略。
## 3. 由角域推导半平面约束
定义方向向量 $u(\alpha)=(\cos\alpha,\sin\alpha)$,二维叉积为 $[a,b]=a_xb_y-a_yb_x$。三角函数计算前将角度换成弧度。
令 $u_i^-=u(\theta_i-\delta_i)$、$u_i^+=u(\theta_i+\delta_i)$。当 $0<\delta_i<90^\circ$ 时,真实位置位于两条边界射线之间,等价于 $[u_i^-,g-s_i]\ge0$ 和 $[u_i^+,g-s_i]\le0$。第一条要求 $g-s_i$ 在下边界的左侧,第二条要求其在上边界的右侧。
将第一条展开,得到 $\sin(\theta_i-\delta_i)x-\cos(\theta_i-\delta_i)y\le\sin(\theta_i-\delta_i)s_{ix}-\cos(\theta_i-\delta_i)s_{iy}$。
将第二条展开,得到 $-\sin(\theta_i+\delta_i)x+\cos(\theta_i+\delta_i)y\le-\sin(\theta_i+\delta_i)s_{ix}+\cos(\theta_i+\delta_i)s_{iy}$。
同时保留前向约束 $u(\theta_i)\cdot(g-s_i)\ge0$。该约束在正半角情形下冗余,但当 $\delta_i=0$ 时,前两条只限定一条直线,加入它才得到正确的射线。角域顶点本身也包含在闭集合内,这是保守几何处理,并不表示该点仍能获得示向度。
因此,$P=\bigcap_{i=1}^{n}W_i=\{g:Ag\le b\}$。采用向量不等式后,$359^\circ$ 与 $0^\circ$ 跨界无需分段比较角度。每个 $W_i$ 是闭凸集,故 $P$ 也是闭凸集;它可能为空、为单点、为线段、为有界凸多边形,也可能无界。
## 4. 定位区域的构造与分类
### 4.1 边界交点与可行性
把约束统一写成 $a_jx+b_jy\le c_j$。两条边界的行列式为 $\Delta_{jk}=a_jb_k-a_kb_j$。当 $\Delta_{jk}\ne0$ 时,交点坐标为 $x=(c_jb_k-c_kb_j)/\Delta_{jk}$、$y=(a_jc_k-a_kc_j)/\Delta_{jk}$。保留满足全部约束的交点,再去重并构造凸包。
**命题1:** 至少有一次观测时,非空的角域交集一定存在极点,因此可通过可行边界交点枚举判空。
**证明:** 取第一个角域的轴向量 $u_1$,其中任意 $g$ 满足 $u_1\cdot(g-s_1)\ge\cos\delta_1\,\lVert g-s_1\rVert$,且 $\cos\delta_1>0$。在非空 $P$ 上最小化线性函数 $u_1\cdot(g-s_1)$;以任一可行点的函数值截取下水平集,得到非空紧集,故最小值能够取得。最小化点集位于一条支撑直线上,且有界,所以为点或线段。取该点或线段端点即得到 $P$ 的极点。二维线性约束的极点至少有两条法向量线性无关的有效边界,否则沿所有有效边界的公共切向可作双向小扰动,与极点定义矛盾。因此极点包含在上述交点枚举中。证毕。
无观测时,$P=\mathbb R^2$,应直接判为无界,不能用“没有交点”判断为空集。
### 4.2 无界性判定
对非空 $P$ 定义衰退锥 $\mathcal R=\{d:Ad\le0\}$。若存在 $d\ne0$,则任意 $g_0\in P$ 与 $t\ge0$ 都满足 $g_0+td\in P$,所以 $P$ 无界。
反之,若 $P$ 无界,可取 $g_k\in P$ 使 $\lVert g_k-g_0\rVert\to\infty$。单位向量 $(g_k-g_0)/\lVert g_k-g_0\rVert$ 存在收敛子列,极限 $d$ 满足 $\lVert d\rVert=1$。将 $Ag_k\le b$ 减去 $Ag_0$,再除以距离并取极限,得到 $Ad\le0$。因此 $P$ 有界当且仅当 $\mathcal R=\{0\}$。
本模型的衰退锥被一个小于 $180^\circ$ 的闭角域约束,若包含非零向量,必含一条极射线,该射线平行于某条有效约束边界。故只需检查每个法向量 $(a_j,b_j)$ 的两个切向方向 $(b_j,-a_j)$、$(-b_j,a_j)$ 是否满足所有齐次不等式。
### 4.3 分类约定
可行交点为空时返回空集;存在非零衰退方向时返回无界。否则求可行交点的凸包,按顶点数和仿射维数区分单点、线段和二维多边形。空集的直径在本文约定为未定义;无界集合的直径为 $+\infty$。程序使用空值及单独的无穷标志表示二者,避免写入非标准 JSON 数值。
显示窗口只用于绘图裁剪。任意大矩形都不能取代衰退锥判定,更不能把截断图形的直径称为原无界区域的直径。
## 5. 直径的顶点定理
**定理1:** 若 $P=\operatorname{conv}(V)$ 非空且有界,则 $D(P)=\max_{i,j}\lVert v_i-v_j\rVert$。
**证明:** 任取 $x,y\in P$,可写成 $x=\sum_i\lambda_i v_i$、$y=\sum_j\mu_jv_j$,其中权重非负且分别求和为1。于是 $x-y=\sum_{i,j}\lambda_i\mu_j(v_i-v_j)$。由三角不等式,$\lVert x-y\rVert\le\sum_{i,j}\lambda_i\mu_j\lVert v_i-v_j\rVert\le\max_{i,j}\lVert v_i-v_j\rVert$。最远顶点对又属于 $P$,上界可以达到,结论成立。证毕。
因此,小规模问题中直接枚举所有顶点对即可,计算复杂度为 $O(m^2)$。单点的直径为0,线段的直径为端点距离。这里的直接枚举不是近似算法;其缺点仅在于大规模时计算量较高。
## 6. 直径圆覆盖的充要条件
**定理2:** 取任意一组最远顶点 $a,b$,令 $D=\lVert a-b\rVert$、$o=(a+b)/2$。存在直径为 $D$ 的覆盖圆,当且仅当所有顶点均满足 $\lVert v_i-o\rVert\le D/2$。
**证明:** 若半径为 $D/2$、中心为 $z$ 的圆同时包含 $a,b$,则 $D\le\lVert a-z\rVert+\lVert z-b\rVert\le D$。两个不等式必须同时取等号,所以 $z$ 在两点连线上,且到两点距离相等,只能是中点 $o$。当 $D=0$ 时结论直接成立。另一方面,圆盘是凸集,包含全部顶点等价于包含它们的凸包。因此只需在这个唯一可能的圆心处检查全部顶点。证毕。
该定理不仅回答“以某条直径线段为直径的圆是否覆盖”,也回答“能否移动一个同样大小的圆使其覆盖”。若检查失败,移动圆心或更换最远顶点对均不能解决。
定义最大超出量 $E=\max_i\lVert v_i-o\rVert-D/2$。在精确算术下,$E=0$ 表示覆盖成立,$E>0$ 表示失败;不会出现严格负值,因为最远点对就在圆周上。取达到最大值的顶点,即得到一份可以独立复核的覆盖失败证据。
## 7. 符合测向条件的反例
取误差半角均为 $1^\circ$,三个检测点及读数如下。
| 检测点 | 坐标(米) | 示向度 |
| --- | --- | --- |
| $s_1$ | $(-1000,0)$ | $1^\circ$ |
| $s_2$ | $(540,-500\sqrt3)$ | $121^\circ$ |
| $s_3$ | $(520,520\sqrt3)$ | $241^\circ$ |
每个角域的下边界方向分别为 $0^\circ,120^\circ,240^\circ$。对应的三个左半平面是 $y\ge0$、$\sqrt3x+y\le40\sqrt3$、$y\le\sqrt3x$,交集为顶点 $A=(0,0)$、$B=(40,0)$、$C=(20,20\sqrt3)$ 的等边三角形。
还需验证每个角域的另一条边不会切去这个三角形。以 $s_1$ 为例,到三个顶点的方向分别为 $0^\circ,0^\circ,\arctan(20\sqrt3/1020)$,最后一项约为 $1.945^\circ<2^\circ$,均在 $[0^\circ,2^\circ]$ 内。其余两站由绕三角形中心旋转 $120^\circ$ 的对称性成立。因此三个完整前向角域之交恰为上述三角形。
将真实源取为三角形中心 $g_*=(20,20\sqrt3/3)$。以第一站为例,真实方向约为 $0.649^\circ$,与 $1^\circ$ 的读数偏差小于 $1^\circ$;检测距离约为1020米,小于1500米。另两站同理。该反例符合题设方位误差和可能的有效接收半径。
此时 $D=40$ 米,而以 $AB$ 为直径的圆中心为 $(20,0)$,到 $C$ 的距离为 $20\sqrt3>20$ 米,不能覆盖。三角形外接圆即最小包围圆,其中心为 $(20,20\sqrt3/3)$,半径为 $40/\sqrt3\approx23.094011$ 米。这也证明了“直径不超过40米”不足以保证一次清除。
## 8. 最小包围圆及其清除含义
### 8.1 存在性、唯一性与支撑点
定义 $f(z)=\max_{v\in V}\lVert v-z\rVert$,则 $\rho(P)=\min_z f(z)$。由于 $V$ 有限,$f$ 连续且随 $\lVert z\rVert\to\infty$ 而趋于无穷,最小值存在。
若两个不同中心 $c_1,c_2$ 都以半径 $r$ 覆盖 $V$,中点 $c$ 对每个顶点满足 $\lVert v-c\rVert^2=(\lVert v-c_1\rVert^2+\lVert v-c_2\rVert^2)/2-\lVert c_1-c_2\rVert^2/4<r^2$,与最小性矛盾。因此最小包围圆唯一。
在最优中心 $c$ 处,令 $T$ 为圆周上的顶点集。若 $c$ 不在 $T$ 的凸包中,可沿严格分离方向小幅移动中心,使所有圆周点的距离同时减小;其余有限个点有严格余量,仍被稍小圆覆盖,产生矛盾。故 $c\in\operatorname{conv}(T)$。二维凸组合经仿射相关权重消元,最多保留3个点。因此最小包围圆由至多3个圆周顶点支撑。
更具体地,若支撑点 $p_j$ 的权重满足 $c=\sum_j\lambda_jp_j$,则对任意 $z$ 有 $\sum_j\lambda_j\lVert p_j-z\rVert^2=r^2+\lVert c-z\rVert^2\ge r^2$。这给出了任何覆盖圆半径不能小于 $r$ 的直接证据。
### 8.2 求解方法与来源
由支撑点性质,可以枚举单点零半径圆、两点直径圆和三点外接圆,再检查全体顶点。这是便于核查的基准方法,最坏复杂度为 $O(m^4)$。
当前实现采用 Welzl 的随机增量算法:打乱点序,若当前圆不包含新点,则在该点成为边界点的约束下递归求解较小问题;边界点至多3个。程序用显式栈避免递归深度限制,并固定随机种子以复现结果。理论期望线性依赖随机排列分析,不等于任意固定排列的最坏时间保证。3个强制边界点应使用外接圆,不能替换成其无约束最小圆。算法来源为 Welzl 的原论文,CGAL 文档提供了定义与实现背景。[文献3](https://people.inf.ethz.ch/emo/PublFiles/SmallEnclDisk_LNCS555_91.pdf)、[文献4](https://doc.cgal.org/latest/Bounding_volumes/classCGAL_1_1Min__circle__2.html)
### 8.3 与一次清除的关系
所有能够保证一次清除的位置构成 $C_{20}(P)=\bigcap_{g\in P}B(g,20)=\bigcap_{v\in V}B(v,20)$。第二个等号来自圆盘凸性。该集合非空当且仅当 $\rho(P)\le20$。
因此,最小包围圆中心是保证清除的充分选择,但不一定是移动距离最短的选择。若后续需要优化路径,可以在 $C_{20}(P)$ 内寻找距离机器狗最近的位置。相比之下,$D(P)\le40$ 只是必要条件。
## 9. 算法流程与计算量
**算法1:角域交、直径及覆盖证据。**
1. 校验观测并进行坐标平移、尺度归一化,保留原误差半角。
2. 生成每次观测的三条半平面约束。
3. 枚举非平行边界交点,保留满足全部约束的点;无观测和空集分别处理。
4. 检验非零衰退方向;存在时报告无界并停止有限圆计算。
5. 对可行点去重并求凸包,识别点、线段或多边形。
6. 枚举顶点对求直径及任意一组最远点。
7. 检查其中点到全部顶点的距离,输出最大超出量与失败顶点。
8. 求最小包围圆,换回原坐标,重新检查顶点包含性,输出清除半径余量。
令半平面数 $k=3n$,顶点数为 $m$。边界交点枚举及全约束检查为 $O(k^3)$,衰退方向检查为 $O(k^2)$,交点排序上界为 $O(k^2\log k)$,直径计算为 $O(m^2)$,覆盖证据检查为 $O(m)$。随机增量最小圆在随机排列下期望为 $O(m)$;整个算法仍由半平面交点枚举主导,不能因此称为总体线性算法。
## 10. 数值实现与已有观测复核
数学结论使用精确不等式。浮点实现先平移、归一化,再用位置容差、平行判定阈值和衰退方向容差分别处理不同问题。接近平行或退化输入应进行精度与容差敏感性检查;任意追加一个固定小数裕量都不能替代严格的误差传播上界。
当前程序输出 `diameter_circle` 中的圆心、半径、最大超出量和反例顶点,以及 `minimum_enclosing_circle`。清除判断采用 $\rho+\varepsilon_m\le20$,其中 $\varepsilon_m$ 是工程数值裕量。它是观测及几何计算可靠这一前提下的决策条件,不是一次真实清除成功记录。
既有官方演练案例 `U5ZW-P9KN-TCAG-R7ST` 的三次不同位置观测如下。
| 检测点 | $x$ / 米 | $y$ / 米 | 示向度 / 度 |
| --- | ---: | ---: | ---: |
| 1 | 0 | 0 | 131.52 |
| 2 | -613.7618853216 | 391.5307754525 | 34.92 |
| 3 | -314.2721344680 | 656.6833525352 | 227.19 |
| 误差半角 | 直径 / 米 | 最小包围半径 / 米 | 直径圆最大超出 / 米 |
| --- | ---: | ---: | ---: |
| $1^\circ$ | 23.996723 | 12.068583 | 0.604002 |
| $1.005^\circ$ | 24.119088 | 12.130377 | 0.608486 |
两种口径下直径圆均不覆盖区域,最小包围半径均小于20米。该演练未公开源坐标,且没有执行清除,故只用于观测交会和计算一致性复核,不能据此声称实测定位误差或全清成功率。数据见[原始三点观测](C:/Users/HelixCopex/code/MATH/output/q1/practice/U5ZW-P9KN-TCAG-R7ST_observations.json),敏感性数值见[已有复算报告](C:/Users/HelixCopex/code/MATH/output/q1/optimization_report.json)。
## 11. 结论与实现对应
问题一的准确答案为:将测向角域表示为半平面交,先判断非空性及有界性,再由最远顶点对得到直径;以该直径为直径的圆一般不能覆盖定位区域,覆盖的充要条件是任意一组最远顶点的中点到全部顶点的距离均不超过半径。最小包围圆提供独立且适合后续清除的精度指标。
对应实现为 [localization.py](C:/Users/HelixCopex/code/MATH/geometry/localization.py)。在项目根目录可运行 `python -m geometry examples/q1/triangle.json`;追加 `--rounding-margin-deg 0.005` 可复算额外舍入裕量。本文整理理论与已有计算结果,不改变原始观测或既有程序。
## 参考文献
1. 全国大学生数学建模竞赛组委会. 2026年高教社杯全国大学生数学建模竞赛B题:无线电干扰源的快速自动定位与清除[Z]. 2026. [本地题面](C:/Users/HelixCopex/code/MATH/issue/B题.pdf),第1页、附录2。
2. BOYD S, VANDENBERGHE L. Convex Optimization[M]. Cambridge: Cambridge University Press, 2004. [作者公开版本](https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf),第2章。用于凸几何背景,本文的题目化证明在正文给出。
3. WELZL E. Smallest enclosing disks (balls and ellipsoids)[C]//MAURER H. New Results and New Trends in Computer Science. Lecture Notes in Computer Science, vol. 555. Berlin: Springer, 1991: 359–370. [作者公开论文](https://people.inf.ethz.ch/emo/PublFiles/SmallEnclDisk_LNCS555_91.pdf)。用于随机增量最小包围圆算法来源。
4. CGAL Project. CGAL::Min_circle_2: Bounding Volumes[EB/OL]. [在线文档](https://doc.cgal.org/latest/Bounding_volumes/classCGAL_1_1Min__circle__2.html),访问日期:2026-09-10。用于最小圆及支撑点定义的交叉核对。
+248
View File
@@ -0,0 +1,248 @@
# 问题二:具有接收保证的第二检测点选择
## 摘要
针对只获得一次全向干扰源示向度的情形,提出以接收保证为约束、以后验最小包围半径为主要指标的主动选点方法。首先将源位置圆域、首次角域与有效接收距离上界相交,构造包含真实源的位置候选集;随后把第二检测点的安全条件写成一族闭圆盘的交,并证明其非空性等价于候选集最小包围半径不超过最小有效接收半径。利用首次角域狭窄的题设特征,进一步推导截断角域的最小包围圆,得到半径约250米、能够直接计算的安全候选圆盘。为比较候选点的定位效果,建立兼顾 `direction` 和 `near` 的保守后验模型,推导交会角的局部几何意义,并给出采用外包多边形及观测区间划分的有限候选评估算法。严格接收保证与启发式性能优化分别陈述,不将有限采样结果解释为连续问题的全局最优解。
**关键词:** 主动测向;鲁棒选点;安全候选区域;最坏后验半径;保守几何近似。
## 1. 问题界定与思路来源
题目第二问给定某全向干扰源在一个检测点处的示向度,要求提出第二检测点的选择策略、说明其定位效果并给出候选区域。这里的源类型明确为全向,不能混入第四问的朝向可见性条件。[题面第1页问题2](C:/Users/HelixCopex/code/MATH/issue/B题.pdf)
本问有两个先后不同的问题:第二点是否仍能收到信号;在能收到信号的点中,如何使新测量更有价值。如果只追求较大交会角而不控制到真实源的距离,第二次测量可能返回 `no_signal`,预期几何收益无法实现。因此先构造保证接收的可行域,再优化测向后的不确定区域。
方法来源分为三部分。候选位置集合来自题设有界误差与接收距离,沿用问题一的角域约束;安全选点来自“对每个可能源位置都满足距离条件”的鲁棒可行性;定位收益来自主动测量设计,以最坏后验半径代替未经题面支持的平均误差。凸函数与鲁棒建模的一般背景参见 Boyd 与 Vandenberghe 的《Convex Optimization》第3章、第6.4节;本题的安全圆盘公式、扇形推导及区间评估方法在下文逐步建立。[文献3](https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf)
需要强调:本题没有给出源位置概率分布,也没有给出可直接使用的独立高斯测向噪声模型。因此不能把卡尔曼滤波、协方差或费舍尔信息计算直接作为严格保证。交会角仍有明确几何意义,但应作为局部解释和候选筛选依据。
## 2. 符号、题设事实与建模约定
| 符号 | 含义 |
| --- | --- |
| $s$、$\theta$ | 首次检测位置与示向度 |
| $\delta$ | 误差半角,默认 $1^\circ$ |
| $g$ | 未知的全向干扰源位置 |
| $\Omega=B(0,1800)$ | 干扰源位置圆域 |
| $R_g\in[R_-,R_+]$ | 未知有效接收半径,$R_-=1000$、$R_+=1500$ 米 |
| $K_1$ | 首次观测后的保守位置候选集 |
| $q$ | 第二检测点 |
| $\mathcal Q(K_1)$ | 对 $K_1$ 内所有位置均保证接收的第二点区域 |
| $\rho(K)$ | 非空有界集合 $K$ 的最小包围半径 |
| $J(q)$ | 第二点的最坏保守后验半径 |
采用以下题设事实:有效接收半径在1000至1500米之间;检测点到全向源距离不超过5米时无法得到示向度,可直接光学定位并清除;清除距离不超过20米;机器狗移动速度为5米/秒,检测需要5秒,同一频道连续测量不发生额外频道切换。[题面附录2第(2)、(4)至(9)项](C:/Users/HelixCopex/code/MATH/issue/B题.pdf)
1800米圆域限制的是源位置,不是机器狗的搜索位置。检测点可以位于该圆域外;接口坐标分量的绝对值上限属于数值防护限制,不能误解成要求 $q\in\Omega$。[题面第4页](C:/Users/HelixCopex/code/MATH/issue/B题.pdf)
如果把读数舍入额外计入误差预算,可显式采用 $\delta=1.005^\circ$。下文解析推导对 $0\le\delta\le45^\circ$ 成立,但这一扩展区间不是题目误差范围。
## 3. 首次观测对应的源位置集合
设 $u=u(\theta)=(\cos\theta,\sin\theta)$。由第一次有效示向度,真实位置属于前向角域 $W(s,\theta,\delta)$;由已经收到信号,必有 $\lVert g-s\rVert\le R_g\le R_+$;由源位置限制,又有 $g\in\Omega$。故定义 $K_1=\Omega\cap W(s,\theta,\delta)\cap B(s,R_+)$。
该集合为闭凸紧集。真实观测一致时 $g\in K_1$,所以它非空。首次返回 `direction` 还意味着 $\lVert g-s\rVert>5$,但若把这个开圆盘排除,会破坏凸性。本文暂不使用该排除信息,保留包含真源的凸外包集合;由此得到的保证可能更保守,不会误删真实位置。
这一区别决定了后续结论的口径:本文给出的保证对较大的 $K_1$ 中所有位置成立,因而对实际源成立;但在 $K_1$ 上定义的最坏后验指标可能比利用全部观测细节的精确模型更悲观。
若计算得到 $K_1=\varnothing$,说明输入、频道、误差界或数值处理与题设不一致。此时应返回不一致状态,不能继续给空集计算圆心。问题一的纯角域求解器也不能直接把上述圆弧边界当作直线边界处理。
## 4. 安全候选区域的精确定义及基本性质
### 4.1 接收距离条件
若第二检测点满足 $\lVert q-g\rVert\le R_-$,由于 $R_g\ge R_-$,即可保证全向源信号能够接收。因此定义 $F_K(q)=\max_{g\in K}\lVert q-g\rVert$,并令 $\mathcal Q(K)=\{q:F_K(q)\le R_-\}=\bigcap_{g\in K}B(g,R_-)$。
这里限制的是第二点到所有可能源位置的距离,而不是到第一次检测点的距离。保证接收也不等于保证返回示向度,因为距离不超过5米时可能返回 `near`;该分支的定位效果更好,不能视为策略失败。
### 4.2 凸性、稳定性和非空条件
**命题1:** 对任意非空紧集 $K$,函数 $F_K$ 为凸函数,且满足 $\lvert F_K(q_1)-F_K(q_2)\rvert\le\lVert q_1-q_2\rVert$。
**证明:** 对每个固定的 $g$,距离函数关于 $q$ 凸;逐点取最大值保持凸性。又由三角不等式,$\lVert q_1-g\rVert\le\lVert q_2-g\rVert+\lVert q_1-q_2\rVert$,对 $g$ 取最大值得到一个方向的不等式,再交换两点即得结论。证毕。
因此 $\mathcal Q(K)$ 是闭凸集。非空时,它包含在任一 $B(g_0,R_-)$ 内,所以也有界。
**定理1:** $\mathcal Q(K)\ne\varnothing$ 当且仅当 $\rho(K)\le R_-$。
**证明:** 最小包围半径的定义为 $\rho(K)=\min_q F_K(q)$。存在 $q$ 使 $F_K(q)\le R_-$,与其最小值不超过 $R_-$ 完全等价。最小值存在,因为 $F_K$ 连续且随 $\lVert q\rVert\to\infty$ 趋于无穷。证毕。
当 $\rho(K)=R_-$ 时,安全区域仅包含唯一最小包围圆中心;唯一性可由两个候选中心的中点距离恒等式证明,见[问题一第8节](C:/Users/HelixCopex/code/MATH/docs/algo-1.md)。因此应使用不严格不等式,不能把等号情形误判为空。
### 4.3 外包圆给出的充分区域
若已知 $K\subseteq B(c,r)$ 且 $r\le R_-$,则任意满足 $\lVert q-c\rVert\le R_--r$ 的点,都有 $\lVert q-g\rVert\le\lVert q-c\rVert+\lVert c-g\rVert\le R_-$。因此 $B(c,R_--r)\subseteq\mathcal Q(K)$。
这给出了容易计算的充分候选区域,但一般不等于整个安全区域。一个宽松外包圆若满足 $r>R_-$,只能说明该外包圆不能提供证书,不能证明真实的 $\mathcal Q(K)$ 为空。
## 5. 首次截断角域的解析最小包围圆
### 5.1 坐标变换
暂时去掉只会缩小集合的 $\Omega$ 约束,考虑完整截断角域 $S=W(s,\theta,\delta)\cap B(s,R_+)$。平移并旋转,使 $s$ 成为原点、$u$ 成为横轴。其点可写成 $g=s+t\,u(\theta+\varphi)$,其中 $0\le t\le R_+$、$-\delta\le\varphi\le\delta$。
令 $a=R_+/(2\cos\delta)$,并取 $c=s+au$。
### 5.2 包含性证明
**定理2:** 对 $0\le\delta\le45^\circ$,截断角域 $S$ 的最小包围圆为 $B(c,a)$。
**证明的第一部分:** 对任意 $g\in S$,有 $\lVert g-c\rVert^2=t^2+a^2-2at\cos\varphi$。固定 $\varphi$ 时,右侧关于 $t$ 为凸二次函数,区间最大值在端点取得。当 $t=0$ 时等于 $a^2$;当 $t=R_+$ 时,由 $\cos\varphi\ge\cos\delta$ 得其不超过 $R_+^2+a^2-2aR_+\cos\delta=a^2$。故整个 $S$ 被该圆覆盖。
### 5.3 最小性证明
取角域中的三个点 $p_0=s$、$p_+=s+R_+u(\theta+\delta)$、$p_-=s+R_+u(\theta-\delta)$。它们均在 $B(c,a)$ 的圆周上。
令 $\lambda_+=\lambda_-=1/(4\cos^2\delta)$,$\lambda_0=1-1/(2\cos^2\delta)$。由于 $\delta\le45^\circ$,三权重非负且和为1,直接代入可得 $c=\lambda_0p_0+\lambda_+p_++\lambda_-p_-$。
对任意中心 $z$,利用加权距离恒等式,有 $\sum_j\lambda_j\lVert p_j-z\rVert^2=a^2+\lVert c-z\rVert^2\ge a^2$。若半径为 $r$ 的圆覆盖这三个点,则左侧不超过 $r^2$,故 $r\ge a$。任何覆盖 $S$ 的圆都必须覆盖这三个点,结合第一部分的包含性,得到最小半径恰为 $a$。当 $\delta=0$ 时两个远端点重合,结论退化为长度 $R_+$ 的线段直径圆,仍成立。证毕。
该推导不依赖源位置先验,也不依赖位置概率分布。它给出的是完整截断角域的精确最小圆;与 $\Omega$ 相交后,真实 $K_1$ 的最小圆可能更小。
## 6. 本题可直接采用的第二点候选区域
由 $K_1\subseteq S\subseteq B(c,a)$ 和第4.3节,可取 $\mathcal Q_0=B(c,b)$,其中 $c=s+au$、$a=1500/(2\cos\delta)$、$b=1000-a$。
| 误差半角 | 轴向中心距离 $a$ / 米 | 安全候选半径 $b$ / 米 |
| --- | ---: | ---: |
| $1^\circ$ | 750.114246 | 249.885754 |
| $1.005^\circ$ | 750.115391 | 249.884609 |
两种口径下 $b>0$,故本题首次有效测向后的安全候选区域可以直接证明非空。无需将“若安全区域为空就去最小圆圆心”作为正常流程的保底步骤。
几何上,$\mathcal Q_0$ 位于首测示向方向前方约750米,以约250米为半径。位于圆盘轴向前后端的点、两侧横向点以及圆心都保证接收。横向点只是可供比较的候选点,并未被证明总是最优。
为抵消坐标计算和动作提交中的工程舍入,可取缩小区域 $\mathcal Q_\eta=B(c,b-\eta)$,其中 $0<\eta<b$。若圆心和提交位置合计偏差不超过 $\eta$,三角不等式保证仍有 $\lVert q-g\rVert\le1000$。例如先取 $\eta=0.01$ 米属于可调工程选择,不是题面要求,也不是未分析数值误差的自动上界。
若有更精细的 $K_1$ 外包圆,可得到更大的充分区域;若精确处理其圆弧边界,也可直接搜索 $\mathcal Q(K_1)$。这些扩展是性能优化,不影响 $\mathcal Q_0$ 的正确性。
## 7. “较好的定位效果”的数学定义
### 7.1 保守后验集合
对候选点 $q\in\mathcal Q_0$,若返回 `direction` 及示向度 $\beta$,定义保守后验 $K_d(q,\beta)=K_1\cap W(q,\beta,\delta)$。这里继续忽略距离大于5米所提供的非凸排除信息。真实源一定属于 $K_d$。
若返回 `near`,定义 $K_n(q)=K_1\cap B(q,5)$,故 $\rho(K_n(q))\le5$。在此分支直接以当前位置进行光学定位和清除,满足20米的清除条件,不必强行再取得一个角度。
设圆周角距离为 $d_{\mathbb S^1}(\alpha,\beta)=\min_{k\in\mathbb Z}\lvert\alpha-\beta+360^\circ k\rvert$。对 $\lVert g-q\rVert>5$ 的候选位置,令真实方位为 $h_q(g)=\operatorname{atan2}(g_y-q_y,g_x-q_x)$。可能出现的读数集合定义为 $\mathcal B(q)=\{\beta:\exists g\in K_1,\ \lVert g-q\rVert>5,\ d_{\mathbb S^1}(\beta,h_q(g))\le\delta\}$。
这里用所有允许误差描述可能读数,不是假设各地点的误差可以随机独立重抽样。同一个位置的重复检测不产生新的独立信息;所构造的 $\mathcal Q_0$ 与首测位置相距至少约500米,天然避免原地重复测量。
### 7.2 最坏后验半径指标
定义 $J(q)$ 为所有可能 `direction` 分支的 $\rho(K_d(q,\beta))$,以及非空 `near` 分支的 $\rho(K_n(q))$ 的上确界。等价地,它是未来所有允许观测下最坏的保守最小包围半径;不存在的观测分支不参与取最大值。
选点的主要目标为在安全候选区域中降低 $J(q)$。该指标直接服务于一次清除要求:若 $J(q)\le20$,则每个可能分支都有半径不超过20米的保守定位圆。它比仅比较面积更符合任务,因为面积较小的集合仍可能十分狭长。
对于任意有效分支,后验都是 $K_1$ 的子集。集合包含关系给出 $\rho(K_2)\le\rho(K_1)$,故 $J(q)\le\rho(K_1)$。但不一定严格小于,因此不能仅由“增加一次观测”推断定位精度必然严格改善,更不能保证只需两次测向便达到20米阈值。
### 7.3 移动成本的引入
连续测量同一频道时,本次动作的虚拟时间增量为 $C(q)=\lVert q-s\rVert/5+5$ 秒。推荐先按后验半径择优,再在几何效果接近的候选点中比较移动成本,以避免任意混合米和秒。
用 $\widehat J(q)$ 表示实际计算的评估量,在第10节的保守方案中取为上界 $\overline J(q)$。设有限候选点中的最小评估值为 $J_{\min}$。可先保留满足 $\widehat J(q)\le J_{\min}+\tau$ 的点,再选择其中 $C(q)$ 最小者,其中 $\tau\ge0$ 是显式给定的定位容忍量,单位为米;$\tau=0$ 对应严格的字典序选择。本文不预设一个未经实验支持的最优 $\tau$。
## 8. 交会角的局部几何解释
在某个假定真实位置 $g$ 附近,令两站距离为 $r_1,r_2$,真实视线单位向量为 $u_1,u_2$,对应法向量为 $n_1,n_2$。当角误差很小且位置扰动相对站距较小时,方位函数的一阶展开给出 $n_i\cdot\Delta g\approx r_i e_i$,其中 $e_i$ 用弧度表示,满足 $\lvert e_i\rvert\le\delta_{\rm rad}$。
于是局部不确定区域近似由两条带状约束限定:$\lvert n_1\cdot\Delta g\rvert\le r_1\delta_{\rm rad}$、$\lvert n_2\cdot\Delta g\rvert\le r_2\delta_{\rm rad}$。若视线交会角为 $\phi$,法向量矩阵的行列式绝对值为 $\lvert\sin\phi\rvert$。对法向坐标中的矩形作线性逆变换,得到近似面积 $A_{\rm loc}\approx4r_1r_2\delta_{\rm rad}^2/\lvert\sin\phi\rvert$。
这解释了两点:近于平行或反向的视线使误差显著放大;在距离不变的局部比较下,接近直角的交会较有利。然而真实源位置未知,$r_2$ 和 $\phi$ 随 $g$ 改变,且有限角域并非无限带状区域。因此不能由该近似推出“总应横移固定距离”或“在某个假定源位置形成90度就是全局最优”。本文只将其用于优先考虑轴线两侧候选点,最终仍以后验集合指标评价。
## 9. 圆弧先验的保守离散
### 9.1 外包切线多边形
直接将圆周采样点连接得到的是内接多边形,会错误排除圆盘边缘的真实位置。为了复用第一问的半平面工具,选择 $M\ge3$ 个均匀法向量 $v_j=u(2\pi j/M)$,定义 $P_M(o,R)=\{x:v_j\cdot(x-o)\le R,\ j=0,\ldots,M-1\}$。
由柯西不等式,任意 $x\in B(o,R)$ 都满足所有约束,因此 $B(o,R)\subseteq P_M(o,R)$。相邻切线交点到圆心的距离为 $R\sec(\pi/M)$,故单个圆盘外包的最大径向超出不超过 $R[\sec(\pi/M)-1]$。
令 $\widetilde K_1=P_M(0,1800)\cap W(s,\theta,\delta)\cap P_M(s,1500)$,便有 $K_1\subseteq\widetilde K_1$。对任何第二读数再求半平面交,仍然保留真实源。上述单圆径向误差不能未经论证直接当成最终定位半径的误差界;靠近切触或退化时尤其需要加密检查。
安全选点仍使用第6节的解析 $\mathcal Q_\eta$。即使粗糙外包多边形的最小圆偏大,也不能据此推翻解析安全区域的非空结论。
### 9.2 多边形安全区域的可选扩展
若采用任意有界凸外包多边形 $\widetilde K=\operatorname{conv}\{v_j\}$,则 $\max_{g\in\widetilde K}\lVert q-g\rVert=\max_j\lVert q-v_j\rVert$,证明与第一问的凸组合论证相同。因此其保证接收区域由有限个约束 $\lVert q-v_j\rVert\le1000$ 给出,是圆盘交。
也可先解最小包围圆问题,再构造充分安全圆盘。由于 $\widetilde K$ 是外包集合,得到的区域可能更小,但其中每个点仍安全。若该离散区域为空,优先加密或回到解析候选盘,不把离散失败误报为真实问题无解。
## 10. 未来读数的保守区间评估
直接枚举少量假定源位置和误差端点,只得到被枚举情形的最大值,可能漏掉真正最坏读数。为了使评估输出具有上界意义,可以划分全部可能方位角,而非仅点采样。
将整周按圆周意义划分为若干区间 $I_j$,中心为 $\beta_j$,宽度为 $h_j$,要求 $\delta+h_j/2<90^\circ$。跨越 $0^\circ$ 的区间按圆周距离处理。
**命题2:** 对任意 $\beta\in I_j$,有 $W(q,\beta,\delta)\subseteq W(q,\beta_j,\delta+h_j/2)$。
**证明:** 对左侧任意非顶点位置,其方向到 $\beta$ 的圆周距离不超过 $\delta$;而 $\beta$ 到区间中心的距离不超过 $h_j/2$。由圆周距离的三角不等式,其方向到中心的距离不超过两者之和。顶点在两个闭角域中均被保留。证毕。
因此定义 $U_j(q)=\widetilde K_1\cap W(q,\beta_j,\delta+h_j/2)$,则任何落在该区间的真实读数所对应的保守后验,都包含于 $U_j(q)$,从而 $\rho(K_d(q,\beta))\le\rho(U_j(q))$。
对于 `near` 分支,可以取统一上界 $\min\{5,\rho(\widetilde K_1)\}$。该上界不需要精确计算圆弧交集;即使某点实际不会触发 `near`,纳入此上界只增加保守性。
令 $\overline J(q)$ 等于所有非空 $U_j(q)$ 的最小包围半径,以及上述 `near` 上界的最大值,即得到 $J(q)\le\overline J(q)$。该结论在精确几何计算下成立。浮点实现还需给出包含性和数值误差处理,不能把无误差预算的计算值称为机器可验证的严格上界。
通过将某个角区间二分,子区间扩张后的角域包含于父区间的扩张角域,所以相应方向上界不会增大。通过保留旧切线并增加新切线,也可使外包多边形嵌套缩小。这给出稳定的自适应加密方向,但没有在本文中证明连续选点的统一收敛速率。
该评估可能较慢,实际可先用少量读数采样粗筛,再对入围点使用完整角区间上界。前一阶段仅决定计算资源分配;最后报告的保守上界必须来自完整覆盖的区间,不能来自粗筛样本最大值。
## 11. 可执行的第二点选择算法
**算法2:安全区域内的有限候选主动测向。**
1. 输入 $s,\theta,\delta$,核验首次观测为同一全向源的有效示向度,构造 $K_1$ 或其保守表示。
2. 计算 $a=1500/(2\cos\delta)$、$c=s+au(\theta)$、$b=1000-a$,选择满足误差预算的缩小半径 $b-\eta$。
3. 构造有限候选集:包含圆心 $c$,并取 $q_{\ell j}=c+r_\ell[\cos\psi_j\,u+\sin\psi_j\,u_\perp]$,其中 $0<r_\ell\le b-\eta$、$\psi_j=2\pi j/N_\psi$、$u_\perp=(-\sin\theta,\cos\theta)$。所有候选点自动满足接收距离保证。
4. 对每个候选点构造第9节的外包后验,按第10节评估 $\overline J(q)$,保存最坏角区间及对应包围圆作为评估依据。
5. 优先选择 $\overline J$ 较小的点;按预先声明的 $\tau$ 筛选近优点,再按移动检测代价选择,必要时用固定顺序消除完全同分。
6. 在现实计算预算内,对入围候选附近加密位置、细分最坏角区间并增加外包切线。保留当前已验证安全的可用点,预算耗尽时返回当前结果。
7. 在所选位置测量同一频道。若为 `near`,在当前位置清除;若为 `direction`,用实际读数更新候选集合并复算最小包围圆;若其半径仍大于20米,继续后续测向,不能宣称两次定位已经完成。
8. 若在距离保证条件下意外得到 `no_signal`,核查动作是否被接受、频道是否正确、源是否仍存在及坐标和模型是否一致。未知原因解决前不按正常 `direction` 分支更新位置候选。
例如可从3层半径、每层16个方向及1个圆心开始,共49个候选点;这是位置搜索的数值分辨率示例,与第三问49点全域覆盖网格无关,也不是已优化参数。外包切线数、角区间宽度、加密次数及 $\tau$ 均应在论文实验部分显式记录。
设候选数为 $N_q$、角区间数为 $N_\beta$、每个后验的半平面数为 $k$。复用第一问的边界枚举时,主计算量约为 $O(N_qN_\beta k^3)$,另加顶点直径或最小圆计算。该方法提供清楚的正确性结构,但需通过缓存首次约束、局部加密和计算预算控制实现成本。不能用“只需一次新的测量”忽略选点器自身的运行时间。
算法输出保证的是:所选点位于已证明安全的区域,并在给定有限候选及评估精度下按既定规则择优。本文未证明 $q\mapsto J(q)$ 是凸函数,也未证明有限候选的最优点就是整个 $\mathcal Q(K_1)$ 中的全局最优点。
## 12. 边界情形与适用范围
| 情形 | 正确处理 |
| --- | --- |
| $K_1$ 为空 | 报告模型或数据不一致,不构造虚假圆心 |
| 首次结果已经为 `near` | 直接清除,不再套用“已知示向度”的第二问流程 |
| 一般集合满足 $\rho(K)=1000$ | 安全区域为最小包围圆中心这个单点 |
| 一般集合满足 $\rho(K)>1000$ | 不存在对该集合全部位置保证接收的点;圆心仅是最小化最坏距离的探索选择 |
| 外包圆半径大于1000 | 只能判定该证书不足,不能直接判真实安全区域为空 |
| 测量轴接近 $0^\circ/360^\circ$ | 使用向量约束和圆周区间,避免角度断点错误 |
| 两次测向交会较差 | 保留完整后验并继续测量,不将小面积当成小直径 |
| 源类型为定向 | 距离证书仍成立,但接收还受朝向限制,不能直接沿用本问的接收保证 |
对于一般集合无安全点的情形,最小包围圆中心确实解 $\min_q\max_{g\in K}\lVert q-g\rVert$,但其最坏距离仍可能大于1000米。改善交会角若要求偏离该中心,还会牺牲最坏距离最优性,必须明确是另一个多目标探索策略,不能把两项互相冲突的要求同时称为已保证。
## 13. 验证设计及当前实现边界
本问的验证分为数学证书与策略性能两层。数学层检查:截断角域被解析圆覆盖;安全候选到所有允许位置的距离不超过1000米;外包离散不删除真实点;角区间扩张包含所有区间内读数。数值抽样只能辅助检查这些证明,不能取代它们。
性能层应在相同自建源位置与确定的空间误差场上,比较轴向点、两个横向点、有限候选最坏后验策略。误差场在同一位置保持固定;不得让每次调用重新独立生成误差。记录第二次测量类型、后验直径和包围半径、额外移动、计算耗时及是否达到20米清除阈值。至少包含误差边界、源域边界、接收半径1000米、近距离和近共线案例。没有这些实验前,不报告未经验证的性能提升比例。
目前 [planning.py](C:/Users/HelixCopex/code/MATH/geometry/planning.py) 中的 `first_bearing_candidate_disk` 已实现第5至6节的解析证书;问题一内核可用于纯半平面区域的顶点和最小圆计算。**本仓库第二问交付的定位是"安全选点的启发式基线"**:解析安全候选盘证书已实现并证明(选中点必能收到信号),而选点评分采用边界采样点 × 读数区间端点的有限枚举近似(含 near 分支)。第9至11节描述的完整选点器数学方案,特别是第10节覆盖全部未来读数的保守区间上界,尚未在现有仓库中实现;采样最大值只用于候选点之间的相对比较与粗筛,不得当作严格最坏情形上界报告,也没有相应正式成绩。该实现边界不影响解析候选区域的证明。
对后续实现而言,应新增接收任意半平面约束的交集入口,或使用独立的多边形裁剪函数,再复用第一问的最小包围圆。不能把圆盘先验伪装成额外测向观测传入现有 `solve(measurements)` 接口。
## 14. 结论
第二问的候选区域可以明确取为前方约750米处、半径约250米的圆盘,其解析式为 $\mathcal Q_0=B(s+au(\theta),1000-a)$,其中 $a=1500/(2\cos\delta)$。这一候选区域对题设全向源提供接收保证,且在首次有效测向条件下严格非空。
在该区域内,以最坏保守后验最小包围半径为主指标、移动代价为次指标,采用有限候选和逐步加密进行选择。交会角解释局部几何优劣,外包多边形和读数区间扩张保证不低估相关后验集合;全局最优和“两次即可清除”均不作为未经证明的结论。
## 参考文献
1. 全国大学生数学建模竞赛组委会. 2026年高教社杯全国大学生数学建模竞赛B题:无线电干扰源的快速自动定位与清除[Z]. 2026. [本地题面](C:/Users/HelixCopex/code/MATH/issue/B题.pdf),问题2、附录2及第4页坐标约束。
2. 模拟器配套材料. 附件2:模拟器通信接口说明及编程指南[Z]. 2026. [本地附件](C:/Users/HelixCopex/code/MATH/issue/附件/附件2.docx)。用于 `direction`、`near`、`no_signal` 等程序观测字段与动作接口的对应。
3. BOYD S, VANDENBERGHE L. Convex Optimization[M]. Cambridge: Cambridge University Press, 2004. [作者公开版本](https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf),第3章、第6.4节。用于凸性及鲁棒建模的一般背景,不作为本题候选圆盘公式的出处。
4. 本项目. 问题一:有界测向误差下定位区域的直径与圆覆盖[Z]. 2026. [algo-1.md](C:/Users/HelixCopex/code/MATH/docs/algo-1.md)。用于角域半平面表示、顶点判定和最小包围圆的衔接。
**来源说明:** 第5节的截断角域最小圆及第6节的安全圆盘,是结合题设参数在本文中推导的结果;第8节的交会角关系由方位函数一阶展开推得;第9至11节是据集合包含关系构造的保守计算方案。以上陈述说明本项目的推导路径,不宣称这些一般几何思想在既有文献中首次出现。
+138
View File
@@ -0,0 +1,138 @@
# 算法说明:问题3 贝叶斯闭环(`bayes` 策略)
对应实现:`src/mcm26b/particles.py`(感知层)、`src/mcm26b/planner/bayes_loop.py`
(决策层)、`scripts/benchmark_q3_bayes.py`(消融)、`scripts/tune_q3_bayes.py`
(Optuna 调参)。基线对比:`docs/algo-3.md` 的七点批量(`seven`,A2)。
## 1. 建模定位
问题3是部分可观察的在线决策问题:频道数未知(10–16/20)、位置未知、有效
接收半径未知(1000–1500m)、测向误差 ±1°(服务器保留两位小数)。策略层
只能拿到 `/measure` 与 `/clear` 的响应,目标是最小化"发现—定位—清除"的
虚拟总时间。`bayes` 策略把它分解为三层滚动时域闭环:
1. **感知层**:每频道一个贝叶斯后验(网格幸存集),融合全部正/负观测;
2. **决策层**:站点扫频、定位测量、清除三类任务统一建表,开放路径
最近邻 + 2-opt 排序,每个动作后滚动重排(动态 TSP);
3. **选点层**:默认按期望log幸存占比和“到检测点、再接近源”的移动代价评分。
已停靠位置可逐频道补交会观测,真实清除始终由完整角域证书批准。
2026-09-11 当前修订的审核与配对验收见 [三四问算法审核与优化](算法审核与优化-20260911.md)。
本文件第5节是早期版本的历史结果,不应当作当前默认参数的复算结果。
## 2. 网格幸存集滤波与真源保留定理
每频道维护 Ω 上间距 h 的网格(h=14.65m,约 4.7 万格),`alive` 为幸存格
集合。Voronoi 裕量 m = √2/2·h 是格心到格内任一点的最大距离;所有删除
判定都内缩 m,即**仅当整格与可行集不相交时才删格**:
| 观测 | 题面语义 | 删除判定 |
|---|---|---|
| `no_signal`@s | 距离 > r_eff ≥ 1000 | 删格心距 s ≤ 1000 − m 的格 |
| `direction`@s | 距离 ≤ 1500,\|读数−真值\| ≤ δ_eff | 删角向超出 δ_eff + asin(m/(d−m)) 或距 s > 1500 + m 的格 |
| `near`@s | 距离 ≤ 5 | 删格心距 s > 5 + m 的格 |
**定理(真源保留)**:真源 P 满足全部题面约束;P 所在格的格心 g 满足
|g−P| ≤ m,故"整格不相交"判定永不命中该格。因此任意观测序列后 P ∈
幸存格的并集,且:
- **缺席证明**:幸存集为空 ⟹ 可行集为空 ⟹ 该频道无源(严格);
- **清除证书**:MEC(幸存).R + m ≤ 20 − 工程余量 ⟹ 真源距清除点 ≤ 20;
- **跳测规则**:幸存格到测点最小距离 > 1500 + m ⟹ 该测量必 no_signal
且无新排除,可跳过。
性质测试:`tests/test_particles.py`(随机源 × 随机测点 × 随机合法误差,
真源格永不被删;`tests/test_bayes_loop_q3.py` 端到端零异常)。
与 `belief.CandidateRegion`(保守凸外包)的分工:凸表示负责**清除证书**
(精确角域裁剪、收敛后触发),网格负责凸表示做不到的三件事——非凸负
观测挖洞(no_signal 排除盘)、缺席提前证毕、跳测判定。两者同读一套
响应流(`_record_measure`),任何一方证毕即收尾。
## 3. 信息增益选点
候选点集(二选一,按保证接收盘是否非空):
- **保证接收盘** B(MEC_poly 圆心, 1000 − ρ_poly)(盘内必收 direction/near,
几何同 `docs/algo-2.md` 定理1):环形采样(`search.candidate_rings`×12 方向);
- **宽候选集**(ρ_poly > 1000 时):PF MEC 的 1.0/1.5/2.0 倍探索环。
评分(`BayesConfig.score_mode`):
- `radius`(可选):期望后验半径 —— 对 K 个代表假设(幸存格均匀抽样)
各自模拟一次测量的幸存分支,分支半径用幸存子采样的质心最大距离近似,
r_eff~U(1000,1500) 的不确定性解析积分(p_no_signal = (d−1000)/500);
总分 = E[半径] + λ·移动秒数(λ=0.1);
- `entropy`(当前默认,λ=0.0105):期望log幸存占比,加上λ乘以
当前点→候选检测点→候选源中心的移动秒数。来向对称候选补充固定全局方向网格。
这里的均匀先验、零误差代表读数和均匀接收半径是选点评分的工程假设,
不属于题面给定的概率模型;只有完整±1.005°角域与距离界参与安全证明。
λ 与半径同量纲,量级必须小:λ 过大时终局阶段"走 300m"的代价压过
"半径 35m→25m"的收益,选点器原地重测、收敛停滞(消融实测 λ≥0.5 时
单源定位步数翻倍)。
## 4. 统一任务循环(动态 TSP)
每个决策点构建任务表并排序执行首个任务,随后滚动重排:
- **站点任务**:七站(原点 + 当前1159.7m环六点)上的UNKNOWN频道;
构造时验证全向覆盖解析界小于1000m,跳测规则与覆盖账本过滤;
- **定位任务**:DETECTED 且无证书的频道,位置由信息增益选点产生;
- **清除任务**:有证书(凸或网格)的频道,可沿当前位置方向移动证书圆心,
但平移量与原半径之和不得超过清除证书阈值,节省最后一段接近路程。
排序 = 开放路径最近邻打底 + 2-opt 改进(`two_opt_passes` 轮,成本含
移动 + 换频 + 动作耗时;换频按路径顺序逐步传递当前频道,clear保持频道;
终点自由不回起点)。这是 A2"站内最近邻服务
队列"的推广:消融显示距离缩短约 24% 是主要收益来源。
停止条件与基线一致:清满 16(数量上界)或全部频道 CLEARED/ABSENT,
`stop_reason=all_resolved` 即停并 `/exit`——**虚拟时间即评测成绩口径**
[用户决策修订 2026-09-11]。复扫保险模式(`mcm26b run --persistent`,
原默认行为):找全后继续只复扫未清除频道直到清除数达 16、实机预算
耗尽或虚拟安全余量(`search.virtual_reserve_s=10000s`)不足,供需要
"防缺席证明假设偏差"保险的场景显式开启。
## 5. 消融结果(自建模拟器,persistent 关,对齐找全口径)
12 随机场景(6 种子 × 10/16 源)+ 2 边界场景,与 SevenBatch 配对;
bayes 参数为 Optuna 回填后的库默认值:
| 指标 | SevenBatch | bayes |
|---|---|---|
| 有效运行(全清+缺席正确+零异常+正常退出) | 14/14 | **14/14** |
| 平均虚拟时间 | 5352.7s | **3726.2s(−30.0%)** |
| 配对降幅(最差 / 最好) | — | +7% / −41% |
| 平均移动距离 | 23413m | **15050m(−36%)** |
| 平均检测次数 | 102.4 | 110.0 |
| 单局实机计算墙钟 | 1.3s | 1.9s |
复现:`uv run python scripts/benchmark_q3_bayes.py --seeds 0,1,2,3,4,5`
(逐场景数据与场景 JSON 见 `output/q3/bayes-ablation/`)。
## 6. Optuna 调参
`scripts/tune_q3_bayes.py`:TPE(dev 依赖 `optuna`,缺失时自动退化为
随机搜索),目标 = 场景子集平均虚拟时间 + 10⁶×失败惩罚。搜索空间:
λ、代表点数、子采样规模、网格间距、站点环半径、2-opt 轮数、评分模式。
最优组合(entropy 评分、λ=0.0105、h=14.65m、代表点 7、2-opt 4 轮)
已按验收流程回填为 `config.BayesConfig` 默认值:全量基准 3726s/−30.0%
优于回填前的 4277s/−19.5%。两处人工修订:
- `station_ring_radius_m` 保留 1200(Optuna 建议 1159.7 虽再快约 60s,
但七站排除盘对最外圈格心的覆盖差 3.3m,PF 无法独立证明缺席,
只能靠覆盖账本兜底——设计性质优先于 1.7% 的均值差异);
- 评分模式在 entropy(信息增益)与 radius(期望后验半径)之间由调参
数据决定,两者实现均保留(`BayesConfig.score_mode`)。
调参记录见 `output/q3/bayes-tuning/best_params.json`。
## 7. 已知边界
- 检测次数略多于 A2(109.6 vs 102.4):定位收敛多用 1-2 次测量换距离
大幅缩短,净收益为正;跳测规则在 UNKNOWN 阶段(先验全域)暂无收益
面,收益集中在定位与复扫阶段;
- 网格清除证书(h=25m 时阈值 ≤1.8m)极少触发,作为凸证书的补位保险;
- 调参与消融基于自建模拟器(逐点固定 ±1° 误差场),不代表官方误差
分布;真源保留定理只依赖题面界(±1°、r_eff∈[1000,1500]),不依赖
误差分布假设。
+414
View File
@@ -0,0 +1,414 @@
# 问题三:具有覆盖证明的多源搜索与总耗时优化
## 摘要
针对源数为10至16、频道互异、位置未知的全向无线电干扰源,建立“发现—定位—清除—完整性证明”的在线决策模型,以全部清除为约束、以移动、检测、换频道和清除的虚拟总耗时为优化目标。沿用问题一的角域交与最小包围圆、问题二的安全接收区域,将改进重点放在全域覆盖规模与多源任务调度。首先从官方演练日志识别移动与无源频道验证的主要开销;随后证明中心加六个环形检测点即可覆盖题设圆域,并提出同站批量扫频、发现任务入队、就近定位清除的可执行基线。进一步规划利用无信号观测维护剩余区域、复用顺路检测点、优化安全清除位置及滚动比较剩余任务耗时的方法。给出停止条件、几何保守性、算法复杂度和分阶段验收方案。12个自建场景的配对消融表明,七点批量策略全部清除成功,平均逐局虚拟时间降幅为58.55%;该结果用于选择下一步实现方向,不作为官方成绩或全局最优性证明。
**关键词:** 全向源搜索;覆盖证书;集合定位;任务调度;虚拟总耗时;滚动规划。
> **延伸实现(2026-09-11)**:本文规划的无信号负观测更新、开放路径 2-opt
> 任务排序等已落地为贝叶斯闭环策略 `bayes`(网格幸存集滤波 + 信息增益
> 选点 + 滚动任务调度,参数经 Optuna 回填),自建消融相对本文七点批量
> 策略平均虚拟时间再降 30.0%(均值 3726s)。设计、严格性证明与消融数据
> 见 [algo-3-bayes.md](algo-3-bayes.md)。
## 1. 问题界定与思路来源
第三问要求在不知道干扰源位置和具体数量的条件下,自动发现并清除全部全向源,尽量缩短总时间。每个频道最多一个源,因此本题的数据关联由频道确定;机器狗无需解决无法区分多个信号身份的问题。源位于半径1800米的圆域内,最小有效接收半径为1000米。这两个尺度之间的关系使稀疏、有证明的覆盖成为可能。[题面](C:/Users/HelixCopex/code/MATH/issue/B题.pdf)、[接口规则](C:/Users/HelixCopex/code/MATH/docs/协议规则表与状态机.md)
本文与前两问分工如下:问题一回答“当前观测允许源在哪里、能否一次清除”;问题二回答“下一次去哪里测才安全且有效”;问题三回答“先搜哪些位置、扫哪些频道、何时中断搜索去清除,以及何时能够确信任务结束”。全局调度会调用前两问的几何内核,但不能只把第二问的局部精度目标逐个重复就视为总时间优化。
参考本项目[问题3—4论文列表](C:/Users/HelixCopex/code/MATH/docs/B题问题3-4相关论文列表.md),选取并核对以下相关思想。
| 来源 | 本文借鉴的内容 | 与本题的区别 |
| --- | --- | --- |
| Bayram、Vander Hook、Isler,2016,列表第10项 | 联合规划测向位置和访问顺序,同时计入移动时间与测量时间 | 原文以GDOP描述不确定度;其近似比不能转移为本文有界角域和清除任务的近似保证 |
| Olofsson等,2020,列表第22项 | 根据已观测区域分配后续搜索资源,在有限预算下规划路径 | 原文使用PHD和期望发现数;本文用确定性的逐频道剩余区域,不用概率很小替代无源证明 |
| Perera等,2023,列表第4项 | 将稀疏覆盖路线与无线电源定位结合,并分别评价路径与采样代价 | 原文依赖RSSI;本题接口没有RSS/RSSI数值,不能直接使用其估计器 |
上述内容分别见[大学研究记录及论文摘要](https://experts.umn.edu/en/publications/gathering-bearing-data-for-target-localization-6/)、[作者公开论文](https://torarnj.folk.ntnu.no/AURO2020a.pdf)、[arXiv原文入口](https://arxiv.org/abs/2312.03493)。这里只迁移任务组织方法,以下七点几何证明和题目化调度公式在本文独立推导。
论文列表中建议的RSS梯度逼近不能直接用于本题:`/measure` 只返回无信号、近距离或示向度,没有连续场强值。Atanasov等的源搜索也依赖场信号、随机梯度或测量模型,其收敛结论不证明本题仅测向闭环收敛。[原论文摘要](https://arxiv.org/abs/1402.0051) 本文也不假定源位置均匀分布、每次误差独立重抽样或某一交会角在所有场景下最优。
## 2. 现有方案的实测瓶颈
官方问题3演练 `DHFK-PHD2-SR2P-FXK9` 已证明现有实现能在该局全清10个源,完整数据见[演练验证报告](C:/Users/HelixCopex/code/MATH/output/q3/practice/20260911-port2026/report.md)。该局在策略运行结束后才读取官方源数,源真值没有进入决策。
| 分项 | 本局数值 | 对改进的含义 |
| --- | ---: | --- |
| 总虚拟时间 | 16217.454814秒 | 作为官方基线,不与自建场景混算 |
| 移动距离 / 耗时 | 64737.274米 / 12947.454814秒 | 移动约占79.84%,应优先减少站点和往返 |
| 检测次数 / 耗时 | 540次 / 2700秒 | 无源频道各扫49点,共490次,占全部检测90.74% |
| 换频道耗时 | 520秒 | 可以优化,但节省一次换频仅相当于少走5米 |
| 清除耗时 | 50秒,10次全部成功 | 清除可靠性已得到单局支持,无需先追求更小定位半径 |
| 最后一个源清除时刻 | 8454.332399秒 | 其后7763.122415秒用于剩余任务,约占总时间47.87% |
现有 `OmnidirectionalLoop._coverage_phase` 的结构还引入额外往返:在一个覆盖站按频道扫描,遇到 `direction` 就立即定位清除,再回原覆盖站继续下一频道。由原始动作日志统计,从非网格点返回网格检测点共10次,累计约9996.714米、1999.343秒。这是实际行程分类,不能全部当成可直接删除的收益,因为改序后仍需访问下一任务;但它明确说明同站任务应先批量处理。
当前49点网格同时服务第三问和第四问。它的定向覆盖证明要求更强的几何条件;第三问无需为未知发射朝向付出同样的采样代价。改进第三问时,应显式区分全向策略和第四问策略,不能全局替换公用网格。
## 3. 状态、信息与优化目标
### 3.1 符号与可用信息
| 符号 | 含义 |
| --- | --- |
| $\Omega=B(0,R)$,$R=1800$ | 源位置区域,单位米 |
| $R_-=1000$,$R_+=1500$ | 有效接收半径下界、上界 |
| $p,f,t$ | 当前机器人位置、测向频道、官方虚拟时刻 |
| $K_c$ | 已发现频道 $c$ 的保守位置候选集 |
| $E_c$ | 尚未发现频道 $c$ 仍可能存在源的位置集合 |
| $\mathcal U,\mathcal D,\mathcal L,\mathcal C,\mathcal A$ | 未发现、待定位、可保证清除、已清除、已证明无源频道集 |
| $\mathcal P$ | 曾获得有效存在证据的不同频道集,包含已清除频道 |
| $\delta=1.005^\circ$ | 题设1°误差加两位小数舍入裕量 |
| $S$ | 具有全域覆盖证明的检测站集合 |
| $L,N_m,N_s,N_c^+,N_c^-$ | 移动长度、检测数、换频数、成功与失败清除数 |
源静止、同位置同频道的测向误差固定。只有该频道实际收到的观测才能更新其状态;经过一个位置不代表在那里扫过所有频道。不同频道的无信号证据不能互相替代。
### 3.2 统一的时间口径
忽略微秒量化时,整局虚拟耗时为
$$T=\frac{L}{5}+5N_m+N_s+5N_c^++3N_c^-.$$
`/clear` 的目标频道不改变测向机频道,因而不引入换频代价;`/exit` 不要求回到原点,也不增加虚拟时间。因此访问顺序是从当前位置出发、终点自由的**开放路径**问题,不能默认使用需要返回起点的旅行商回路。
官方内部按微秒累计,验收时按每次移动耗时量化到整数微秒,再累加检测、换频和清除的整数秒。连续实数公式用于规划,逐动作微秒公式用于复算。原演练汇总的541处偏差已查明为累计浮点与微秒精度口径不同,详见[独立审计](C:/Users/HelixCopex/code/MATH/output/q3/practice/20260911-port2026/verification.json)。
优化目标按优先级定义为:保持真源候选和有效完成条件;在现实1200秒、虚拟360000秒上限内全清;在可完成策略中降低 $T$。现实计算和网络耗时单独约束,不加进虚拟时间公式。由于源场景和误差场未知,理想模型可写为对允许场景集合 $\Xi$ 的 $\inf_\pi\sup_{\xi\in\Xi}T(\pi,\xi)$,但本文不声称解出了这个连续在线极小极大问题,也不声称已证明任意合法场景都能在两个预算内完成。
## 4. 逐频道证据与安全停止
### 4.1 观测更新
首次 `direction` 在 $s$ 返回 $\theta$ 时,建立
$$K_c=\Omega\cap B(s,R_+)\cap W(s,\theta,\delta).$$
以后每次有效测向再交入相应距离上界和角域。`near` 时交入 $B(s,5)$,当前检测点本身就满足20米清除条件。角域的半平面表达、保守圆盘外包和最小包围圆计算沿用[问题一](C:/Users/HelixCopex/code/MATH/docs/algo-1.md)、[问题二](C:/Users/HelixCopex/code/MATH/docs/algo-2.md)。
全向源在 $s$ 返回 `no_signal`,意味着若该频道仍存在未清除源,则其距离严格大于实际接收半径,进而大于1000米。因此对未发现频道可维护
$$E_c=\Omega\setminus\bigcup_{s\in\mathcal N_c}B(s,R_-),$$
其中 $\mathcal N_c$ 只含该频道实际测得无信号的位置。有限精度实现可只排除 $B(s,R_- -\eta)$,$\eta>0$ 是有依据的数值裕量;少删不会漏源。该负观测更新仅用于第三问,不能直接用于第四问的定向源。
圆盘差通常非凸。不能把扣除圆盘后的集合强行表示成单个凸多边形,更不能丢弃狭窄或小面积分量。第一阶段保留当前凸定位内核,仅在未知频道的覆盖账本中使用负观测;后续如把无信号用于已发现源的精定位,应使用多片区域或再取保守凸外包。
### 4.2 完成与计数推理
安全停止条件是 $\mathcal C\cup\mathcal A=\{1,\ldots,20\}$,且本局 `/exit` 已被接受。无源证明可来自完整覆盖、剩余集合的可靠判空,或下述数量上界。
由于每频道至多一个源且总数不超过16,当 $|\mathcal P|=16$ 时,所有未出现过有效信号的频道即可由数量上界判为无源,**不必等待16个都清除才停止扫未知频道**。随后仍须清除 $\mathcal P\setminus\mathcal C$,不能直接退出。成功清除16个则立即满足全清条件。
只发现或清除10个不够,因为10是下界。反过来,若无源证据已排除10个频道,则其余10个频道都必须有源,但仍需获取其定位观测;这种计数推理不能替代位置搜索。若已知存在与无源证据互相矛盾,或可存在频道数不足10,应报告协议、模型或数值不一致,不能把矛盾解释为成功。
## 5. 用七个检测站替代49点网格
### 5.1 布点
取原点及半径 $a$ 圆周上的六个等角点:
$$S(a)=\{(0,0)\}\cup\{a(\cos(k\pi/3),\sin(k\pi/3)):k=0,\ldots,5\}.$$
推荐首个工程版本固定 $a=1200$ 米。站点坐标为 $(0,0)$、$(1200,0)$、$(600,\pm600\sqrt3)$、$(-600,\pm600\sqrt3)$、$(-1200,0)$。这些点全部位于源圆域内;允许域外检测这一规则仍然保留,但本方案不需要依赖它。
### 5.2 连续覆盖证明
**定理1:** 若 $0<a/\sqrt3\le R$,则 $S(a)$ 对 $B(0,R)$ 的覆盖距离满足
$$\max_{g\in\Omega}\min_{s\in S(a)}\|g-s\|\le D(a):=\max\left\{\frac a{\sqrt3},\sqrt{R^2+a^2-\sqrt3Ra}\right\}.$$
**证明:** 任意 $g$ 写成极坐标 $(r,\theta)$。它与最近环上站点的夹角 $\varphi$ 不超过 $\pi/6$。令 $r_0=a/\sqrt3$。若 $r\le r_0$,选择原点,距离至多 $r_0$。若 $r\in[r_0,R]$,选择最近环站,有
$$\|g-s\|^2=r^2+a^2-2ar\cos\varphi\le r^2+a^2-\sqrt3ar.$$
右侧关于 $r$ 为凸二次函数,在闭区间最大值出现在端点。代入 $r_0$ 得 $a^2/3$,代入 $R$ 得第二项平方,从而得到结论。证毕。
代入 $R=1800$、$a=1200$,得到 $r_0=692.820323$ 米,$D(a)=968.901572$ 米,距离接收下界有31.098428米余量。因此每个合法全向源至少可在七站之一被检测到,不依赖位置概率、源数或源频道。
这是连续圆域的证明,不是“抽样没看到空洞”。此外用130501个极坐标采样点复算,最大最近站距为968.901572米,与解析值一致;该数值检查仅辅助发现公式或实现错误,见[覆盖校核数据](C:/Users/HelixCopex/code/MATH/output/q3/search-ablation/benchmark.json)。
**推论:** 对某频道七站全部测得无信号,就能证明该频道不存在源。若真实有源,覆盖定理给出一个距其小于1000米的站,在该站不可能返回无信号,矛盾。对已发现或已清除频道可以停止剩余覆盖检测,必须在逐频道账本中保存其原因。
### 5.3 环半径与时间的权衡
在本七点族内,若要求覆盖距离至多 $d\le1000$,外边界约束为
$$a^2-\sqrt3Ra+R^2-d^2\le0,$$
同时要求 $a/\sqrt3\le d$。当 $d\ge R/2$ 时,环半径的外边界允许区间为
$$R\cos(\pi/6)-\sqrt{d^2-R^2/4}\le a\le R\cos(\pi/6)+\sqrt{d^2-R^2/4}.$$
只按1000米边界、零裕量计算,最小 $a$ 约为1122.955832米;保留1米覆盖裕量时为1125.254906米。1200米不是最短路线的解析最优参数,而是在站距与覆盖裕量之间采用的透明工程选择。较小 $a$ 缩短站间路线,却改变后续发现时的交会几何和定位路程;应在独立场景上比较,不能仅由扫描路长选全局最优值。
从原点先到任一环站,再依次访问相邻五站,不返回原点,纯站间路长为 $6a=7200$ 米。每站最坏扫描20个频道,发现阶段最多140次检测,顺序扫描的换频次数至多139。因此这一**不含定位清除插入**的纯覆盖路线有上界
$$T_{\rm cover}\le7200/5+140\times5+139=2279\text{秒}.$$
不能把2279秒当成全清总耗时上界;定位插入还会改变站间行程。对本次官方案例的10个无源频道,完整覆盖所需检测可从490次降为70次,差420次、2100秒检测时间。这是覆盖账本的解析差额,不是已在相同官方案例实测的新算法收益。
七点既未被证明是最少站数,也未被证明在全部可行布点中路线最短。第四问边界朝外的定向源可看不到这些内侧站点,所以该定理仅进入第三问专用策略。
## 6. 同站批量扫频与定位任务队列
### 6.1 先完成本站,再离站
推荐的第一阶段策略如下:到达一个覆盖站,先对尚需在该站搜索的全部未知频道各测一次。若当前测向频道在待测集合中,将其排第一以节省一次换频,其余频道按固定顺序扫描。`direction` 只更新候选集并加入定位队列;`near` 可以在当前站立即清除,因为不需增加移动。完成本站的频道批次后,再决定离站执行哪些定位任务。
这保留每次请求的串行语义,也避免“查出一个频道—离站—返回—再查下一个频道”的结构性往返。全局频道分组,即先把某频道扫遍全域再换下一频道,虽然省换频,却可能把路径重复十余遍;每次检测移动只有超过5米,其耗时就已超过一次换频,应以空间批处理优先。
### 6.2 队列中的基本排序
第一版对待定位队列按当前点到候选集最小包围圆中心的距离选择最近频道,完成该频道的安全测向和清除后重新排序,然后访问仍有未知频道待测的最近覆盖站。圆心距离只是一种便宜的排序代理,不是实际完成该频道的精确剩余成本。
相比按频道编号处理,重新排序能考虑清除后的新位置;相比扫完七站才定位,同站发现后的批量服务能避免把所有局部信息拖到远处再处理。第12节的消融支持先采用这一方案,但最近优先没有全局最优或对所有场景更快的保证。
同一轮每个待定位频道最多调用一次既有定位子循环;该子循环每轮最多追加8次检测。未解决的频道保留在队列,不能忙等或重复清除同一份失败证书。覆盖阶段结束后再处理未解决任务;预算不足时明确记为未完成。
### 6.3 后续将队列代价改成“插入耗时”
设当前点为 $p$,下一计划覆盖站为 $b$。若某待清除目标允许的位置集合为 $\mathcal C_c$,其插入路径代价可写为
$$\Delta L_c=\min_{q\in\mathcal C_c}\bigl(\|p-q\|+\|q-b\|\bigr)-\|p-b\|.$$
再加5秒清除时间,即可与直接前往下一覆盖站比较。待定位目标用一次或两次安全测向的短程预演估计对应代价。存在多个目标时,采用最近插入、开放路径2-opt或限宽束搜索重排;测量产生新候选集后只执行当前最佳方案的第一步,再重规划。缺少未来目标真值时,这些都是显式的在线启发式。
“把所有新发现目标都做完再去下一站”是第一版规则,后续可允许代价过高的目标暂存,但要设置可审计的最大延后次数,并在搜索终止后清空队列,防止某个难目标长期得不到处理。
## 7. 无信号区域复用与自适应跳站
七点是固定的完成保证,负观测区域允许进一步减少实际检测。在定位、清除行程的已到达位置,可以评估是否顺路测量少量未知频道;每个额外频道仍需5秒,不能把“已到达”解释为“免费探测”。
### 7.1 具有保守性的区域表示
对每个未知频道以方形单元并集 $\widetilde E_c$ 外包 $E_c$。初始保留与 $\Omega$ 可能相交的单元。设单元中心为 $z$、半对角线为 $h$,只有满足 $\|z\|-h>1800$ 的单元才可直接判为域外;边界相交不确定时继续保留或细分。
一次该频道无信号观测位于 $s$,若整个单元满足
$$\|z-s\|+h\le1000-\eta,$$
则单元全部落入保证可收盘,可以安全删除。不得只检查单元中心,也不得用近似覆盖面积达到100%作为判空证据。若单元仍与真实残余相交,就保留它,直至可给出整单元删除证书。
**命题2:** 以上规则维持 $E_c\subseteq\widetilde E_c$,故 $\widetilde E_c=\varnothing$ 足以证明无源。反过来,$\widetilde E_c\ne\varnothing$ 可能只是离散保守性,不能据此断言有源。
七点有31.098米几何余量;可使最终方格边长不超过20米,其直径不超过28.285米。对任意与 $\Omega$ 相交的单元,取其中一个域内点,该点距某站不超过968.902米;单元全部点距该站不超过997.186米。因此在工程裕量小于约2.81米且正确处理边界相交的情况下,七站无信号足以最终删除这些单元。这里用整单元的最大距离证书;若只用 $\|z-s\|+h$ 的较松证书仍未通过,继续细分或直接使用七点账本证明,不错误地停在粗格残片上。
### 7.2 候选点与频道选择
新增候选点来自:未完成的七个锚点、当前位置、已规划的定位点/清除点、残余区域边界附近点。对 $q$ 和频道集合 $F$,定义
$$G(q,F)=\sum_{c\in F}\operatorname{area}\bigl(\widetilde E_c\cap B(q,1000-\eta)\bigr),$$
并以 $G(q,F)/(\|p-q\|/5+5|F|+N_{\rm switch}(F))$ 作为探索排序指标。面积是搜索潜力代理,不是发现概率或保证的信息增益;面积计算可近似,但只影响候选排序。无源判定仍由整区域覆盖证书给出。对极小、线状或退化残余,还要保留单元数、最远未覆盖距离及锚点完成优先级,不能因面积接近零而永久忽略。
在当前位置按每个候选频道的 $G(q,\{c\})$ 与5秒检测、可能1秒换频排序,只有优于当前预演方案时才添加。未来站点若要删除,必须重新证明该频道的剩余 $\widetilde E_c$ 被保留站点的保证接收盘覆盖;一次扫描所得“没有发现”只删该次盘内区域,不能整片按经验跳过。
### 7.3 完备后备
七点中未完成的“站点—频道”记录始终保留。自适应探索若连续不产生新的可靠覆盖、计算超时或动态证书不确定,则恢复固定七点访问。设置有限的额外探测额度或要求每次替换都完成至少一个新的覆盖记录,使启发式不能无限拖延覆盖完成。
这给出确定性的搜索后备:自适应部分只允许节省已证明冗余的动作,不允许删除尚未证明冗余的覆盖责任。该设计尚未进入当前生产实现,也未包含在第12节的七点消融中。
## 8. 定位和清除也应优化剩余时间
### 8.1 定位到“够清除”就停止
设保守多边形 $\widetilde K_c$ 的最小包围圆为 $B(m_c,\rho_c)$。清除阈值使用 $r_{\rm safe}=20-\varepsilon$,其中 $\varepsilon$ 覆盖实际计算和坐标提交误差。若 $\rho_c\le r_{\rm safe}$,就具有一次清除证书;没有必要为了获得更小半径继续增加检测或横移。
外包多边形本身已经包含真集,它的多余面积使决策更保守;不能把“外包多边形与原圆盘的径向差”未经传播分析当作浮点误差保证。现有实现还扣除了 `slack_m` 和工程清除余量,本次消融完整保留其行为;后续统一外包与数值误差口径时另行验收。
### 8.2 在所有保证清除点中选择短路径位置
若 $V_c$ 为 $\widetilde K_c$ 的顶点,则
$$\mathcal C_c=\bigcap_{v\in V_c}B(v,r_{\rm safe})$$
是凸集,非空当且仅当 $\rho(\widetilde K_c)\le r_{\rm safe}$。圆盘凸性保证覆盖全部顶点等价于覆盖整个多边形,故任意 $q\in\mathcal C_c$ 都能清除真源。
无后续任务时,选择 $\arg\min_{q\in\mathcal C_c}\|q-p\|$;已计划下一站 $b$ 时选择 $\arg\min_{q\in\mathcal C_c}(\|p-q\|+\|q-b\|)$。两者都是凸优化问题,可用二阶锥形式表达,也可在圆盘交的候选边界上求解后逐顶点复核。
轻量实现可先使用内部安全圆盘 $B(m_c,r_{\rm safe}-\rho_c)\subseteq\mathcal C_c$:将 $p$ 投影到该圆盘即可得到一个不远于前往 $m_c$ 的保证清除点。这只是对该充分圆盘的最近点,并非对整个 $\mathcal C_c$ 最优。若圆盘半径为0就退化到 $m_c$。
### 8.3 安全测点的目标由半径改为任务耗时
问题二提供的安全区域为 $\mathcal Q(K_c)=\bigcap_{g\in K_c}B(g,1000)$,可用解析盘或保守多边形构造充分区域。选点仍必须先满足接收保证,不能为走近一个猜测坐标而接受未经评估的失联风险。
在可安全测量的候选点中,使用以秒计量的短程代价
$$J_H(q)=\frac{\|p-q\|}{5}+5+\mathbf1_{f\ne c}+\max_{z\in\mathcal Z(q)}\widehat V_{H-1}(K_c\mid q,z;q,c),$$
其中 $z$ 包含 `near` 及允许的示向度,$\widehat V$ 估计完成该源及返回后续任务的时间。若某分支已能保证清除,其终端代价包括移动至 $\mathcal C_c$ 的时间和5秒清除;若未能清除,可继续一层安全测向,或赋予经过标定的剩余定位代价。未来测点、清除位置与访问顺序共同影响 $\widehat V$。
这个形式解释了为什么“后验半径更小”不一定“完成更快”:走远很久将半径降到5米,可能劣于近处测量后已经达到19米。所有实际比较项统一为秒,避免随意相加米、面积和时间。有限候选和有限视野只给出预演策略的启发式排序。
若要把 $\max_z$ 报告为严格上界,必须采用问题二第10节覆盖全部读数的角区间扩张,并对区域误差与终端代价也作保守上界。当前“边界位置采样×误差端点”并无该保证,不能仅因取了样本最大值就声称最坏总时间已受控。推荐先保留现有局部选点,验证搜索调度收益,再单独启用这一成本模型。
## 9. 保守性、有限结束与预算边界
**命题3(不漏发现):** 固定七点对每个仍未知频道完成扫描,或由可靠的残余覆盖/数量证书替代相应扫描,必能发现所有合法全向源。
**证明:** 固定点由定理1保证;动态替代保持该频道覆盖域包含所有仍可能位置;数量证书只在已有16个不同源的存在证据时排除其他频道。因此真源不可能被当作无源跳过。证毕。
**命题4(证书清除):** 若维护的外包集合包含真源,实际提交点满足对该外包的20米清除约束,则在题设规则下 `/clear` 必成功。几何证书通过而官方失败时必须记录异常并检查模型、数值及协议状态,不能在同一证书上循环重试。
上述命题不证明任意安全测点序列都会有限步收缩到20米。现有每轮8次测量是工程限额,不能作为收敛定理。拟在后续增加有限后备:对已发现频道的有界外包区域,用边长20米方格的中心覆盖所有相交格,任意格内点至格心不超过 $10\sqrt2<20$ 米;遍历该有限清除候选即可在模型成立时清除源。单元相交计算必须向保留更多格的方向保守。
后备仅在定位停滞时使用,并须先检查实际枚举格数、路径和预算。设当前到首格及格间的计划路长为 $L_f$,共 $M_f$ 格,最迟第 $M_f$ 格成功的虚拟耗时上界为
$$T_f\le L_f/5+3(M_f-1)+5.$$
使用相交格数硬顶、现实高分位单请求估计 $M_f\,t_{\rm RTT}^{95}$ 加退出预留,以及虚拟剩余预算共同筛选。现有第四问中的后备格算法可供复用,但不能跳过第三问的验证。硬顶或预算不允许时,保留“未完成”,不将耗尽预算说成证明无源。
因此本文区分三层结论:覆盖与证书的数学安全性;预算足够且正确遍历有限后备时的有限完成性;现实/虚拟双预算内的性能,目前由实验评价,尚无所有合法场景的统一完成上界。
## 10. 推荐算法与伪代码
**算法3A:七点覆盖+同站批量扫频+就近定位清除(优先落地版本)。**
```text
读取第三问参数,生成七点 S(1200),初始化逐频道观测和覆盖账本
调用 /enter,记录官方时间预算
while 尚有未知频道的站点记录未完成:
若预算不足:标记未完成,转退出
选择仍有未知频道待测的最近站点 s
在 s 批量测量待查频道(当前测向频道若在其中,优先测)
no_signal:记录该频道在 s 的覆盖证据
direction:更新该频道 K,加入待定位队列
near:在 s 清除并依据响应更新状态
对本站结束后的待定位队列:
按当前位置到候选圆心距离选最近频道
调用问题二安全选点与问题一清除证书完成其定位子循环
清除成功后重新排序;未完成者保留,单轮不无限重试
若已清除16个:结束任务
根据逐频道七点账本标记无源;继续处理尚未清除的已发现频道
仅在全频道均已清除/有无源证明时标记完成
调用 /exit;退出响应失败单独记录,不能宣称正常结束
```
**算法3B:在3A之上逐项增加的完整改进规划。** 每次 `direction/near` 更新存在集合 $\mathcal P$,达到16时提前结束未知频道搜索;在各实际测量点更新负观测区域并进行有证书的站点替代;用插入耗时比较“先搜下一站”与“先做某个源”;对候选路线重排;以预计剩余时间选择安全测点,在可清除区域中选择省路位置;定位停滞时按预算调用有限后备。每执行一个动作就用真实响应更新状态,禁止整段盲执行预测的后续动作。
```mermaid
flowchart TD
A[进入并读取预算] --> B[更新逐频道证据与完成条件]
B -->|已全清且无遗漏证明完整| X[退出并保存日志]
B -->|预算不足| Y[按未完成退出]
B -->|仍有任务| C[候选覆盖站与定位清除任务]
C --> D[比较短程总耗时并保持覆盖责任]
D --> E[同站批量扫描或执行一次定位清除动作]
E --> F[接收官方响应并验证候选及证书]
F --> B
```
第一版和后续规划分别命名,防止把3B尚未实现的负观测跳站、时间型选点和后备算法算进3A的测试成绩。
## 11. 计算量与工程实现
七点固定账本最多 $7\times20=140$ 个布尔记录。最近站选择检查7个点,每次按至多20个频道统计待测项;16个源的贪心任务队列重排规模很小。固定站路线的开放路径最优排序如需精确解,可使用子集动态规划,规模为 $O(k^2 2^k)$、$k\le7$;但加入观测依赖的定位任务后不再是同一个静态问题。
定位计算仍主要消耗在多个候选点、候选源见证点、读数分支的几何裁剪和最小圆计算。假设候选测点 $Q$ 个、读数区间 $B$ 个、外包顶点 $V$ 个,单层保守评估包含 $QB$ 次裁剪和最小圆计算,可表示为 $O(QB[V+T_{\rm MEC}(V)])$;两层分支不能简单称为线性。复用候选集缓存、先粗筛少量入围点,再完整区间验证,能够控制现实计算预算。
残余区域若使用 $H$ 个单元,20频道掩码空间为 $O(20H)$,一次频道负观测朴素检查 $O(H)$;可以预计算七锚点的单元覆盖掩码,并通过空间索引限制动态点的更新范围。分辨率只控制证书的保守程度,不得因内存不足删除尚未证实的残余格。
| 模块 | 当前事实 | 建议改动 |
| --- | --- | --- |
| `coverage` | 共用49点与逐频道账本 | 新增第三问七点构造;保留第四问网格及其独立证明 |
| `planner.OmnidirectionalLoop` | 发现后立即离站定位 | 把“本站扫频”与“队列服务”拆开,引入第三问策略选项 |
| `belief` | 无信号不裁剪候选 | 增加第三问独立残余覆盖层,避免破坏第四问朝向语义 |
| `geometry/planning`、`planner` | 有安全选点与最小圆证书 | 后续增加最近安全清除点和时间型候选评分 |
| `evaluation` | 浮点累计、固定微秒容差 | 单独兼容官方逐步微秒时钟和自建连续时钟,保留两种原始口径 |
| `protocol` | 串行、幂等、预算退出、JSONL日志 | 延用;增加的动作仍走同一客户端,不能并发测多个频道 |
实际路径分别位于 [coverage](C:/Users/HelixCopex/code/MATH/src/mcm26b/coverage/__init__.py)、[planner](C:/Users/HelixCopex/code/MATH/src/mcm26b/planner/__init__.py)、[belief](C:/Users/HelixCopex/code/MATH/src/mcm26b/belief/__init__.py)、[evaluation](C:/Users/HelixCopex/code/MATH/src/mcm26b/evaluation/__init__.py)。前两问文档中部分旧路径仍写为根目录 `geometry`,复用时以当前 `src/mcm26b/geometry` 为准。
## 12. 已完成的自建配对消融
### 12.1 实验口径
为验证优先级,新增独立脚本 [benchmark_q3_search.py](C:/Users/HelixCopex/code/MATH/scripts/benchmark_q3_search.py),只连接进程内 `LocalSimulator`,不连接官方端口、不修改生产策略。数据保存在 [search-ablation](C:/Users/HelixCopex/code/MATH/output/q3/search-ablation/benchmark.json),同时逐局保存源场景、固定误差场种子、接受动作日志与哈希。
共12个场景:源数10和16各一组,每组包含 `random_omni_scene` 种子0、1、2、3、4的5个场景,以及1个源位于1800米边界、接收半径均为1000米的场景。随机生成器径向采样不是圆域面积均匀分布,并特意含近边界源,不将其称为真实场景分布。各变体使用同一局源坐标、接收半径、频道和固定空间误差场;不同位置的合成误差机制不代表官方误差场。边界例包含扇区接缝附近的源。
比较四种版本,均沿用现有安全选点与清除内核、舍入裕量0.005°和8次追加检测限额:
| 版本 | 唯一涉及的搜索与调度变化 |
| --- | --- |
| A0:49点即时定位 | 当前生产基线 |
| A1:七点即时定位 | 只把覆盖点换成七点,仍发现即离站 |
| A2:七点本站批量 | 本站扫频完成后,按最近候选圆心服务队列;当前频道优先 |
| A3:七点全域先扫 | 扫完所有必要覆盖站后,再按最近候选圆心定位;near仍原地清除 |
A2/A3都包含当前频道优先这一小优化,因此A1与A2之差不是“纯粹只改变一个排序变量”的严格单因素实验。后续应再拆分消融换频顺序。3B的动态残余区域、16个已发现源提前停止搜索、时间型选点、最近安全清除点及后备均未在这组实验启用。
### 12.2 全部12个场景结果
| 版本 | 全清且正常完成 | 平均虚拟时间 / 秒 | 平均检测数 | 平均移动距离 / 米 | 平均逐局时间降幅 |
| --- | ---: | ---: | ---: | ---: | ---: |
| A0 | 12/12 | 13788.04 | 418.00 | 56183.95 | — |
| A1 | 12/12 | 7476.09 | 100.42 | 34146.70 | 43.25% |
| A2 | 12/12 | 5496.20 | 100.92 | 24177.66 | **58.55%** |
| A3 | 12/12 | 6094.73 | 101.67 | 27164.04 | 53.90% |
每个版本共清除156个源,48局合计624个源全部清除,无失败清除、无错误缺席判定、无定位异常。A2相对A0的逐局降幅范围为37.50%至70.84%。降幅按 $\frac1n\sum_i(1-T_{A2,i}/T_{A0,i})$ 计算,不能与两个均值之比混称同一个指标。
另以保存的自建场景真值独立复核48局动作日志,逐步检查正观测后的候选保留真源、清除证书及实际清除距离、全清集合、计时、检测数、退出响应与日志哈希,全部通过,见[证据复核结果](C:/Users/HelixCopex/code/MATH/output/q3/search-ablation/evidence-audit.json)。这些真值只用于离线验收,不进入策略。
| 源数(每组6场景) | A0平均时间 / 秒 | A1平均时间 / 秒 | A2平均时间 / 秒 | A3平均时间 / 秒 |
| --- | ---: | ---: | ---: | ---: |
| 10 | 15516.58 | 6313.47 | **4836.11** | 5467.38 |
| 16 | 12059.50 | 8638.71 | **6156.28** | 6722.08 |
10源时,未知频道的无源证明开销较大,所以七点替换收益明显;16源时,可通过清除数量上界提前停止,原网格未必扫完,但批量调度仍显著减少移动。A1与A2检测数相近,A2平均移动距离进一步下降,表明减少往返比单纯少测一次更有价值。这组自建证据支持优先实现A2,而非先投入复杂概率图、强化学习或全局非线性优化。
四版本平均本地计算墙钟约1.7至1.8秒/局,记录在数据中;它不含官方网络、真实程序截止或官方UI开销,不能当作新方案官方现实耗时。原官方动作日志只能验证旧路径上的响应,不能用它推断新测点的读数。只有在官方新演练执行新策略后,才能报告官方提速。
### 12.3 复现
```powershell
.venv/Scripts/python.exe scripts/benchmark_q3_search.py --seeds 0,1,2,3,4
```
也可使用 `uv run python` 调用同一脚本。输出包含原始逐局数据,失败不会从汇总中剔除。当前实验是小规模方案筛选,不能证明所有合法场景、所有固定误差场或不同环半径下的性能。
## 13. 分阶段改进与验收计划
| 阶段 | 交付 | 必须通过的验收 |
| --- | --- | --- |
| I:七点+本站批量 | 将A2接入第三问CLI选项,保留A0可切换;原始日志格式兼容 | 七点连续覆盖证明与坐标误差预算;10/16源及边界例全清;第四问覆盖策略未被改动 |
| II:存在计数与扫频次序 | $|\mathcal P|=16$ 提前停止未知频道扫描;同站频道优先独立消融 | 已发现数、已清除数不混淆;发现10个不能停;clear不改变测向频道 |
| III:残余覆盖与顺路观测 | 保守单元账本、负观测复用、有证书跳站 | 边界及单元接缝不漏;未知频道各有独立覆盖责任;启发式停滞自动恢复七点 |
| IV:时间型局部动作 | 最近安全清除点、短程任务预演、插入排序 | 实际提交点满足全部外包顶点约束;near和跨0°读数正确;采样评分不冒充严格上界 |
| V:定位停滞与预算后备 | 有界区域有限清除覆盖,明确上限与退出 | 清除格子覆盖全部候选;格数/两种时间预算不足均记未完成;故障与失败可回放 |
每个阶段都在相同场景和同一固定误差场上进行配对比较。建议将种子0—4保留为本次开发集;最终验证另生成独立种子100—199,并分别覆盖10至16个源、接收半径1000和1500米、边界源、团簇源、同站near、接近共线读数、误差恰在±1°及空间相关误差场。所有超时、矛盾和未全清样例进入结果表,不允许只报成功局。
主要指标为全清且正常退出比例、平均/中位/P95/最大虚拟总时间、移动长度、检测数、换频数、清除失败数、证明无源的成本;同时报告最后清除时刻、现实计算时间与总请求数。小样本不确定性用逐局配对差分及其范围表达,增加样本后可在声明抽样假设的前提下给出区间估计;不从当前12例推出总体成功率为100%。
官方验收继续使用 socket 接口,逐条保存请求响应,最后保存官方结果及加密日志;优先使用官方支持的同案例复现功能进行配对,如果无法复现同一案例,就分别报告案例差异,不将两次随机局的时间差当成纯算法收益。本轮只完成方案研究与自建实验,没有再次启动官方演练。
## 14. 结论与实现边界
第三问首先应把覆盖责任从49点缩减为已证明足够的七点,并将覆盖站内扫频和离站定位拆开。该改进直接针对官方日志中的主要开销,在保持几何定位方法不变时,已经得到12个自建场景的配对支持。推荐先落地A2,再独立验证存在数量上界、残余覆盖和时间型测点/清除点优化。
初稿形成时,七点与三种调度变体存在于离线消融脚本,官方仅验证A0;随后A2已通过下述一次官方演练。生产 `src/mcm26b` 默认策略仍未修改,A2由独立运行脚本调用。3B给出了可实现的进一步规划,但没有将其预期收益写成已测结果。固定覆盖、观测集合和清除证书负责可靠性;候选评分、任务排序和半径调参负责效率,二者的保证范围分别陈述。
## 15. 补充:A2官方演练已通过
在方案研究之后,用户启动新的问题3演练,于2026-09-11通过2026端口实际执行A2。案例 `J4ER-Y9EP-Q379-UPFA` 的官方源数为12,12个全部清除,109次检测、12次清除无失败,现实耗时3.406秒,总虚拟耗时5232.132109秒(1小时27分12秒),移动22645.661米。其余8个频道各有完整七点无信号记录,最终正常退出。
123个请求响应已严格离线回放,清除证书和官方微秒计时全部通过复核。原始数据、官方产物、运行代码哈希及复现入口见[本局验证报告](C:/Users/HelixCopex/code/MATH/output/q3/practice/20260911-seven-batch-01/report.md)。因此A2现已有自建配对实验及一个官方案例的有效性证据。
相较之前A0官方10源案例的16217.454814秒,本局虚拟时间少67.74%,但案例和源数不同,不能把该差异称为严格算法提速率;第12节的58.55%仍仅指12个自建场景的配对平均结果。3B的进一步改进尚未启用。
## 参考文献
1. 全国大学生数学建模竞赛组委会. 2026年高教社杯全国大学生数学建模竞赛B题:无线电干扰源的快速自动定位与清除[Z]. 2026. [题面](C:/Users/HelixCopex/code/MATH/issue/B题.pdf);模拟器配套材料《附件2:模拟器通信接口说明及编程指南》[本地文件](C:/Users/HelixCopex/code/MATH/issue/附件/附件2.docx)。
2. 本项目. 问题一:有界测向误差下定位区域的直径与圆覆盖;问题二:具有接收保证的第二检测点选择[Z]. 2026. [algo-1](C:/Users/HelixCopex/code/MATH/docs/algo-1.md)、[algo-2](C:/Users/HelixCopex/code/MATH/docs/algo-2.md)。
3. BAYRAM H, VANDER HOOK J, ISLER V. Gathering Bearing Data for Target Localization[J]. IEEE Robotics and Automation Letters, 2016, 1(1): 369–374. DOI: 10.1109/LRA.2016.2521387. [作者所在大学的研究记录](https://experts.umn.edu/en/publications/gathering-bearing-data-for-target-localization-6/)。核对题目、作者、页码及移动与测量联合代价;未套用其GDOP近似比。
4. OLOFSSON J, HENDEBY G, LAUKNES T R, JOHANSEN T A. Multi-Agent Informed Path Planning Using the Probability Hypothesis Density[J]. Autonomous Robots, 2020. [作者公开稿](https://torarnj.folk.ntnu.no/AURO2020a.pdf),第1—2节。用于未观测区域与预算路径的建模对照。
5. PERERA A, TRAN V P, ANAVATTI S, KASMARIK K, GARRATT M. Radio Source Localization using Sparse Signal Measurements from Uncrewed Ground Vehicles[EB/OL]. arXiv:2312.03493, 2023. [原文入口](https://arxiv.org/abs/2312.03493)。用于稀疏覆盖与实验设计的对照,RSSI估计器未迁移。
6. ATANASOV N A, LE NY J, PAPPAS G J. Distributed Algorithms for Stochastic Source Seeking with Mobile Robot Networks: Technical Report[EB/OL]. arXiv:1402.0051v2, 2014. [原文入口](https://arxiv.org/abs/1402.0051)。用于说明场强梯度和测量模型假设的适用边界,不引用其结论证明本算法收敛。
在线来源核对日期:2026-09-11。本文的七点构造、覆盖界和具体调度规划来自对题设参数的推导与本项目实验,不宣称一般几何和路径规划思想在文献中首次出现。
+167
View File
@@ -0,0 +1,167 @@
# 问题3/4 强化学习选点(PPO + CUDA)
## 0. 摘要
**2026-09-11审核更新:**本文件下方的训练成绩与BC准确率是第一版历史记录。
复核发现训练/部署特征错位、BC激活函数不一致以及评测只检查completed等问题。
当前修复、Maskable PPO新模型和独立配对验证见
[强化学习适用性审核与改进](强化学习适用性审核与改进-20260911.md)。
新模型未替换原默认检查点;通过`--rl-model`显式加载。
本项目在保持 P0–P5 保守性与可解释证明不变的前提下,为问题3(全向源)与
问题4(定向源)增加了一个可选的**强化学习测量点选择策略**:
- 把“下一检测点去哪”建模为离散动作的局部决策问题;401维特征是压缩观测,
不能认定为完整马尔可夫状态,尤其第四问仍有未知朝向和被省略的历史约束;
- 状态由逐频道信念的几何特征 + 60 个候选检测点的几何特征组成(401 维);
- 动作为 60 选 1(保证接收盘环候选、对称交会候选、定向遮挡环探候选);
- 使用 Stable-Baselines3 的 PPO 训练,MLP 策略与价值网络在 **CUDA GPU**
(本机 RTX 4060 Laptop, CUDA 12.8 / torch 2.11.0+cu128)上更新;
- 训练环境基于自建评测机 `referee`(内存回环,与真实 HTTP 协议同边界);
- 运行闭环仅替换既有选点排序器,覆盖证明、清除证书、定向后备清除全部保留。
历史结果(第一版自建配对消融,5 个种子):Q3 用 12 万步随机初始化 PPO(与 `bayes`
基本持平,+1.18%);Q4 用**专家行为克隆初始化 + PPO 微调**,混合源平均
虚拟时间相对 `directional` 基线降低 **7.16%**(14250.1s → 13230.2s)。
Q3 的 BC 初始化在消融中反而退化,因此保留随机初始化模型;Q4 的 BC 初始化
是当时五场比较中均值最好的版本。官方演练验证见 §5:两次 Q4 演练(3 定向混合源、10 定向全定向
场景)与一次 Q3 演练均全清,且通过离线审计。
## 1. 环境搭建(CUDA)
```powershell
# 安装可选依赖组 rl(PyTorch CUDA 12.8 + stable-baselines3 + gymnasium)
uv sync --group rl --group dev
# 验证 CUDA
uv run python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
```
`pyproject.toml` 中 `[tool.uv.sources] torch = { index = "pytorch-cu128" }`
与 `[[tool.uv.index]]` 指向 PyTorch 官方 CUDA 12.8 轮子;下载约 2.6 GB,
首次同步建议 `$env:UV_HTTP_TIMEOUT='300'`。默认 PyPI 的 Windows torch 轮子
为 `+cpu`,可以使用CPU训练;本轮修订模型即采用CPU,CUDA并非训练前提。
## 2. 第一版局部决策环境
训练环境:`src/mcm26b/rl/env.py::LocalizationEnv`。
| 项 | 定义 |
| --- | --- |
| 初始状态 | 自建模拟器随机布设一个源(Q3 全向;Q4 定向比例可调,训练默认 1.0),机器狗完成一次保证得到 `direction` 的首测 |
| 观测 | 401 维:21 个全局特征 + 20 维频道 one-hot + 60×6 维候选点特征(见 `features.py`) |
| 动作 | `Discrete(60)`:0=候选集 MEC 圆心,1..36=保证接收盘 3 环×12 方向,37..51=对称交会 15 点,52..59=定向遮挡环探 8 点 |
| 转移 | 按动作位置调用 `/measure`,用 `BeliefState` 保守更新候选集;Q4 保证接收盘内 `no_signal` 记为朝向遮挡并进入 `blocked` 序列;证书达标后自动 `/clear`;遮挡梯子用尽后模拟 20m 网格后备清除 |
| 奖励 | `-Δvirtual_time/100`(移动+检测+换频+清除真实耗时)、候选半径收缩加成、首次遮挡证据 +2、重复测点 -0.75、清除成功 +10、失败/截断负奖励 |
约束说明:候选点全部来自既有几何生成器(`planner.candidate_points`、
`planner.safe_disk_radius`、定向环探梯子),RL 不生成新的空间候选;它只做
排序。清除仍须通过几何证书;但“保证收到方向”只适用于全向源且实际点位于
距离保证盘内。第一版的52—59号环探点可能在盘外,第四问的定向遮挡也不受
距离盘保证。v2对第三问加入盘外动作屏蔽,第四问保留探索分支。
## 3. 训练与自建模拟器逻辑利用
```powershell
# 1) 用自建模拟器上的手写专家生成 (观测, 动作) 并行为克隆
uv run python scripts/pretrain_rl_expert.py --problem 3 --episodes 3000
uv run python scripts/pretrain_rl_expert.py --problem 4 --episodes 3000
# 2) 从当前v2 BC初始化继续普通PPO(算法类型需显式匹配)
uv run python scripts/train_rl.py --problem 4 --algorithm ppo --timesteps 40000 \
--init output/rl/q4_ppo_bc_init.zip
# Q3 保留随机初始化长训练版本:
uv run python scripts/train_rl.py --problem 3 --timesteps 120000
```
专家逻辑与自建模拟器同源:Q3 用 worst-posterior 选点器,Q4 用对跖/环探
遮挡梯子;`pretrain_rl_expert.py` 在 `LocalizationEnv` 上记录每个状态的
专家动作,训练与 PPO policy_net/action_net 同构的 MLP,再把权重拷入 PPO
作为初始化。产物位于 `output/rl/bc/` 与 `output/rl/q{3,4}_ppo_bc_init.zip`。
实测:Q3 专家数据 5141 条、BC 验证准确率 38.9%,微调后自建消融退化
(保留 12 万步随机初始化模型);Q4 专家数据 14181 条、BC 验证准确率
65.3%,微调后自建消融从 −3.84% 提升到 **−7.16%**。但审核确认BC与PPO的
激活函数不一致,这些数字不能证明成功迁移了专家策略,也不足以判断全向分支已最优。
输出:`output/rl/q3_ppo.zip`、`output/rl/q4_ppo.zip` 及同名 JSON 报告;
训练脚本先打印 `train_start`(含 device/gpu 字段),再执行 PPO 并在独立
种子场景上确定性评估成功率、平均步数与平均回报。Q4 4 万步微调约 236s;
Q3 12 万步约 625s(RTX 4060 Laptop,2 个 CPU 环境)。
## 4. 运行闭环接入
- Q3:`uv run mcm26b run --robot-id 2026001 --self-test --strategy rl`
`RLBayesLoop` 继承 `BayesLoop`(七点覆盖 + 网格粒子滤波 + 滚动 2-opt),
仅 `_select_point` 改由 PPO 输出候选编号。
- Q4:`uv run mcm26b run --robot-id 2026001 --self-test --problem 4 --q4-strategy rl`
`RLDirectionalLoop` 继承 `DirectionalExtension`(49 点覆盖 + 遮挡梯子 +
20m 有限圆盘后备清除),仅 `_next_probe` 改由 PPO 输出。
- 模型加载时校验观测 401 维 / 动作 60 维,失配直接拒绝运行。
- 默认运行路径不导入 torch/referee;只有显式选择 `rl` 才惰性导入,项目
运行时依赖仍保持 `requests` 一项。
## 5. 消融基准
```powershell
uv run python scripts/benchmark_rl.py --seeds 5
```
同种子同场景配对比较,结果写入 `output/rl/benchmark.json`。以下为第一版历史结果:
| 场景 | 基线 | 平均虚拟时间(基线 / RL) | 相对差 | 全清 |
| --- | --- | --- | --- | --- |
| Q3(10 源全向 ×5 种子,scratch PPO) | `bayes` | 3088.3s / 3124.8s | +1.18% | 5/5 |
| Q4(10 源、3 定向 ×5 种子,BC+PPO) | `directional` | 14250.1s / 13230.2s | −7.16% | 5/5 |
训练局评估:Q3 单源 40 局成功率 100%、平均 3.55 步;Q4 定向单源 40 局
成功率 90%、平均 4.45 步;其余单源训练局未完成,不能由此宣称已兜底成功。随机策略对照:
Q3 平均回报 13.28 vs PPO 17.71;Q4 平均回报 8.72 vs BC+PPO 12.62。
### 5.1 官方模拟器演练验证(仅演练,未触碰正式测试)
使用目录内官方 `jammers-simulator-full` 的**演练测试**(不限次数),通过
官方 HTTP 接口运行同一闭环;官方产物按原名归档并离线审计:
| 问题 | 案例 | 场景真值(演练结束后可见) | 结果 | 虚拟时间 | 请求数 | 审计 |
| --- | --- | --- | --- | --- | --- | --- |
| Q3 | `F38Y-9Q9J-B82V-CB9Z` | 13 全向 | 13/13 全清 | 3538.8s | 124 | ✅ |
| Q4 | `X43X-VMRF-8GRZ-3SYA` | 7 全向 + 3 定向 | 10/10 全清 | 14003.1s | 619 | ✅ |
| Q4(BC) | `BXSA-TFQ3-2DJ6-DHH7` | **10 定向** | 10/10 全清 | 14562.8s | 691 | ✅ |
前两次为随机初始化模型,第三次为 BC 初始化微调模型。两个 Q4 官方案例的
源构成不同(3 定向 vs 10 定向),**虚拟时间不可直接相减比较**;可确认的
是 RL 在官方混合源与全定向源演练中都能完成全部清除,且
`all_timestamps_match_microsecond_recomputation`、官方 `.jlog` 的
SHA-256 校验全部通过。归档目录:`output/rl/official-practice/`。
### 5.2 自建 referee 演练验证
`uv run mcm26b run --local-judge` 走自建 referee 的 `q3_practice` /
`q4_practice` 模块(与官方相同的演练生命周期,真值在结束后可见):
| 问题 | 案例 | 场景 | 结果 | 虚拟时间 | 归档 |
| --- | --- | --- | --- | --- | --- |
| Q3 | `FKUY-K8KJ-RXRL-FMBM` | 10 全向 | 10/10 全清 | 3317.6s | `output/rl/local-practice/q3/20260911-rl-01` |
| Q4 | `3J8T-L9GY-HRGL-LYVZ` | 7 全向 + 3 定向 | 10/10 全清 | 11942.8s | `output/rl/local-practice/q4/20260911-rl-01` |
| Q4(BC) | `VM2G-UVC6-4N7R-TVGW` | 7 全向 + 3 定向 | 10/10 全清 | 12520.8s | `output/rl/local-practice/q4/20260911-rl-bc-01` |
不同案例仍不可直接比较;成对可比的提升证据是 §5 的 5 种子同场景消融。
## 6. 结论与边界
以下是第一版结论;BC权重拷贝缺陷使“同构初始化”的解释不成立,性能判断
应以新审核报告的同场景验证及不确定性为准,而不能由BC分类准确率推出。
- RL 已接入问题3/4 完整闭环,并在自建 referee 演练与官方模拟器演练中
全清验证;这是方法验证,不是对正式成绩的承诺。
- 第一版Q4的BC初始化后均值变化为−3.84% → −7.16%,但初始化存在激活函数
缺陷,样本数也不足以支持“明确收益”的归因;当前判断见新审核报告。
- 训练环境使用自建场景假设(源均匀分布、逐点固定误差场、定向源朝向随机);
官方隐藏分布未必相同。正式测试仍应默认使用经过演练验证的手写策略;
`--strategy rl` / `--q4-strategy rl` 适合消融、方法对比与后续调参。
- 官方演练仅使用“演练测试”按钮与开放接口,从未点击“正式测试”;官方
`.jlog/.result.json` 保持原样,未解密。
- 保守性不变式:RL 只改变选点排序,不改变覆盖账本、候选集更新、清除证书
与后备清除的数学证明;所有策略均以 `/exit` 与完整日志收尾。
+117
View File
@@ -0,0 +1,117 @@
# HRL P0+P1 执行报告(本地自建评测机)
日期:2026-09-11(本机工作区)
范围:按用户确认,仅完成 P0 正确性回归 + P1 最小可训练/可评测闭环;
P2 的 BC、完整课程长训、Optuna、正式消融与正式测试表留待下一阶段。
## 1. 本轮代码交付
| 文件 | 内容 |
| --- | --- |
| `scripts/benchmark_hrl.py` | 同一 manifest 真值场景复用;`hrl`/`hrl_heuristic`/`bayes`/`directional` 配对评测;写 `results.json`、`aggregate.json/csv`、每局 `summary.json` 与 `session.jsonl` |
| `scripts/train_hrl_high.py` | 高层 MaskablePPO 训练;`--problem/--stage/--envs/--vec-env/--device/--config-profile/--reward-profile/--model/--resume/--init/--eval-manifest`;模型元数据固化 feature/action/reward 版本;墙钟硬上限 |
| `src/mcm26b/hrl/constants.py` | 新增 `ACTION_LAYOUT_VERSION=1`、`REWARD_VERSION=1` |
| `src/mcm26b/hrl/policy.py` | 高层模型严格校验元数据;低层模型保持独立基础校验 |
| `src/mcm26b/cli.py` | 新增 `--strategy hrl`、`--q4-strategy hrl`、`--hrl-model`、`--hrl-low-model`、`--hrl-device`、`--trace-low` |
| `src/mcm26b/hrl/hierarchical_env.py` | 新增 `HRLReward.time_only()`:P0.4 建议的纯时间目标,去掉逐源清除/发现/熵减塑形 |
| `project/` | 严格目录树薄兼容层,转发真实实现,不复制算法 |
| `tests/test_hrl_p1.py` | manifest 往返、真值隔离、纯时间奖励、project re-export 回归 |
## 2. 全量回归
```bash
.venv/bin/python -m pytest -q --tb=short
# 275 passed in 124.57s
```
## 3. P1 smoke 训练(本机 Apple MPS)
```bash
.venv/bin/python scripts/train_hrl_high.py \
--problem 3 --stage 1 --timesteps 2048 --seed 320001 \
--envs 1 --vec-env dummy --device mps \
--config-profile production --reward-profile time \
--model output/hrl/p1-smoke-time/q3.zip \
--eval-episodes 2 --rollout-steps 128 --batch-size 128 \
--n-epochs 3 --max-wall-s 800 --verbose 0
```
结果:
- `actual_timesteps=2048`,墙钟 `260.069 s`;
- 保存后确定性评估 2/2 成功,`accounted=20`,无异常;
- 模型元数据含 `feature_version=4`、`action_layout_version=1`、
`reward_version=1`、`reward_profile=time`、`model_sha256`。
模型重载已由以下两条路径验证;`--resume` 的 `--timesteps` 是增量步数
(SB3 `reset_num_timesteps=False` 语义),元数据写 `timesteps_semantics="additional"`:
```bash
.venv/bin/python -m mcm26b.cli run \
--robot-id 2026001 --self-test --strategy hrl \
--hrl-model output/hrl/p1-smoke-time/q3.zip --hrl-device mps \
--sources 3 --seed 1 --summary-steps 5
python scripts/benchmark_hrl.py --variants hrl \
--hrl-model output/hrl/p1-smoke-time/q3.zip --hrl-device mps \
--problem 3 --scenes 1 --sources 3 --output output/hrl/p1-bench-hrl
```
## 4. 多轮本地配对测试
### Q3:3 个独立场景 × 3 个变体
```bash
python scripts/benchmark_hrl.py --variants hrl,hrl_heuristic,bayes \
--hrl-model output/hrl/p1-smoke-time/q3.zip --hrl-device mps \
--problem 3 --scenes 3 --sources 3 --start-seed 91000 \
--output output/hrl/p1-multiround-q3
```
| variant | episodes | valid_rate | cleared_mean | virtual_time_mean_s | virtual_time_std_s | program_run_time_mean_s |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| bayes | 3 | 1.0 | 3.0 | 2518.371 | 74.183 | 0.748 |
| hrl_heuristic | 3 | 1.0 | 3.0 | 2518.371 | 74.183 | 0.883 |
| hrl | 3 | 1.0 | 3.0 | 3731.380 | 120.536 | 1.853 |
结论:P1 模型只在 stage 1 单源课程上训练 2048 步,可直接重载并在 3 源场景保持 3/3 有效全清;
但用时明显未优于 bayes/heuristic,符合本轮不做正式性能声明的边界。
### Q4:3 个独立混合源场景 × 2 个变体
```bash
python scripts/benchmark_hrl.py --variants hrl_heuristic,directional \
--problem 4 --scenes 3 --sources 3 --directional 1 --start-seed 92000 \
--output output/hrl/p1-multiround-q4 --force
```
| variant | episodes | valid_rate | cleared_mean | virtual_time_mean_s | virtual_time_std_s | program_run_time_mean_s |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| directional | 3 | 1.0 | 3.0 | 13442.997 | 263.902 | 1.063 |
| hrl_heuristic | 3 | 1.0 | 3.0 | 12292.198 | 344.827 | 6.284 |
说明:Q4 高层 PPO 尚未训练;本轮只验证 Q4 的 `hrl_heuristic` 与 `directional` 闭环、真值隔离与计时审计。
## 5. P0 状态
- `--resume` 重载:16 步起步模型续训 32 增量步后 `actual_timesteps=48`,
校验 `feature_version/action_layout_version/reward_version` 后保存;
- 槽位唯一性:`test_hrl.py` 覆盖 channel 17–20 与 1–4 同时 clear/locate 不丢;
- 清除事件一次且仅一次:fallback 成功写 `_step_clears` 已有回归;
- 候选快照:`test_opportunity_measure_precedes_candidate_snapshot` 已覆盖;
- 奖励对齐:新增 `HRLReward.time_only()`,训练脚本默认 `--reward-profile time`;
- 终止/安全网:现有 `HierarchicalEnv` 回合测试继续通过;
- 训练/部署配置:`--config-profile production` 使用生产配置,`coarse-pretrain`
显式映射到 fast 评分配置并写入模型元数据;
- 依赖守卫:全量测试 275 项在 dev+rl 环境通过。
## 6. 未完成 / P2 待办
- `scripts/pretrain_hrl_expert.py` 已建可 `--help` 的接口占位,专家轨迹 + BC 功能待实现;
- `scripts/ablate_hrl.py` 已建接口占位,无信息增益/无掩码/无课程/无粒子统计消融待实现;
- `scripts/tune_hrl.py` 已建接口占位,Optuna TPE 搜索待实现;
- Q3→Q4 迁移训练与配对实验;
- 完整 10–16 源课程训练、多个训练种子、冻结测试清单;
- 官方三次正式测试表:必须有真实官方案例码与导出日志后才能填写;
本地 `referee` 结果只标 `local_self_test`。
+267
View File
@@ -0,0 +1,267 @@
# HRL 续作执行说明:交给 Sol 的工程任务书
适用日期:2026-09-11。工作目录:本仓库根目录。先检查当前代码与本轮测试结果,再按 P0 → P1 → P2 → P3 顺序执行。
目标是交付可运行、可审计的整场调度学习系统;训练收益由完整场景验证决定,不把训练脚本存在或局部奖励上升视为完成。
本说明更新了原粘贴 Prompt 与 `.zcode/plans/plan-sess_cf390556-4ef3-4ce6-b91e-782aee1718f9.md` 中不符合现有协议或证据的部分。
## 1. 现在有什么,缺什么
| 组件 | 当前状态 | Sol 的操作 |
| --- | --- | --- |
| `protocol/`、`referee/`、`harness.py` | 已有客户端、独立评测机、内存回环与计时审计 | 复用,不另建模拟器客户端 |
| `belief/`、`particles.py`、`planner/` | 已有保守候选、网格幸存集、覆盖证明、证书清除与后备清除 | 保持证明前提;改调度时复用 |
| `rl/`、`train_rl.py`、现有 RL 检查点 | 已有单源选点 PPO/MaskablePPO 与完整对照 | 作为局部策略和对照,勿命名为端到端 PPO |
| `hrl/constants.py`、`scheduler.py`、`planner/hrl_loop.py` | 已有高层候选、特征、执行与闭环骨架;存在本轮需修复的 P0 项 | 先完成第 4 节门槛 |
| `hrl/hierarchical_env.py`、`curriculum.py` | 已有训练环境和课程;奖励、终止、训练配置仍需审核 | 在长训前修正,覆盖独立环境/部署一致性 |
| `hrl/low_level_env.py`、`executor.py`、`train_hrl_low.py` | 有八方向到达实验;训练入口尚有掩码等缺陷 | 作为可选离线实验,不能卡住主线 |
| `tests/test_hrl.py` | 有接口和启发式 episode 测试 | 增补行为验证,不能只检验公式与实现一致 |
| `train_hrl_high.py`、`pretrain_hrl_expert.py` | 尚未实现 | P1 编写最小可训练闭环,P2 再加入 BC |
| `benchmark_hrl.py`、`ablate_hrl.py`、`tune_hrl.py` | 尚未实现 | 先评测,再训练,再做消融,最后受限调参 |
| CLI 的 `hrl` 策略和 `--hrl-model` | 当前入口尚未接入 | P1 接入并检验 `--help` 与离线闭环 |
| `output/hrl/` 的高层模型、曲线、评测表 | 本次审阅未发现这些产物 | 不声称已有 HRL 模型或训练成绩 |
现有证据:修订单步 RL 的 Q3 独立验证均值比 `bayes` 低 0.69%,区间跨 0;Q4 比 `directional` 低 14.38%,比旧 PPO 低 2.26%,后一比较区间跨 0。
这些来自固定模型、本地 18 场/题的验证;新 Q4 的后备清除次数更多,边界压力性能有退化。详情见 `docs/强化学习适用性审核与改进-20260911.md`。
没有证据证明 HRL 已优于上述基线,没有证据支持“Q4 迁移节约 80% 训练成本”或“全部合法场景小于 4000 秒”。
## 2. 必须纠正的原 Prompt 假设
1. `/measure` 与 `/clear` 提交终点,移动按两次实际动作位置间的直线距离除以 5 计费;没有朝向、转弯或八方向移动协议。
2. 八方向策略仅在本地推演再强制补上终点,无法影响模拟器实际路径;不能把这段推演称为比赛收益来源。
3. `/clear` 不切换接收机频道,目标频道与当前接收机频道应分别记录;`near` 是测量结果,清除仍需独立请求。
4. 接收半径逐源未知,动作掩码只能使用观测与保守界,不能读真实半径、源位置、类型或朝向。
5. Q3 的 `no_signal` 只能按已证明的保守半径规则删格;Q4 的 `no_signal` 可能由方向遮挡造成,不能直接删空间候选。
6. Q4 联合位置/半径/朝向粒子是后续研究选项;普通二维粒子加“角度门控”并不会自动得到正确联合后验。
7. 固定地点误差固定;同地重测不是新独立样本。保留读数舍入裕量,不收紧真实的 ±1° 误差界来追求表面收敛。
8. 源数最多 16 不等于只有 16 个频道;所有按频道编号索引的动作必须覆盖 1–20。
9. 连续无信号次数不能作为全场结束条件;覆盖参数不能随意调到破坏已证明的发现覆盖。
10. “无信息增益”“无动作掩码”“无粒子滤波”必须精确定义;不能通过取消清除证书或真源保留约束制造消融。
11. 原 Prompt 的 6 个状态与实现里的状态枚举不一致;以 `ChannelStatus` 为准,额外 TRACKING/LOCATED 只能定义为派生特征。
12. 协议文档 §6 仍写持续搜索默认开启;当前 `config.py` 为 `persistent_search=False`,CLI 用 `--persistent` 显式开启。先同步文档,不恢复过时默认值。
## 3. 推荐架构与工程边界
采用“高层学习调度 + 低层局部选点 + 协议执行”的分层架构。高层学习先处理哪个频道、继续覆盖还是定位、何时使用后备清除。
低层默认调用成熟几何选点;可切换现有 `PointSelectionPolicy` 学习局部检测点,形成第二个学习层。直线移动与设备动作继续由协议客户端执行。
Q3 首版低层用 `bayes` 几何选点;Q4 先保留 `directional` 的遮挡处理,待接线一致性通过后对比旧/新局部 PPO。
```text
SimulatorClient.state + belief + particles + coverage ledger
↓ 同一份候选快照和动作掩码
高层 MaskablePPO:选择频道/覆盖站/清除任务
↓
局部选点:geometry | 已有 v2 PointSelectionPolicy
↓
证书/预算/覆盖约束 + 实际 measure/clear 宏动作
↓
accepted 请求与响应 → 时间、信念、清除与覆盖账本
```
八方向 PPO 保留为 `low_level_env.py` 的离线附录实验;生产默认无需加载。若论文要求字面双 PPO,用高层调度 PPO + 局部选点 PPO 对应真正可影响成绩的两个层次。
现有高层一个动作可以包含整站逐频道扫描或多次后备清除,因此是变长宏动作。记录每个宏动作的实际持续时间、请求数和中断原因。
先采用 `gamma=1` 与实际时间成本,避免把“每宏动作折扣一次”误当成“每秒折扣一次”;只有明确改变目标才引入按持续时间折扣。
第一版保留 120 槽位 MLP,不同时重写注意力网络或连续动作;需要多候选/频道时另升动作版本并独立比较。
建议新增的共享接口如下;这些是待实现契约,避免训练和 CLI 分别拼接策略。
```python
@dataclass(frozen=True)
class HRLPolicyConfig:
local_selector: str = "geometry" # geometry | rl
local_model_path: str | None = None
def make_hrl_loop(client, config, *, problem: int,
high_policy=None, policy_config=HRLPolicyConfig()) -> HRLLoop: ...
def validate_episode(summary: dict, events: list[dict],
truth_channels: set[int]) -> dict: ... # 仅评测模块
def run_episode(scene: dict, variant: dict, *, output_dir: Path) -> dict: ...
```
## 4. P0:修复正确性,未过门槛不得长训
以下表中的状态以本轮提交和测试报告为准;Sol 接手时先查看 diff,已完成的项只做回归,不重复实现。
| 项目 | 精确入口与问题 | 目标与验收 |
| --- | --- | --- |
| P0.1 槽位冲突 | `constants.py`;`scheduler.build_candidates/heuristic_action`:clear 频道 17–20 与 locate 频道 1–4 重叠 | 本轮优先修复;每类按 20 频道分配,构造同时就绪冲突场景验证任务均保留 |
| P0.2 清除事件遗漏 | `scheduler._hrl_execute_fallback` 成功未写 `_step_clears` | 本轮优先修复;证书/后备/宏动作内部清除均由相同成功事件口径计数,一次且仅一次 |
| P0.3 候选过期 | `HRLLoop._coverage_phase` 在构建候选后 `_measure_at_stop` 可改变信念 | 本轮优先修复;选动作前候选/特征/掩码属于同一个状态快照 |
| P0.4 奖励对齐 | `HierarchicalEnv.step/_reward_from/HRLReward` | 改默认奖励,成功/异常/安全网/截断均计入已经发生的真实时间 |
| P0.5 回合终止 | `HierarchicalEnv.step/reset/close` | 实际完成、失败终止与采样截断分开;收尾不丢 /exit,不把零观测用于有效截断 bootstrap |
| P0.6 训练部署配置 | `curriculum.training_config` 默认网格 29.3m,部署 14.65m | 首个可比较模型使用生产几何配置;粗网格只能显式快速预训练,后接完整保真微调与评测 |
| P0.7 无进展循环 | `scheduler` 的 locate/probe/fallback 掩码及预算检查 | 去重、已清除/无效证书、后备预算不足在动作前处理;合法动作不能无限零成本自循环 |
| P0.8 测试与依赖 | `tests/test_hrl.py` 导入守卫、`policy.py/scheduler.py` 顶层 numpy | 不安装 RL 组时基础 CLI 可导入;完整 RL 环境运行测试时不得意外全部 skip |
建议槽位布局为 clear 0–19、locate 20–39、station 40–88、fallback 89–108、保留 109–119;所有槽位互斥且小于 120。
槽位含义改变必须升 `FEATURE_VERSION`,即使仍是 1248 维/120 动作,也必须拒绝旧语义检查点。
模型元数据应要求 `level/problem/algorithm/feature_version/action_layout_version/reward_version`,并记录模型 SHA、配置、依赖版本、代码版本。
缺字段不能默认为兼容;Q3 权重初始化 Q4 必须走显式训练迁移参数,部署加载仍严格检查题号。
默认奖励先用:`r = -实际本步虚拟时间增量 / 100`;证明完成时加固定完成奖,未完成的真实终止加失败罚。
失败惩罚按冻结的 episode 最大成本界设置并记录,不随意用不足以覆盖数千秒的 `-100`。
相同全清场景里逐源常数奖可能只是常数偏移,但不同终止路径、事件漏记和失败场景会改变激励;故首版去掉新发现/熵减/每源清除附加奖。
如需塑形,另做势函数差 `gamma * Phi(next_state) - Phi(state)`,真正终止态统一势函数值,并检验总和望远镜消去。
如果优化题目平均时间,用整场时间作为训练目标时明确这是所选代理;不同源数的跨场景均值与 `T/N` 均值不等价,不能暗称完全一致。
人工步数上限若仅为采样截断,返回可用的终末观测并允许 bootstrap;若定义为任务失败期限,应作为真实终止计罚。按该语义设计测试。
P0 验收至少覆盖以下行为,不只验证 reward 按代码相加:
- 20 个频道的各类槽位唯一;频道 17–20 与 1–4 同时有 clear/locate 不丢任务。
- 同一观测轨迹分别构建独立训练环境与部署闭环,比较候选、mask、特征、下一实际请求及状态。
- 固定动作序列跨成功、失败、后备与安全网路径:reward 的时间分项总和等于 accepted 日志复算时间。
- Q4 保证盘内/盘外无信号不误删真源;正读数重置遮挡序列;无效证书不能执行清除。
- 10/16 源、频道含 20、边界源与预算中断均检查真实源集合、缺席集合、正常退出、异常与计时。
- 评测端真值仅进 `validate_episode`,策略构建、候选、mask、观测与模型选择均不得读取真值。
## 5. P1:最小完整闭环,先评测再短训
先实现 `scripts/benchmark_hrl.py` 与共享审计函数,使 `HRLLoop(high_policy=None)` 可以与原 `bayes/directional` 同场景对比。
这个启发式 HRL 骨架是重要对照:若差距来自任务候选、机会测量、Q4 保底或预算语义变化,先修或如实量化,不归因给神经网络。
每次运行将 scene、误差种子、配置、summary、完整 JSONL/accepted 事件、时间复算和模型 SHA 写入新目录;目录已存在则拒绝覆盖。
单场异常也写结果;聚合存在任一无效局时 `all_valid=false` 且脚本非零退出,不从平均值表中静默删除失败场景。
随后实现 `scripts/train_hrl_high.py`,第一版提供以下参数并通过 `--help` 验证:
```text
--problem {3,4} --stage {1,2,3,4} --timesteps INT --seed INT
--envs INT --vec-env {dummy,subproc} --device {cpu,cuda,mps,auto}
--config-profile {production,coarse-pretrain}
--model PATH --resume PATH --eval-manifest PATH --verbose INT
--local-selector {geometry,rl} --local-model PATH
```
阶段 1 即保持 20 频道与固定观测维度,只改变布景复杂度;早期课程可减少源数,但完整训练必须覆盖 10/13/16 源与实际 ±1° 固定地点误差。
Q4 完整课程同时覆盖少量/半数/大量定向源及近边界向外朝向;Q3→Q4 迁移与 Q4 随机初始化作为配对实验。
禁止让策略知道课程场景真实源数或隐藏的占用频道列表;初始位置保持官方 `(0,0)`,除非任务被明确标为局部交接课程。
先测 1/2/4 个环境的采样吞吐、内存和每次决策耗时,再选择 Dummy/Subproc;小 MLP 不假定 GPU 更快。
Subproc 环境类内部提供 `action_masks()`;Windows/macOS 使用入口守卫及可序列化工厂。
随机种子覆盖 Python/NumPy/Torch、PPO、每个环境、场景误差;每个 worker 使用独立 Monitor 文件。
保存实际 `model.num_timesteps` 与请求步数,恢复时说明增量还是累计;续训加载正确算法/特征版本且不覆盖原模型。
使用掩码评估接口,如 `MaskableEvalCallback`;同时在确定性推理中传入同源 mask。
CLI 加入 `--strategy hrl`、`--q4-strategy hrl`、`--hrl-model` 与局部策略选项,经 `make_hrl_loop` 统一构建;默认策略保持现状。
显式指定缺失模型应报可操作错误,不能把启发式降级结果记成 HRL 模型成绩;启发式骨架单独命名 `hrl_heuristic`。
P1 门槛:启发式骨架全场审计通过;512–2048 步训练冒烟可保存、重载、确定性推理;CLI 内存回环至少 Q3/Q4 各一场通过。
短训先用单个种子验证流程,不用这次模型的成功率作论文结论;完成后记录吞吐再定时间预算,不预设 1–2 小时足够。
## 6. P2:完整保真训练、独立评测与消融
实现 `pretrain_hrl_expert.py`:运行 `hrl_heuristic`,保存 `(episode_id, state, candidates, mask, action)`;按 episode 划分训练/验证。
BC 与 PPO 的网络层、激活、归一化、mask 处理保持一致;复制后在真实样本上逐位比较 logits,critic 单独初始化。
记录专家动作无法映射到候选的比率与原因;若大量回退到最近候选,先改专家映射,不用假专家标签继续训练。
至少比较 BC+PPO 与随机初始化 PPO;BC 准确率单独报告,不能代替独立闭环用时与有效全清率。
冻结数据集分工:
| 集合 | 用途与约束 |
| --- | --- |
| 已有 700–702 开发场景 | 查实现错误、探索配置与性能分解 |
| 已有 91000–91005 场景 | 历史回归;结果已经被审阅,不再宣称是本次全新盲测 |
| 新开发/选择清单 | 固定 JSON manifest,记录 seed、源数、定向组成、error_seed;用于训练选择和调参 |
| 新冻结最终测试清单 | 与训练、BC、调参及选择清单不重叠;模型冻结后运行,失败后修改则新开一轮测试 |
| 压力场景 | 圆周边界、1000m 半径、向外/切向定向、高频道、固定误差与预算边界;单独汇总 |
同场景每个变体用相同位置、频道、半径、朝向和地点误差函数。每个模型至少跑 30 个完整场景,再按预算扩大;“30”是工程起点,不是统计充分性证明。
最终用于稳定收益结论的主方法至少 5 个独立训练种子;场景种子与训练种子分开报告,不能用 5 个场景替代 5 次训练。
Q3、Q4 分开统计,并按源数/定向占比分层;所有基线与候选使用相同停止、预算和计时口径。
| 指标 | 固定定义 |
| --- | --- |
| 有效全清 | 成功清除频道集合等于评测真值;缺席集合与真值不交;completed、正常 exit、无异常、计时一致 |
| `virtual_time_s` | 实际退出前的完整虚拟时间;主竞赛口径显式 `persistent_search=False` |
| `avg_locate_clear_time_s` | 每场 `T / 实际清除数`;有效全清主表再做逐场平均,另报源数分组 |
| `accounted_virtual_time_s` | 首次完成证明的时间;与最终时间并列,不悄悄用它替换正式计分 |
| 运行时间 | 每场实际墙钟、模型推理耗时分位数;本地内存回环时间不冒充官方程序运行时间 |
| 成本分解 | 移动秒、测量秒、换频秒、成功/失败 clear 秒、后备尝试、重复测量、总请求数 |
| 尾部与失败 | 中位数/P90/P95/最大值、有效全清率、失败明细;小样本尾分位注明估计局限 |
平均 `T/N` 不等于 `平均 T / 平均 N`;若另用总体总时间/总源数,明确标为按源数加权口径。
配对效应以同场景时间差为基础,报告均值相对变化、胜出场数、95% 配对 bootstrap 区间;相同场景家族共享种子时按家族重采样。
多训练种子结果报告种子间分散程度;必要时对训练种子和场景做分层重采样,不能用单一场景区间代表训练稳定性。
最小比较矩阵:`bayes/directional`、旧局部 PPO、修订局部 MaskablePPO、`hrl_heuristic`、高层 PPO+几何、后续高层 PPO+局部 PPO。
此矩阵先回答“改调度是否有用”和“增加局部学习是否有用”;既有单步 RL 不能命名为无几何的端到端基线。
若仍要端到端 PPO,必须单独定义输入、实际动作、安全执行边界并训练,标记预算;它不是 P1 完成条件。
每项消融使用相同训练步数/场景预算/种子和评测集,单次只改变一个因素:
- 调度:学习高层 vs `hrl_heuristic`,保持候选生成和局部选点一致。
- 局部策略:同一高层与执行接口下,geometry vs 现有局部 PPO;报告是冻结替换还是联合重训。
- 塑形:纯时间目标 vs 经过恒等式核验的势函数塑形;无信息增益奖励就是系数为 0。
- 课程:相同总交互步数的课程训练 vs 从完整场景开始训练;Q4 迁移另列,不预设节约百分比。
- 掩码:只取消重复/低效候选等策略性屏蔽;协议合法性、证书和预算硬守卫始终保留,标明实际取消范围。
- 粒子特征:保留几何守恒内核,先将粒子统计输入和评分消融;若真的移除粒子模块,另实现保守几何替代并重新验证。
- 八方向:只报告离线到达率/路径效率/推演耗时,以及实际协议终点相同时成绩相同的事实。
P2 推广门槛:所有最终与压力场景有效,Q4 相对最强已冻结基线的时间差区间上界小于 0;尾部容忍度先写入 manifest。
建议初始尾部门槛为 P95 不退化超过 5%,这是可调整的工程标准,不是题设要求;任何调整都在重跑最终测试前完成。
Q3 若未显示稳定收益,保留 `bayes` 默认并交付负结果。仅比手写基线快、却未优于现有 PPO,不能宣布替换默认模型。
## 7. P3:受限调参、论文与官方验证
只有 P2 主方法具备竞争力才实现并运行 `tune_hrl.py`。先搜索学习率、熵系数、网络宽度、GAE、合法候选排序参数。
不搜索真实误差上限、光学清除半径、无信号停止次数或破坏覆盖证明的网格间距;确定性网格没有粒子重采样阈值可调。
Optuna 只用开发/选择清单,失败配置先按有效性淘汰;预算与失败/剪枝逻辑写入结果。最终模型重新用固定配置多种子训练。
文档、流程图与论文表明确:学习负责哪些决策、证明由哪些模块提供、本地生成分布未知是否对应官方分布。
训练曲线、实际步数、配置、全部对照与失败明细均归档;不要只挑最好种子或去掉不利的边界场景。
官方三次测试需要对应演练已经启动、真实案例码与官方导出日志;本地 referee 的三场不能填写成“三次正式测试”。
不覆盖旧官方归档;官方结果与本地结果分表,不对不同官方案例直接计算改进百分比。
## 8. 命令:已经存在与待实现的严格区分
以下入口当前已经存在;依赖需先安装,命令失败要修复或如实报告,不能跳过错误声称通过:
```bash
uv sync --group dev --group rl
uv run python -m pytest -q --tb=short
uv run python -m pytest -q tests/test_hrl.py --tb=short
uv run mcm26b run --help
uv run mcm26b run --robot-id 2026001 --self-test --strategy bayes
uv run mcm26b run --robot-id 2026001 --self-test --problem 4 --q4-strategy directional
uv run python scripts/train_rl.py --help
uv run python scripts/train_hrl_low.py --help
```
`train_hrl_low.py` 目前仅 `--help` 可用于检查入口,不把完整训练列为已可用:
其 `MaskablePPO.learn()` 需要环境掩码,当前 `LowLevelEnv` 没有 `action_masks()`;改普通 PPO 或提供全 True 掩码后再试。
还需修 BC 按 episode 划分、统一随机种子、每 worker 独立 Monitor 文件、评估 seed 生效、实际路径长度与成功率分开统计。
低层到达失败不能靠 executor 最后强制补终点伪装成策略到达;环境裁剪后的实际移动长度也不能简单记为 `steps*100m`。
下面是 P1/P2 实现后必须支持并实测的命令契约,当前尚不能直接运行:
```bash
# P1:先验证不加载模型的共享调度闭环
uv run python scripts/benchmark_hrl.py --variants hrl_heuristic,bayes,directional --manifest output/hrl/manifests/dev.json --output output/hrl/p1-heuristic
# P1:完整保真冒烟;模型目录必须是新目录
uv run python scripts/train_hrl_high.py --problem 3 --stage 1 --timesteps 2048 --seed 320001 --envs 1 --vec-env dummy --device cpu --config-profile production --model output/hrl/p1-smoke/q3.zip --verbose 0
# P1:CLI 明确加载高层模型
uv run mcm26b run --robot-id 2026001 --self-test --strategy hrl --hrl-model output/hrl/p1-smoke/q3.zip
# P2:正式阶段训练;步数先依据采样吞吐与学习曲线再调整
uv run python scripts/train_hrl_high.py --problem 4 --stage 4 --timesteps 60000 --seed 420001 --envs 2 --vec-env dummy --device cpu --config-profile production --model output/hrl/p2/q4-seed420001.zip --eval-manifest output/hrl/manifests/select.json --verbose 0
# P2:冻结模型完整对照;variants 的模型位置来自同目录的配置清单
uv run python scripts/benchmark_hrl.py --variants hrl,hrl_heuristic,legacy,revised,baseline --manifest output/hrl/manifests/final.json --output output/hrl/p2-final
```
命令使用的 manifests 也要由脚本生成、校验并归档;尚不存在的模型不能当作初始化输入。
添加 `--full` 一键课程入口时,它应展开并记录每阶段命令/配置/检查点链,失败即停,可继续,不是忽略错误的 shell 包装。
参考现有依赖配置:基础运行依赖仅 requests;RL 为可选组。固定环境版本并记录硬件,勿假定当前执行机就是旧报告中的 RTX 4060。
## 9. 可以直接粘贴给 Sol 的续作 Prompt
```text
继续当前仓库的 HRL 工作。先读 docs/hrl-sol-execution.md、最新测试结果与 git diff,保留现有修改。
已有客户端/referee/几何/PPO 都要复用;不要重写骨架,不把缺失脚本或 CLI 说成已完成。
先完成 P0 尚未关闭的奖励、终止、完整保真配置、掩码和依赖问题;本轮已修的槽位/清除事件/候选过期只回归。
采用高层 MaskablePPO 调度 + 几何/已有局部 PPO 选点 + 协议直线执行;八方向只作为可选离线实验。
按 P1 先实现 benchmark_hrl 与真值隔离审计,再实现 train_hrl_high、模型元数据和 CLI,跑可重载的短训冒烟。
P0/P1 没通过就修实现,不用加训练步数掩盖问题。通过后再开展 BC、完整保真课程、多训练种子、冻结场景配对评测。
保持 Q3 bayes/Q4 现有默认策略;完整实验胜出前不覆盖默认模型。主指标包含有效全清、T、逐场 T/N、请求分解和尾部。
每阶段交付具体文件、实际执行命令、测试结果、模型/日志路径与未完成项;不预设 Q4 80% 节约或 4000 秒保证。
官方测试只有真实演练开始并获得案例码/导出日志才记正式结果,本地实验单独标注。
```
接口参考:[MaskablePPO 官方文档](https://sb3-contrib.readthedocs.io/en/master/modules/ppo_mask.html),[Gymnasium 终止与时间限制](https://gymnasium.farama.org/tutorials/gymnasium_basics/handling_time_limits/)。
+65
View File
@@ -0,0 +1,65 @@
# 论文(docs/paper)
2026 年高教社杯全国大学生数学建模竞赛 B 题论文 LaTeX 工程,格式依据
`issue/论文格式/附件3. 全国大学生数学建模竞赛论文格式规范.pdf`(2026 年修订稿)。
## 编译
需要 TeX Live(含 XeLaTeX 与 ctex)。在本目录执行:
```bash
latexmk -xelatex -outdir=build main.tex
# 或
xelatex main.tex && xelatex main.tex
```
输出 PDF:`build/main.pdf`(用第二种方式则为 `main.pdf`)。
## 目录结构
| 路径 | 内容 |
| --- | --- |
| `main.tex` | 论文源文件(摘要、正文、附录及源码引用) |
| `mcm26b-paper.cls` | 论文版式模板(宏包、字体、标题、代码排版与通用命令) |
| `fonts/` | 从本机提取的中文字体(宋体 SC 常规/加粗、黑体 SC Light/Medium)与 Times New Roman 四体,约 150 MB,编译自包含 |
| `figures/` | 插图目录 |
| `build/` | 编译产物(已 gitignore) |
VS Code 工作区已在 `.vscode/settings.json` 中将 LaTeX Workshop 的默认配方设为
`xelatex`;也提供 `latexmk (xelatex)` 配方用于自动处理交叉引用。
## 规范要点与工程实现
- A4、四边距 2.5cm:`geometry` 宏包。
- 页码从摘要专用页起、页脚中部、从 1 连续编号:摘要页 `\setcounter{page}{1}`。
- 正文不要目录、不超过 30 页:未生成目录,正文当前远少于 30 页。
- **电子版第一页必须是摘要专用页**(不含承诺书与编号专用页):默认
不启用 `paper` class option。打印纸质版时将 `main.tex` 的
`\documentclass[zihao=-4,a4paper]{mcm26b-paper}` 改为
`\documentclass[zihao=-4,a4paper,paper]{mcm26b-paper}`,自动加入承诺书与编号专用页
(占位文字,须替换为组委会当年发布的专用页原文)。
- 摘要页含标题与关键词,不超过一页,无需英文。
- 摘要页、正文、附录中不得出现姓名、学校、赛区等信息。
- 附录含支撑材料文件列表与完整源码:源码以 `\lstinputlisting` 引用仓库内
`src/mcm26b/geometry/` 等模块(相对路径 `../../`),提交前须确认与支撑材料
压缩包一致。
## 待办(正文中红色【待填/待补】标记)
- 问题 3、4 演练统计值与正式测试结果(表 1 两张表)。
- 问题 1 定位区域图、问题 2 候选区域示意图与选点对比实验。
- 支撑材料文件列表更新;定稿前删除全部红色批注(`\todonote`)。
## 字体说明
`fonts/` 下中文 字体自 macOS 系统字体(Songti.ttc、STHeiti)提取简体字面而来,
授权仅限本队参赛使用。若在 Windows/Overleaf 编译,可改用系统自带中易宋体/黑体,
将导言区字体设置替换为:
```latex
\setCJKmainfont{SimSun}
\setCJKsansfont{SimHei}
\setmainfont{Times New Roman}
```
若仓库体积敏感,可将 `fonts/` 加入 `.gitignore`(此时每位队员需自备字体)。
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+920
View File
@@ -0,0 +1,920 @@
% 2026 年高教社杯全国大学生数学建模竞赛论文(B 题)
% 编译:在 VS Code 中默认使用 xelatex;命令行可运行:
% latexmk -xelatex main.tex
%
% 版式、宏包、字体和通用命令统一放在 mcm26b-paper.cls 中。
% 电子版默认从摘要页开始;打印纸质版时将 documentclass 的选项
% 改为 [zihao=-4,a4paper,paper],即可加入承诺书与编号专用页。
\documentclass[zihao=-4,a4paper]{mcm26b-paper}
\begin{document}
% ============================================================
% 纸质版专用页(电子版不编译)
% 注意:承诺书与编号专用页的正式文字以组委会当年发布的专用页为准,
% 此处为占位排版。电子版必须不含本部分。
% ============================================================
\ifpaper
\thispagestyle{empty}
\begin{center}
{\heiti\zihao{2} 承\ 诺\ 书}
\end{center}
\vspace{1em}
\todonote{纸质版承诺书:请将组委会当年发布的专用页原文粘贴于此(含编号、
队员信息表与全体队员签名、日期)。电子版论文不得包含本页。}
\vspace{2em}
\begin{center}
{\heiti\zihao{2} 编号专用页}
\end{center}
\vspace{2em}
\begin{center}
{\zihao{4} 报名号:\rule[-2pt]{8cm}{0.4pt}}
\end{center}
\todonote{纸质版编号专用页:仅填写报名号,不得出现姓名、学校、赛区等信息。}
\clearpage
\fi
% ============================================================
% 摘要专用页(电子版第一页;页码从此页开始编号)
% ============================================================
\setcounter{page}{1}
\begin{center}
{\heiti\zihao{3} 无线电干扰源的\\[0.3em]
快速自动定位与清除}
\end{center}
\vspace{0.8em}
\begin{center}
{\heiti\zihao{4} 摘\quad 要}
\end{center}
无线电干扰源的测向与规划问题在生产和军事上的应用十分广泛。
\texttt{no\_signal}、\texttt{near}、\texttt{direction} 为唯一信息来源,建立
\textbf{有界误差交会定位—主动选点—覆盖证明搜索—动作耗时调度}的统一框架:四个问题
复用同一几何内核,以覆盖证明与严格停止条件保证“清除所有干扰源”的硬约束,再优化
时间指标。
\textbf{针对问题~1},将 $\pm 1^{\circ}$ 有界误差下的测向观测建模为以检测点为顶点的
前向角域 $W_i$,交会定位区域即诸角域的半平面交 $P=\bigcap_i W_i$,给出直径
$D(P)=\max_{i,j}\|v_i-v_j\|$ 的顶点对枚举算法,并处理空集、无界区域等退化情形。
对“直径圆能否覆盖定位区域”,给出只需检查最远顶点对中点的充要判定,并以符合题设
测向条件的等边三角形反例给出否定回答;以最小包围圆半径 $\rho(K)\le 20$ 米为可保证
清除的充分判据,用 Welzl 算法求解并以支撑点枚举对照。官方演练三点观测复算:
$\delta=1^{\circ}$ 时 $D=23.9967$ 米、$\rho=12.0686$ 米,直径圆不覆盖定位区域,
但存在一点可保证清除。
\textbf{针对问题~2},首次测向后取保守候选集合
$K_1=\Omega\cap W(s_1,\theta_1\pm\delta)\cap B(s_1,1500)$,将接收保证写成一族闭
圆盘之交并给出非空判据;进而证明截断角域的最小包围圆恰为 $B(c,a)$
($a=R/(2\cos\delta)$、$c=s_1+a\bm{u}$),故安全候选圆盘
$B(c,1000-a)\subseteq\mathcal{Q}$ 严格非空($\delta=1^{\circ}$ 时半径约 $249.89$
米)。在安全区域内以“最坏保守后验包围半径”为主目标、移动与检测成本为次目标
主动选点,交会角仅作局部解释与同分筛选指标。
\textbf{针对问题~3},建立以虚拟时间
$T=L/5+N_{\mathrm{switch}}+5N_{\mathrm{measure}}+5N_{\mathrm{clear}}^{\mathrm{s}}
+3N_{\mathrm{clear}}^{\mathrm{f}}$
为目标的全向源搜索清除模型。构造间距 $700$ 米的 $7\times 7=49$ 点覆盖基线,由
$700\sqrt{2}\approx 989.95<1000$ 米证明任何位置的源均能被某格点发现,从而保证
不漏源;维护逐频道覆盖记录与“发现—定位—清除”闭环,给出严格停止条件与请求数
预算控制。\todonote{演练统计值待填入}
\textbf{针对问题~4},将定向源建模为位置—半径—朝向的联合假设:\texttt{no\_signal}
不单独删除空间候选点,避免误删真源;证明 $49$ 点覆盖基线对定向源仍然有效。对再次
失去信号的源,给出候选集合的 $20$ 米网格有限圆盘覆盖后备清除方法及请求次数上界
$N\le(\lceil w/20\rceil+2)(\lceil h/20\rceil+2)$,并纳入现实时间预算约束。
\todonote{演练统计值与正式测试结果(表~1)待填入}
最后对模型的保守性与效率进行评价:几何内核可复用、覆盖保证可验证;局限在于
主动选点为采样启发式、后备清除请求数较大,可通过共享测点与自适应覆盖加速。
\vspace{0.4em}
\noindent{\heiti 关键词:}交会定位;半平面交;最小包围圆;覆盖证明;主动选点;动作调度
\clearpage
% ============================================================
% 正文(不超过 30 页,不要目录)
% ============================================================
\section{问题分析}
四个问题构成一条递进的主线:问题~1 的交会定位几何是全部后续问题的基础;问题~2 在
单次观测下研究“下一步去哪里测”的主动测量设计;问题~3、问题~4 则是在数量未知的
条件下,把定位几何组织成“全域覆盖发现—逐个定位—清除—证明完成”的闭环调度问题。
因此不必为每问单独建模,而是复用同一几何内核与观测更新机制。
\textbf{问题~1 的分析}。题面附录~2 第(1)项把测向误差限定在
$[-1^{\circ},1^{\circ}]$,且同一地点重复检测不改变误差:没有误差分布可利用、
原地重复测量不产生新信息,故采用有界误差的集合相交建模——单次测向只能确定源
位于以示向度方向为轴、半角 $1^{\circ}$ 的前向角域内,多检测点角域的交集即为
定位区域。题目要求“采用交会定位法”计算“多边形定位区域”的直径(附录~2 第(3)
项图~2),角域边界为直线,求交即半平面交这一经典计算几何问题;直径在凸多边形
顶点上取得,可用顶点对枚举精确求得。对“直径圆能否覆盖区域”的追问,需要区分
“直径”与“外接”两个概念:先给出只需检查最远顶点对中点的充要判定,再构造符合
题设测向条件的等边三角形反例说明一般不覆盖。最后,清除以 $20$ 米距离为判据
(附录~2 第(8)项),正确的保证清除工具是最小包围圆。
\textbf{问题~2 的分析}。题目要求同时给出第二检测点的“选择策略”与“候选区域”,
这是在目标位置未知条件下的主动测量设计,方法取舍由两条题设决定。其一,有效接收
半径在 $1000$ 至 $1500$ 米之间且具体值未知(附录~2 第(2)项):无论真实源位于
当前候选集合何处,新检测点都必须保证落在其接收半径内,否则该次检测退化为无效
动作,故先构造保守候选集合,再解析证明存在“任何情况下都收到信号”的安全区域。
其二,题面只给有界误差而无误差分布与源位置分布(附录~2 第(1)项),概率类方法
没有严格依据,故在安全区域内以最坏情形的后验包围半径为主目标、移动与检测成本
(附录~2 第(5)、(6)项)为次目标选取检测点,交会角仅作局部几何解释与同分筛选。
此外,$1800$ 米圆域限制的是源位置而非机器狗(附录~3),安全选点允许越出圆域;
返回 \texttt{near} 的分支按附录~2 第(9)项就地清除,不视为策略失败。
\textbf{问题~3 的分析}。全清是硬约束:发现 $10$ 个源或连续多次无信号都不构成停止
依据。需要一组对任何源位置都能保证“至少一个检测点落在其有效接收范围内”的覆盖点集,
并对每个频道维护覆盖记录,使“未发现”严格等价于“已证明不存在”。在该保证之上,
用虚拟时间公式统一度量移动、切换、检测与清除成本,安排发现与处理的调度。
\textbf{问题~4 的分析}。定向源的发射半平面使得“无信号”不能单独否定位置假设:
源可能恰在检测点背后发射。把观测视为对“位置—半径—朝向”联合假设的约束即可保持
不漏源的保守性;同时证明覆盖基线对定向源依然成立,失去信号后的已定位源可用有限
圆盘覆盖逐点清除作为后备。
\section{模型假设}
\begin{enumerate}[label=\arabic*.,leftmargin=2.5em]
\item 示向度误差满足 $|\varepsilon|\le 1^{\circ}$,且同一检测点重复检测误差不变;
仅在不同地点误差才呈现统计规律(题设)。本文取有界误差模型,不假设误差的
分布形式。
\item 每个频道至多存在一个干扰源,源总数为 $10$--$16$,频道编号 $1$--$20$;
不同源信号互不影响(题设)。
\item 各源有效接收半径未知但属于 $[1000,1500]$ 米;信号场强仅随距离衰减,
与角度无关(题设)。
\item 定向源有效覆盖角度为定向方向两侧各 $90^{\circ}$(含边界);光学精确定位与
清除只依赖距离、不受覆盖角度限制(题设)。
\item 策略仅依赖接口返回的三值观测(\texttt{no\_signal}、\texttt{near}、
\texttt{direction} 及示向度读数),不引入场强、距离等接口未提供的观测量
(工程约定)。
\item 机器狗沿直线匀速行进、停机检测,虚拟时间按题设动作耗时累计;程序运行时间
与虚拟时间相互独立(题设)。
\end{enumerate}
\section{符号说明}
\begin{table}[htbp]
\centering
\caption{主要符号说明}
\label{tab:symbols}
\begin{tabular}{cl}
\toprule
符号 & 说明 \\
\midrule
$\Omega$ & 目标区域 $\{(x,y):x^2+y^2\le 1800^2\}$(米) \\
$R_c$ & 干扰源 $c$ 的有效接收半径,$R_c\in[1000,1500]$ 米 \\
$\delta$ & 示向度误差界,$\delta=1^{\circ}$ \\
$s_i,\ \theta_i$ & 第 $i$ 个检测点坐标及其测得的示向度读数 \\
$W_i$ & 检测点 $s_i$ 处的前向角域 $[\theta_i-\delta,\theta_i+\delta]$ \\
$P$ & 交会定位区域(诸角域的半平面交) \\
$D(P)$ & 定位区域 $P$ 的直径 \\
$K$ & 某频道源的可能位置候选集合 \\
$\rho(K)$ & $K$ 的最小包围圆半径 \\
$\mathcal{Q}$ & 第二检测点的安全候选区域 \\
$B(c,r)$ & 以 $c$ 为圆心、$r$ 为半径的闭圆盘(米) \\
$R_-,\ R_+$ & 有效接收半径的下、上限,$1000$、$1500$ 米 \\
$J(q)$ & 第二检测点 $q$ 的最坏保守后验包围半径(米) \\
$C(q)$ & 在 $q$ 处完成一次检测的虚拟时间增量(秒) \\
$L$ & 机器狗移动总路程(米) \\
$N_{\mathrm{switch}},N_{\mathrm{measure}},N_{\mathrm{clear}}$ & 频道切换、检测、清除动作次数 \\
$T$ & 完成任务的虚拟总时间(秒) \\
\bottomrule
\end{tabular}
\end{table}
\section{问题~1:有界误差交会定位模型}
\subsection{建模思路来源}
本问每种方法的取舍都由题面描述直接确定,对应关系如下。
\textbf{由误差描述确定集合模型。}题面附录~2 第(1)项指出:示向度与真实方位角之间
的误差“在一段时间内,同一地点的电磁环境干扰是固定的,所以重复检测不会改变检测
误差”,且“从目标区域全局来看,所有这些误差在 $[-1^{\circ},1^{\circ}]$ 范围内”。
因此单次观测不能确定一条精确射线,却可以确定一个必含真实方向的角域;题面没有
给出误差的分布形式,原地重复测量又不产生新信息,故采用有界误差下的集合相交,
而非直线最小二乘或多次读数平均——后两者既不能保证真源不被排除,也与“同点误差
不变”的题设相悖。
\textbf{由交会定位的规定确定半平面交。}问题~1 要求“采用交会定位法(见附录~2)
计算多边形定位区域直径”,附录~2 第(3)项的图~2 把定位区域画成两个检测点示向度
实线两侧各 $1^{\circ}$ 虚线所夹的四边形。角域边界是直线,故定位区域是二维线性
不等式组的可行域,可用半平面交显式构造,问题随之成为凸几何问题\cite{boyd}。
\textbf{由直径的定义确定顶点枚举。}题目规定直径是“区域内任意两点之间距离的最大
值”。两点距离关于其变元是凸函数,在紧凸集上的最大值必在极点处取得,故只需在
顶点对上枚举,无需任何近似。
\textbf{由覆盖之问确定“先判定、后反例”。}题目追问“以定位区域直径为直径的圆能否
覆盖此定位区域”。“直径”是最长弦概念,与“外接”并非同一对象,因此先给出存在
覆盖圆的充要判定,再构造符合题设测向条件的反例,据此回答“不一定”。
\textbf{由清除条件确定最小包围圆。}附录~2 第(8)项规定光学精确定位与清除“在距离
干扰源不超过 $20$ 米”时进行,且成功与否仅与清除点到干扰源的距离有关。定位精度的
最终判据因而是“存在一点到所有可能源位置都不超过 $20$ 米”,即最小包围圆半径
$\rho\le 20$,而非直径不超过 $40$ 米。
\subsection{测向观测的前向角域与半平面约束}
设第 $i$ 个检测点 $s_i=(s_{ix},s_{iy})$ 处测得示向度 $\theta_i$(题面附录~2
第(1)项:示向度自 $x$ 轴正向逆时针计量,范围 $[0^{\circ},360^{\circ})$)。
由假设~1,真实方位角位于 $[\theta_i-\delta,\theta_i+\delta]$ 内,故源必然落在
以 $s_i$ 为顶点、以该方向区间为边界的前向角域
\begin{equation}
W_i=\bigl\{s_i+t\,u(\varphi):t\ge 0,\ \varphi\in[\theta_i-\delta,\theta_i+\delta]\bigr\},
\qquad u(\varphi)=(\cos\varphi,\sin\varphi)
\label{eq:wedge}
\end{equation}
内。记二维叉积 $[a,b]=a_xb_y-a_yb_x$ 与 $u_i^{\pm}=u(\theta_i\pm\delta)$。当
$0<\delta<90^{\circ}$ 时,“位于两条边界射线之间”等价于
\begin{equation}
[\,u_i^-,\,g-s_i\,]\ge 0,\qquad [\,u_i^+,\,g-s_i\,]\le 0,
\label{eq:cross}
\end{equation}
即 $g-s_i$ 位于下边界射线的左侧、上边界射线的右侧。展开即标准线性约束
\begin{align}
\sin(\theta_i-\delta)\,x-\cos(\theta_i-\delta)\,y
&\le \sin(\theta_i-\delta)\,s_{ix}-\cos(\theta_i-\delta)\,s_{iy},\\
-\sin(\theta_i+\delta)\,x+\cos(\theta_i+\delta)\,y
&\le -\sin(\theta_i+\delta)\,s_{ix}+\cos(\theta_i+\delta)\,s_{iy}.
\end{align}
另保留前向约束 $u(\theta_i)\cdot(g-s_i)\ge0$:它在 $0<\delta<90^{\circ}$ 时冗余,
但 $\delta=0$ 时前两条约束只限定一条直线,加入它才得到正确的射线。角域顶点本身
包含在闭集合内,这是保守处理,并不表示在该点仍能获得示向度。采用向量不等式后,
$359^{\circ}$ 与 $0^{\circ}$ 跨界无需分段比较角度。示向度读数保留两位小数时,可
取 $\delta=1.005^{\circ}$ 作显式声明的保守裕量;本节推导对任意
$\delta\in(0,90^{\circ})$ 成立,本题算例始终取 $\delta=1^{\circ}$。
\subsection{定位区域的构造与分类}
交会定位区域为诸角域之交
\begin{equation}
P=\bigcap_i W_i=\{g:Ag\le b\}.
\label{eq:polygon}
\end{equation}
每个 $W_i$ 都是闭凸集,故 $P$ 也是闭凸集;它可能为空、为单点、为线段、为有界凸
多边形,也可能无界,算法必须显式区分这五种情形,不得混同处理。
\textbf{边界交点枚举。}把约束统一写成 $a_jx+b_jy\le c_j$,两条边界的行列式
$\Delta_{jk}=a_jb_k-a_kb_j\ne0$ 时,交点为 $x=(c_jb_k-c_kb_j)/\Delta_{jk}$、
$y=(a_jc_k-a_kc_j)/\Delta_{jk}$。保留满足全部约束的交点,去重后构造凸包即得
$P$ 的顶点集。
\textbf{命题~1}(极点存在保证判空)\quad 至少有一次观测时,非空的角域交集一定存在
极点,因此可通过可行边界交点枚举判空。
\textbf{证明}\quad 取第一个角域的轴向 $u_1$,其中任意 $g$ 满足
$u_1\cdot(g-s_1)\ge\cos\delta_1\,\|g-s_1\|$,且 $\cos\delta_1>0$。在非空 $P$ 上
最小化线性函数 $u_1\cdot(g-s_1)$:由该不等式,以任一可行点的函数值截得的下水平
集有界,从而是非空紧集,最小值可达;最小化点集位于一条支撑直线上且有界,因而是
点或线段,取其点或端点即得 $P$ 的极点。二维线性约束的极点至少有两条法向量线性
无关的有效边界(否则沿所有有效边界的公共切向可作双向小扰动,与极点定义矛盾),
故必出现在上述交点枚举中。\hfill$\square$
无观测时 $P=\R^2$,应直接判为无界,不能用“没有交点”判为空集。
\textbf{有界性判定。}对非空 $P$ 定义衰退锥 $\mathcal{R}=\{d:Ad\le0\}$。若存在
$d\ne0$,则任取 $g_0\in P$ 都有 $g_0+td\in P$($t\ge0$),$P$ 无界;反之若 $P$
无界,取 $g_k\in P$ 使 $\|g_k-g_0\|\to\infty$,将 $Ag_k\le b$ 减去 $Ag_0\le b$、
除以 $\|g_k-g_0\|$ 并取极限,知单位向量 $(g_k-g_0)/\|g_k-g_0\|$ 的任一聚点 $d$
满足 $Ad\le0$。故 $P$ 有界当且仅当 $\mathcal{R}=\{0\}$。本模型的衰退锥被一个小于
$180^{\circ}$ 的闭角域约束,若含非零向量必含一条极射线,该射线平行于某条有效
约束边界,故只需检查每个法向量 $(a_j,b_j)$ 的两个切向方向 $(b_j,-a_j)$、
$(-b_j,a_j)$ 是否满足全部齐次不等式。
\textbf{分类约定。}可行交点为空时返回空集;存在非零衰退方向时返回无界;否则对
可行交点去重求凸包,按顶点数与仿射维数区分单点、线段和二维多边形。空集的直径
约定为无定义,无界区域的直径为 $+\infty$。显示窗口只用于绘图裁剪:任何大矩形都
不能取代衰退锥判定,更不能把截断图形的直径称为原无界区域的直径。
\subsection{定位区域直径的顶点定理}
\textbf{定理~1}(直径在顶点上取得)\quad 若 $P=\mathrm{conv}\{v_1,\dots,v_m\}$ 非空
且有界,则
\begin{equation}
D(P)=\max_{1\le i<j\le m}\|v_i-v_j\|.
\label{eq:diameter}
\end{equation}
\textbf{证明}\quad 任取 $x,y\in P$,写成凸组合 $x=\sum_i\lambda_iv_i$、
$y=\sum_j\mu_jv_j$(权重非负且各自求和为 $1$),则
$x-y=\sum_{i,j}\lambda_i\mu_j(v_i-v_j)$。由三角不等式,
$\|x-y\|\le\sum_{i,j}\lambda_i\mu_j\|v_i-v_j\|\le\max_{i,j}\|v_i-v_j\|$;最远顶点对
本身属于 $P$,上界可达。\hfill$\square$
$m$ 很小(为检测点数的常数倍),直接枚举顶点对即可,复杂度 $O(m^2)$;这是精确
算法而非近似,缺点仅在于大规模时的计算量,确有需要时可换旋转卡壳算法
$O(m)$\cite{preparata,toussaint,cgrl}。本文以顶点对枚举为基准实现,旋转卡壳仅作
对照。单点的直径为 $0$,线段的直径为端点距离。
\subsection{直径圆覆盖的充要条件与反例}
\textbf{定理~2}(覆盖判定)\quad 取任意一组最远顶点 $a,b$,记 $D=\|a-b\|$、
$o=(a+b)/2$。存在直径为 $D$ 的圆覆盖 $P$,当且仅当所有顶点满足
$\|v_i-o\|\le D/2$。
\textbf{证明}\quad 若半径 $D/2$、圆心 $z$ 的圆同时包含 $a,b$,则
$D\le\|a-z\|+\|z-b\|\le D$,两处不等号必须同时取等,故 $z$ 在 $a,b$ 连线上且到
两点等距,只能是中点 $o$;$D=0$ 时结论直接成立。又圆盘是凸集,包含全部顶点等价
于包含其凸包,故只需在这唯一可能的圆心处检查全部顶点。\hfill$\square$
该判定同时回答“以某条直径线段为直径的圆能否覆盖”与“能否移动一个同样大小的圆
使其覆盖”:检查失败时,移动圆心或更换最远顶点对均不可能成功。定义最大超出量
$E=\max_i\|v_i-o\|-D/2$:精确算术下不会出现严格负值(最远顶点对就在圆周上),
$E>0$ 即覆盖失败,取达到最大值的顶点即得可独立复核的失败证据。
\textbf{结论:直径圆不一定覆盖定位区域。}反例如表~\ref{tab:counterexample} 所示
(误差半角均取 $1^{\circ}$,符合题设测向条件)。
\begin{table}[htbp]
\centering
\caption{符合题设测向条件的反例:三点观测}
\label{tab:counterexample}
\begin{tabular}{ccc}
\toprule
检测点 & 坐标(米) & 示向度 \\
\midrule
$s_1$ & $(-1000,0)$ & $1^{\circ}$ \\
$s_2$ & $(540,-500\sqrt{3})$ & $121^{\circ}$ \\
$s_3$ & $(520,520\sqrt{3})$ & $241^{\circ}$ \\
\bottomrule
\end{tabular}
\end{table}
三个角域的下边界方向分别为 $0^{\circ},120^{\circ},240^{\circ}$,对应左半平面
$y\ge0$、$\sqrt{3}\,x+y\le40\sqrt{3}$、$y\le\sqrt{3}\,x$,其交为顶点 $A=(0,0)$、
$B=(40,0)$、$C=(20,20\sqrt{3})$ 的等边三角形。以 $s_1$ 为例,它到三顶点的方向分别
为 $0^{\circ},0^{\circ},\arctan(20\sqrt{3}/1020)\approx1.945^{\circ}$,均在
$[0^{\circ},2^{\circ}]$ 内,故上边界不切去该三角形;其余两站由绕三角形中心旋转
$120^{\circ}$ 的对称性同理成立,三个完整前向角域之交恰为该三角形。取真实源为
三角形中心 $g_*=(20,20\sqrt{3}/3)$:以 $s_1$ 为例,真实方位约 $0.649^{\circ}$,与
读数 $1^{\circ}$ 的偏差不超过 $1^{\circ}$,检测距离约 $1020$ 米,不超过 $1500$ 米,
另两站同理,故该反例符合题设的误差界与有效接收半径范围。此时 $D=40$ 米,以 $AB$
为直径的圆中心为 $(20,0)$,到 $C$ 的距离为 $20\sqrt{3}>20$ 米,不能覆盖;换任何
最远顶点对亦然。该三角形的最小包围圆即其外接圆,半径
$40/\sqrt{3}\approx23.094011$ 米。这同时说明“直径不超过 $40$ 米”不足以保证一次
清除。
\subsection{最小包围圆与可保证清除}
定位的最终目的是清除(附录~2 第(8)项的 $20$ 米距离判据),故正确工具是最小
包围圆
\begin{equation}
\rho(K)=\min_{z}\max_{g\in K}\|g-z\|.
\label{eq:mec}
\end{equation}
对有限顶点集 $V$,$f(z)=\max_{v\in V}\|v-z\|$ 连续且随 $\|z\|\to\infty$ 趋于无穷,
最小值存在;若两个不同中心 $c_1,c_2$ 都以半径 $r$ 覆盖 $V$,则中点 $c=(c_1+c_2)/2$
对每个顶点满足
$\|v-c\|^2=(\|v-c_1\|^2+\|v-c_2\|^2)/2-\|c_1-c_2\|^2/4<r^2$,
与最小性矛盾,故最小包围圆唯一。在最优中心处,圆周上的顶点集 $T$ 满足
$c\in\mathrm{conv}(T)$(否则沿严格分离方向小幅移动中心,可使所有圆周点的距离同时
减小,产生矛盾);二维凸组合经仿射相关权重消元至多保留 $3$ 个点,故最小包围圆由
至多 $3$ 个圆周顶点支撑。进而若 $c=\sum_j\lambda_jp_j$ 为支撑点凸组合,则对任意
$z$ 有 $\sum_j\lambda_j\|p_j-z\|^2=r^2+\|c-z\|^2\ge r^2$,给出任何覆盖圆半径不能
小于 $r$ 的直接证据。
求解采用带固定随机种子的 Welzl 随机增量算法\cite{welzl,mcgill}:打乱点序,若当前
圆不包含新点,则在该点成为边界点的约束下求解较小子问题,边界点至多 $3$ 个;实现
用显式栈避免递归深度限制,$3$ 个强制边界点必须用外接圆,不能替换成其无约束最小
圆。其期望线性复杂度依赖随机排列分析,不等于任意固定排列的最坏时间保证;另保留
支撑点枚举法(单点零半径圆、两点直径圆、三点外接圆,最坏 $O(m^4)$)作独立对照。
$\rho(K)\le20$ 时,最小包围圆圆心即可作为清除点;更一般地,所有可保证清除的位置
组成
\begin{equation}
C_{20}(K)=\bigcap_{g\in K}B(g,20)=\bigcap_{v\in V}B(v,20),
\label{eq:c20}
\end{equation}
第二个等号来自圆盘的凸性;该集合非空当且仅当 $\rho(K)\le20$,非空时可取其中距
机器狗最近者以节省移动。相比之下,$D\le40$ 只是必要条件(见上节反例)。
\subsection{算法流程与演练复算}
综合上述结果,问题~1 的完整算法如下。
\textbf{算法~1}(角域交、直径与覆盖证据)
\begin{enumerate}[label=\arabic*.,leftmargin=2.5em]
\item 校验观测并进行坐标平移、尺度归一化,保留原误差半角;
\item 按 \eqref{eq:cross} 生成每次观测的半平面约束(含前向约束);
\item 枚举非平行边界交点,保留满足全部约束的点;无观测与空集分别处理;
\item 检验非零衰退方向;存在时报告无界并停止有限圆计算;
\item 对可行点去重并求凸包,识别单点、线段或多边形;
\item 枚举顶点对求直径及任意一组最远顶点;
\item 检查其中点到全部顶点的距离,输出最大超出量 $E$ 与失败顶点;
\item 求最小包围圆,换回原坐标,重新检查顶点包含性,输出清除半径余量。
\end{enumerate}
设半平面数为 $k$(约为观测数的 $3$ 倍)、顶点数为 $m$:边界交点枚举及全约束检查
为 $O(k^3)$,衰退方向检查为 $O(k^2)$,交点排序上界为 $O(k^2\log k)$,直径计算为
$O(m^2)$,覆盖证据检查为 $O(m)$;随机增量最小圆在随机排列下期望为 $O(m)$。整体仍
由半平面交点枚举主导,不能称为总体线性算法。数值实现上,数学结论使用精确不等式,
浮点计算先平移、归一化,再以位置容差、平行判定阈值和衰退方向容差分别处理不同
问题;接近平行或退化的输入应作精度与容差敏感性检查,任意追加固定小数裕量不能
替代严格的误差传播分析。清除判断采用 $\rho+\varepsilon_m\le20$,其中
$\varepsilon_m$ 为工程数值裕量。
\textbf{演练复算。}对官方演练案例 \texttt{U5ZW-P9KN-TCAG-R7ST} 的三点观测离线复算,
结果如表~\ref{tab:q1practice}。两种口径下直径圆均不覆盖定位区域($E>0$),但最小
包围圆半径均小于 $20$ 米,即存在一点可保证清除,与可视化结果一致。该演练未公开
源坐标且未执行清除,故仅用于观测交会与计算一致性复核,不能据此声称实测定位误差
或清除成功率。\todonote{此处可补充定位区域图(figures/)}
\begin{table}[htbp]
\centering
\caption{官方演练三点观测的离线复算结果}
\label{tab:q1practice}
\begin{tabular}{cccc}
\toprule
误差半角 & 直径 $D$ / 米 & 最小包围半径 $\rho$ / 米 & 直径圆最大超出 $E$ / 米 \\
\midrule
$1^{\circ}$ & 23.996723 & 12.068583 & 0.604002 \\
$1.005^{\circ}$ & 24.119088 & 12.130377 & 0.608486 \\
\bottomrule
\end{tabular}
\end{table}
\section{问题~2:第二检测点的主动选点模型}
\subsection{建模思路来源}
问题~2 给定“某全向干扰源在一个检测点处测得的示向度”,要求“给出第二个检测点的
选择策略,以获得关于该干扰源较好的定位效果,并给出第二个检测点的候选区域”。
注意源类型明确为全向,不能混入问题~4 的朝向可见性条件。本问方法的取舍同样由
题面描述逐项确定。
\textbf{先接收、后优化。}附录~2 第(2)项规定各源有效接收半径在 $1000$ 至 $1500$
米之间且具体值未知。真实源位置未知时,若第二检测点距真源超过其实际接收半径,
第二次检测将返回 \texttt{no\_signal},任何定位收益都无从谈起。因此把本问拆成
先后两个问题:先构造“无论真源在候选集合内何处都能收到信号”的安全候选区域,
再在其中优化定位效果。若只追求较大交会角而不控制到真实源的距离,预期几何收益
可能根本无法实现。
\textbf{由误差描述确定最坏情形指标。}题面只给出有界误差(附录~2 第(1)项),没有
给出源位置的概率分布,也不存在可独立重抽样的测向噪声模型(同一地点误差固定,
重复检测不产生新信息)。因此不能把卡尔曼滤波、协方差传播或费舍尔信息直接用作
严格保证,本文以最坏情形的后验包围半径作为选点主目标\cite{boyd};交会角仍有
明确的几何意义,但只作局部解释与候选筛选依据。
\textbf{由区域描述确定活动范围。}题面第~1 页的 $1800$ 米圆域限制的是干扰源位置;
附录~3 说明机器狗位置通常不构成约束(接口坐标分量绝对值上限仅为数值防护)。
故第二检测点允许位于 $\Omega$ 之外,安全候选区域不受源位置圆域限制。
\textbf{由 near 机制确定分支处理。}附录~2 第(9)项规定检测点距源不超过 $5$ 米时
“无法获得示向度信息,此时可直接进行光学精确定位并清除干扰源”。返回
\texttt{near} 不是策略失败,而是定位效果更好的分支(不确定半径不超过 $5$ 米),
应单独建模并就地清除。
\textbf{由动作耗时确定成本项。}附录~2 第(5)、(6)项规定检测耗时 $5$ 秒、移动
速度 $5$ 米/秒,故第二点的成本取移动与检测耗时之和,作为后验半径择优之后的次
目标,避免任意混合米与秒。
\subsection{首次观测后的候选集合}
设在 $s_1$ 处首次测得 \texttt{direction},示向度 $\theta_1$,记 $u=u(\theta_1)$。
由角域模型、题面第~1 页的源位置圆域与附录~2 第(2)项的接收半径上界,真实源
$g$ 满足
\begin{equation}
g\in K_1=\Omega\cap W(s_1,\theta_1,\delta)\cap B(s_1,R_+),
\qquad R_+=1500,
\label{eq:k1}
\end{equation}
即保守位置候选集合 $K_1$ 为闭凸紧集;观测一致时它必含真源,从而非空。首次返回
\texttt{direction} 还意味着 $\|g-s_1\|>5$(附录~2 第(9)项),但排除这个开圆盘
会破坏凸性,本文暂不使用该信息,保留包含真源的凸外包集合:由此得到的保证可能
更保守,但绝不误删真实位置。若计算得到 $K_1=\varnothing$,说明输入、频道、误差
界或数值处理与题设不一致,应返回不一致状态,不能继续给空集计算圆心。
\subsection{安全候选区域的定义与非空判据}
第二个检测点 $q$ 必须保证:无论真源位于 $K_1$ 内何处,都有 $\|q-g\|\le R_-$
($R_-=1000$),从而对任何 $R_c\ge R_-$ 都能收到信号。定义
\begin{equation}
F_K(q)=\max_{g\in K}\|q-g\|,\qquad
\mathcal{Q}(K)=\{q:F_K(q)\le R_-\}=\bigcap_{g\in K}B(g,R_-).
\label{eq:Q}
\end{equation}
保证接收不等于保证返回示向度:距离不超过 $5$ 米时可能返回 \texttt{near},该分支
定位效果更好(见 6.6 节),不能视为策略失败。
\textbf{命题~1}($F_K$ 的凸性与稳定性)\quad 对任意非空紧集 $K$,$F_K$ 为凸函数,
且 $|F_K(q_1)-F_K(q_2)|\le\|q_1-q_2\|$。
\textbf{证明}\quad 对每个固定的 $g$,距离函数关于 $q$ 凸,逐点取最大值保持凸性;
由三角不等式 $\|q_1-g\|\le\|q_2-g\|+\|q_1-q_2\|$,对 $g$ 取最大得到一个方向的
不等式,再交换两点即得 Lipschitz 性。\hfill$\square$
故 $\mathcal{Q}(K)$ 为闭凸集;非空时它含于任一 $B(g_0,R_-)$ 内,因而有界。
\textbf{定理~1}(非空判据)\quad $\mathcal{Q}(K)\ne\varnothing$ 当且仅当
$\rho(K)\le R_-$。
\textbf{证明}\quad 由定义 $\rho(K)=\min_q F_K(q)$;$F_K$ 连续且随 $\|q\|\to\infty$
趋于无穷,最小值可达,故“存在 $q$ 使 $F_K(q)\le R_-$”与“该最小值不超过 $R_-$”
完全等价。\hfill$\square$
当 $\rho(K)=R_-$ 时,安全区域仅含最小包围圆中心这个单点(唯一性见 5.6 节),因此
判据必须使用不严格不等式,不能把等号情形误判为空。
\textbf{外包圆给出的充分区域。}若已知 $K\subseteq B(c,r)$ 且 $r\le R_-$,则对任意
$\|q-c\|\le R_--r$ 的点都有 $\|q-g\|\le\|q-c\|+\|c-g\|\le R_-$,故
\begin{equation}
B(c,R_--r)\subseteq\mathcal{Q}(K).
\label{eq:sufficient}
\end{equation}
这给出容易计算的充分候选区域;但一个满足 $r>R_-$ 的宽松外包圆只能说明该外包圆
不能提供证书,不能据此判定真实的 $\mathcal{Q}(K)$ 为空。
\subsection{截断角域的解析最小包围圆}
首次角域狭窄($\delta=1^{\circ}$)这一题设特征,使 \eqref{eq:sufficient} 所需的
外包圆可以解析地算到最小。暂时去掉只会缩小集合的 $\Omega$ 约束,考虑完整截断
角域 $S=W(s_1,\theta_1,\delta)\cap B(s_1,R_+)$,其点可写成
$g=s_1+t\,u(\theta_1+\varphi)$($0\le t\le R_+$,$|\varphi|\le\delta$)。令
\begin{equation}
a=\frac{R_+}{2\cos\delta},\qquad c=s_1+a\,u.
\label{eq:ac}
\end{equation}
\textbf{定理~2}(截断角域的最小包围圆)\quad 对 $0\le\delta\le45^{\circ}$,$S$ 的
最小包围圆恰为 $B(c,a)$。
\textbf{证明}\quad 先证包含。对 $g=s_1+t\,u(\theta_1+\varphi)\in S$,
\begin{equation}
\|g-c\|^2=t^2+a^2-2at\cos\varphi.
\label{eq:dist}
\end{equation}
固定 $\varphi$ 时右端关于 $t$ 为凸二次函数,区间最大值在端点取得:$t=0$ 时等于
$a^2$;$t=R_+$ 时由 $\cos\varphi\ge\cos\delta$ 得
$\|g-c\|^2\le R_+^2+a^2-2aR_+\cos\delta=a^2$,最后一步代入了
$a=R_+/(2\cos\delta)$。故 $S\subseteq B(c,a)$。
再证最小。取 $p_0=s_1$、$p_{\pm}=s_1+R_+u(\theta_1\pm\delta)$,三点都在 $B(c,a)$
的圆周上。令 $\lambda_+=\lambda_-=1/(4\cos^2\delta)$、
$\lambda_0=1-1/(2\cos^2\delta)$;$\delta\le45^{\circ}$ 时三权重非负且和为 $1$,
直接代入得 $c=\lambda_0p_0+\lambda_+p_++\lambda_-p_-$。于是对任意中心 $z$,由加权
距离恒等式
\begin{equation}
\sum_j\lambda_j\|p_j-z\|^2=a^2+\|c-z\|^2\ge a^2,
\end{equation}
故任何覆盖这三点的圆半径不小于 $a$;而覆盖 $S$ 的圆必须覆盖这三点,结合包含性
知最小半径恰为 $a$。$\delta=0$ 时两个远端点重合,结论退化为长度 $R_+$ 的线段
直径圆,仍成立。\hfill$\square$
该推导不依赖源位置先验与任何概率分布;它给出完整截断角域的精确最小圆,与
$\Omega$ 相交后,真实 $K_1$ 的最小圆可能更小。
\subsection{本题可直接采用的安全候选圆盘}
由 $K_1\subseteq S\subseteq B(c,a)$ 与 \eqref{eq:sufficient},取
\begin{equation}
\mathcal{Q}_0=B(c,b),\qquad b=R_--a=1000-\frac{1500}{2\cos\delta},
\label{eq:Q0}
\end{equation}
数值见表~\ref{tab:q2disk}。
\begin{table}[htbp]
\centering
\caption{安全候选圆盘的解析参数}
\label{tab:q2disk}
\begin{tabular}{ccc}
\toprule
误差半角 $\delta$ & 轴向中心距离 $a$ / 米 & 安全候选半径 $b$ / 米 \\
\midrule
$1^{\circ}$ & 750.114246 & 249.885754 \\
$1.005^{\circ}$ & 750.115391 & 249.884609 \\
\bottomrule
\end{tabular}
\end{table}
两种口径下 $b>0$,故本题首次有效测向后的安全候选区域由解析证明严格非空,无需把
“若安全区域为空就去最小包围圆圆心”作为保底步骤(对一般候选集合,$\rho(K)>R_-$
时根本不存在保证接收的点)。几何上 $\mathcal{Q}_0$ 位于首测示向方向前方约 $750$
米处、半径约 $250$ 米,与首测点相距至少约 $500$ 米,还天然避免了同点重复测量不
产生新信息的问题(附录~2 第(1)项)。机器狗不受源位置圆域限制,即使 $c$ 位于
$\Omega$ 外,选点也合法。为抵消坐标计算与动作提交中的工程舍入,可取缩小区域
$\mathcal{Q}_\eta=B(c,b-\eta)$($0<\eta<b$,如 $\eta=0.01$ 米):若圆心与提交位置
的合计偏差不超过 $\eta$,三角不等式保证仍有 $\|q-g\|\le1000$;这是可调工程选择,
不是题面要求。若有更精细的 $K_1$ 外包圆,可得更大的充分区域;这些扩展均属性能
优化,不影响 $\mathcal{Q}_0$ 的正确性。
\subsection{“较好的定位效果”的数学定义}
\textbf{保守后验集合。}对 $q\in\mathcal{Q}_0$,若返回 \texttt{direction} 及读数
$\beta$,定义 $K_d(q,\beta)=K_1\cap W(q,\beta,\delta)$(继续忽略距离超过 $5$ 米的
非凸排除信息),真源必在其中;若返回 \texttt{near},定义
$K_n(q)=K_1\cap B(q,5)$,故 $\rho(K_n)\le5$,可直接在当前位置光学定位并清除,满足
$20$ 米清除条件,不必强行再取一个角度。以 $d_{\mathbb{S}^1}$ 记圆周角距离,对
$\|g-q\|>5$ 的候选位置记真实方位 $h_q(g)=\operatorname{atan2}(g_y-q_y,g_x-q_x)$,
则可能读数集合为
$\mathcal{B}(q)=\{\beta:\exists\, g\in K_1,\ \|g-q\|>5,\ d_{\mathbb{S}^1}(\beta,h_q(g))
\le\delta\}$。这里用所有允许误差描述可能读数,而不是假设误差可以随机独立重抽样。
\textbf{最坏后验半径指标。}定义 $J(q)$ 为所有可能 \texttt{direction} 分支
$\rho(K_d(q,\beta))$ 与非空 \texttt{near} 分支 $\rho(K_n(q))$ 的上确界,即未来所有
允许观测下最坏的保守包围半径;不存在的观测分支不参与取最大。选点主目标即在安全
候选区域内降低 $J(q)$。该指标直接服务一次清除要求:$J(q)\le20$ 时每个可能分支都
有半径不超过 $20$ 米的保守定位圆;它比面积更贴合任务——面积较小的集合仍可能
十分狭长。注意后验总是 $K_1$ 的子集,故 $J(q)\le\rho(K_1)$,但不一定严格小于:
不能仅由“增加一次观测”推断精度必然严格改善,更不能保证两次测向即达 $20$ 米
阈值。
\textbf{移动成本与字典序。}连续测量同一频道时,本次动作的虚拟时间增量为
\begin{equation}
C(q)=\|q-s_1\|/5+5\ \text{秒}.
\label{eq:cost}
\end{equation}
以 $\widehat{J}(q)$ 表示实际计算的评估量(6.8 节取保守上界 $\overline{J}(q)$),
推荐先按后验半径择优,再保留满足 $\widehat{J}(q)\le J_{\min}+\tau$ 的近优点并取
其中 $C(q)$ 最小者,其中 $\tau\ge0$ 是显式声明的定位容忍量(米),$\tau=0$ 对应
严格字典序;本文不预设未经实验支持的最优 $\tau$。
\subsection{交会角的局部几何解释}
在假定真实位置 $g$ 附近,记两站距离为 $r_1,r_2$,真实视线单位向量为 $u_1,u_2$,
对应法向量为 $n_1,n_2$。角误差很小且位置扰动相对站距很小时,方位函数的一阶展开
给出 $n_i\cdot\Delta g\approx r_ie_i$($|e_i|\le\delta_{\mathrm{rad}}$,弧度),即
局部不确定区域近似由两条带状约束 $|n_i\cdot\Delta g|\le r_i\delta_{\mathrm{rad}}$
限定。若视线交会角为 $\phi$,法向量矩阵的行列式绝对值为 $|\sin\phi|$,对法向坐标
中的矩形作线性逆变换,得近似面积
\begin{equation}
A_{\mathrm{loc}}\approx\frac{4\,r_1r_2\,\delta_{\mathrm{rad}}^{2}}{|\sin\phi|}.
\label{eq:anglearea}
\end{equation}
这解释了两点:视线近于平行或反向时误差被显著放大;在距离不变的局部比较下,接近
直角的交会较有利。但真实源位置未知,$r_2$ 与 $\phi$ 随 $g$ 改变,且有限角域并非
无限带状区域,故不能由此推出“总应横移固定距离”或“对某个假定源位置成
$90^{\circ}$ 即全局最优”。本文仅用它优先考虑轴线两侧的候选点,最终仍以后验集合
指标评价,交会角只作同分筛选指标。
\subsection{圆弧先验的保守离散与读数区间评估}
\textbf{外包切线多边形。}直接连接圆周采样点得到的是内接多边形,会错误排除圆盘
边缘的真实位置。为复用问题~1 的半平面工具,取 $M\ge3$ 个均匀法向量
$v_j=u(2\pi j/M)$,定义
\begin{equation}
P_M(o,R)=\{x:v_j\cdot(x-o)\le R,\ j=0,\dots,M-1\}.
\end{equation}
由柯西不等式,$B(o,R)\subseteq P_M(o,R)$;相邻切线交点到圆心的距离为
$R\sec(\pi/M)$,故单个圆盘外包的最大径向超出不超过 $R[\sec(\pi/M)-1]$。令
$\widetilde{K}_1=P_M(0,1800)\cap W(s_1,\theta_1,\delta)\cap P_M(s_1,1500)$,则
$K_1\subseteq\widetilde{K}_1$,对任何第二读数再求半平面交仍保留真源。靠近切触或
退化情形须加密检查,不能把单圆径向误差未经论证直接当成最终定位半径的误差界。
安全选点仍使用解析的 $\mathcal{Q}_\eta$:即使粗糙外包多边形的最小圆偏大,也不能
据此推翻解析安全区域的非空结论。若改用任意有界凸外包多边形
$\widetilde{K}=\mathrm{conv}\{v_j\}$,则
$\max_{g\in\widetilde{K}}\|q-g\|=\max_j\|q-v_j\|$(与 5.4 节相同的凸组合论证),
其保证接收区域由有限个圆盘约束 $\|q-v_j\|\le1000$ 给出;离散区域为空时优先加密
或回到解析候选盘,不把离散失败误报为问题无解。
\textbf{读数区间的保守评估。}仅枚举少量假定源位置与误差端点,只得到被枚举情形的
最大值,可能漏掉真正最坏的读数。将整周按圆周意义划分为若干区间 $I_j$(中心
$\beta_j$、宽度 $h_j$,要求 $\delta+h_j/2<90^{\circ}$,跨 $0^{\circ}$ 的区间按
圆周距离处理)。
\textbf{命题~2}\quad 对任意 $\beta\in I_j$,有
$W(q,\beta,\delta)\subseteq W(q,\beta_j,\delta+h_j/2)$。
\textbf{证明}\quad 左侧角域内任意非顶点位置,其方向到 $\beta$ 的圆周距离不超过
$\delta$,而 $\beta$ 到区间中心的距离不超过 $h_j/2$,由圆周距离的三角不等式,其
方向到中心的距离不超过两者之和;顶点在两个闭角域中均被保留。\hfill$\square$
定义 $U_j(q)=\widetilde{K}_1\cap W(q,\beta_j,\delta+h_j/2)$,则落在该区间的任何
真实读数对应的保守后验都含于 $U_j(q)$,从而
$\rho(K_d(q,\beta))\le\rho(U_j(q))$;\texttt{near} 分支取统一上界
$\min\{5,\rho(\widetilde{K}_1)\}$。令 $\overline{J}(q)$ 为所有非空 $U_j(q)$ 的最小
包围半径与该上界的最大值,则 $J(q)\le\overline{J}(q)$(精确几何计算下成立;浮点
实现还须另行给出包含性与数值误差处理)。二分角区间或增加外包切线都使相应上界
单调不增,给出稳定的自适应加密方向。实际可先以少量读数采样粗筛,再对入围点使用
完整区间上界:粗筛只决定计算资源分配,最终报告的保守上界必须来自完整覆盖的
区间,不能来自粗筛样本最大值。
\subsection{选点算法与边界情形}
\textbf{算法~2}(安全区域内的有限候选主动测向)
\begin{enumerate}[label=\arabic*.,leftmargin=2.5em]
\item 核验首次观测为同一全向源的有效示向度,构造 $K_1$ 或其保守表示;
\item 按 \eqref{eq:ac} 计算 $a$、$c$ 与 $b=1000-a$,选取满足误差预算的缩小半径
$b-\eta$;
\item 构造有限候选集:圆心 $c$ 及
$q=c+r_\ell(\cos\psi_j\,u+\sin\psi_j\,u_\perp)$($0<r_\ell\le b-\eta$、
$\psi_j=2\pi j/N_\psi$、$u_\perp=(-\sin\theta_1,\cos\theta_1)$),全部候选
自动满足接收距离保证;
\item 对每个候选点构造外包后验并评估 $\overline{J}(q)$,保存最坏角区间及对应
包围圆作为评估依据;
\item 优先取 $\overline{J}$ 较小者,按预先声明的 $\tau$ 筛出近优点后比较移动
检测成本,必要时以固定顺序消除完全同分;
\item 在计算预算内对入围候选附近加密位置、细分最坏角区间并增加外包切线;预算
耗尽时返回当前已验证安全的最好点;
\item 在所选位置测量同一频道:若 \texttt{near} 则就地清除;若 \texttt{direction}
则用实际读数更新候选集合并复算最小包围圆,半径仍大于 $20$ 米时继续测向,
不宣称两次定位已经完成;
\item 若在距离保证条件下意外返回 \texttt{no\_signal},核查动作是否被接受、频道
是否正确、源是否仍存在及坐标模型是否一致;原因查明前不按正常
\texttt{direction} 分支更新候选。
\end{enumerate}
例如可取 $3$ 层半径、每层 $16$ 个方向加圆心共 $49$ 个候选点起步;这只是位置搜索
的数值分辨率示例,与问题~3 的 $49$ 点覆盖网格无关,也不是已优化参数。设候选数为
$N_q$、角区间数为 $N_\beta$、每个后验的半平面数为 $k$,复用问题~1 的边界枚举时
主计算量约为 $O(N_qN_\beta k^3)$,另加直径或最小圆计算;选点器自身的运行时间不能
忽略。算法输出保证的是:所选点位于已证明安全的区域内,并在给定有限候选与评估
精度下按既定规则择优;本文未证明 $q\mapsto J(q)$ 为凸函数,也未证明有限候选的
最优点就是整个 $\mathcal{Q}(K_1)$ 中的全局最优点。
\textbf{边界情形。}(i)$K_1$ 为空:报告模型或数据不一致,不构造虚假圆心;
(ii)首次结果已是 \texttt{near}:直接清除,不再套用本问流程;
(iii)一般集合满足 $\rho(K)=1000$:安全区域退化为最小包围圆中心这个单点;
(iv)$\rho(K)>1000$:不存在对该集合全部位置保证接收的点,圆心仅是最小化最坏
距离的探索选择,改善交会角若要求偏离该中心还会牺牲最坏距离最优性,两项冲突的
要求不能同时称为已保证;(v)外包圆半径大于 $1000$:只能说明该证书不足,不能
判真实安全区域为空;(vi)测量轴接近 $0^{\circ}/360^{\circ}$:使用向量约束与
圆周区间,避免角度断点错误;(vii)两次测向交会较差:保留完整后验并继续测量,
不把小面积当成小直径;(viii)源类型为定向:距离证书仍成立,但接收还受朝向
限制,不能直接沿用本问的接收保证(见问题~4)。
\todonote{候选区域示意图与选点对比实验待补}
\section{问题~3:全向干扰源的搜索定位与清除调度}
\subsection{虚拟时间与动作成本模型}
依据题设动作耗时,完成任务所需虚拟时间
\begin{equation}
T=\frac{L}{5}+N_{\mathrm{switch}}+5N_{\mathrm{measure}}
+5N_{\mathrm{clear}}^{\mathrm{s}}+3N_{\mathrm{clear}}^{\mathrm{f}},
\label{eq:time}
\end{equation}
其中 $L$ 为移动总路程(含检测与清除引发的移动),频道切换次数只计被接受的检测
动作。优化顺序为:先保证全部清除,再减小 $T$;不能通过少清除源来改善平均时间。
虚拟活动时长上限为 $100$ 小时;程序运行时间另受 $20$ 分钟窗口约束,二者独立。
\subsection{全域覆盖发现基线}
在 $s$ 处对某频道测得 \texttt{no\_signal},只能排除以 $s$ 为中心、半径 $1000$ 米
圆盘内存在该频道源(有效接收半径可能只有 $1000$ 米),不能一律排除到 $1500$ 米。
据此构造覆盖点集
\begin{equation}
S=\{(700i,700j):i,j=-3,-2,\dots,3\},\qquad |S|=49,
\end{equation}
其覆盖范围 $[-2100,2100]^2$ 包含 $\Omega$。对任一单元内的源 $g$,其所在单元的
$4$ 个格点到 $g$ 的距离均不超过 $700\sqrt{2}\approx 989.95<1000$ 米,故必存在
合格检测点;又 $g$ 位于 $4$ 个格点的凸包内部,经过 $g$ 的任意发射半平面必包含
至少一个格点(否则全部格点落入相反开半平面,与 $g$ 在凸包内矛盾)。因此 $49$ 点
逐一检测可保证发现该频道的源;源恰在网格线上时按半开区间归入相邻单元处理。
$49$ 点 $\times\,20$ 频道至多 $980$ 次检测,虚拟耗时上界约 $1.32\times 10^4$ 秒,
在 $100$ 小时上限内有充分设计空间;实际执行中已清除频道跳过、同点共享多频道测量、
已发现频道转入定位队列。
\subsection{发现—定位—清除闭环}
机器狗维护逐频道状态:未知/已发现待定位/可清除/已清除/已证明不存在,以及候选
集合 $K_c$。闭环流程为:覆盖扫描发现源 $\to$ 用问题~2 的主动选点缩小 $K_c$ 直至
$\rho(K_c)\le 20$ $\to$ 移动到 $C_{20}(K_c)$ 内距当前点最近的点清除 $\to$ 更新覆盖
记录与队列。多个已发现源按“预期信息改善/增量虚拟耗时”排序处理;候选采样点恰
返回 \texttt{near} 时立即就地清除。
\subsection{停止条件与结果统计}
\textbf{停止成功的依据为以下之一}:(i)已成功清除 $16$ 个不同频道的源(数量
上界);(ii)每个频道都已有清除成功记录或经完整覆盖证明不存在。发现 $10$ 个源、
连续若干次无信号、候选采样为空均不是充分停止条件;程序运行时间或窗口不足而退出
记为未证明完成,不与成功混记。结果统计按题设给出
\begin{align}
\text{被清除干扰源个数的比例} &= \frac{\text{被清除干扰源的个数}}{\text{干扰源总数}} ,\\
\text{平均定位清除时间} &= \frac{\text{定位清除总时间}}{\text{被清除干扰源的个数}} .
\end{align}
\begin{table}[htbp]
\centering
\caption{问题~3 正式测试结果(按题目表~1 格式)}
\label{tab:q3formal}
\begin{tabular}{lcccc}
\toprule
& 测试案例编码 & 清除干扰源个数 & 平均定位清除时间 & 程序运行时间 \\
\midrule
测试~1 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
测试~2 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
测试~3 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
\bottomrule
\end{tabular}
\end{table}
\todonote{演练测试统计值(清除比例、平均定位清除时间)待演练后填入}
\section{问题~4:含定向干扰源的检测与清除}
\subsection{定向源观测模型}
定向源的接收条件是“距离 $\le R_c$ 且检测点位于发射半平面内”。因此
\texttt{no\_signal} 约束的是位置—半径—朝向的\textbf{联合假设}:若不联合维护朝向
可行集合,就不能用它单独删除空间候选点。可靠基线是对 \texttt{no\_signal} 只记录
“该点覆盖检测已完成”,不做空间删除;加速版本再维护朝向可行集合,且必须验证
不误删真源。
\subsection{覆盖发现基线对定向源仍然有效}
由 7.2 节的凸包论证:源 $g$ 位于所在单元 $4$ 格点的凸包内部,故经过 $g$ 的任意
发射半平面必含至少一个格点;该格点同时满足距离不超过 $989.95<1000$ 米。因此
$49$ 点逐频道检测对全向与定向源统一保证发现,包括贴近 $\Omega$ 边界朝外发射的源
(格点允许越出 $\Omega$ 访问)。
\subsection{失去信号后的后备清除}
已发现的定向源在定位过程中可能再次失去信号。对已知有界候选集合 $K$,构造边长
$20$ 米的全局网格:格中心到格内任意点距离不超过 $10\sqrt{2}\approx 14.14<20$ 米,
保留与 $K$ 的外包框相交的格子即得无空洞的有限圆盘覆盖,逐点调用清除动作。请求
次数上界
\begin{equation}
N\le\Bigl(\lceil w/20\rceil+2\Bigr)\Bigl(\lceil h/20\rceil+2\Bigr),
\end{equation}
其中 $w,h$ 为候选集合外包框的宽与高;单源全失败清除耗时为 $L/5+3N$。若 $K$ 外包
尺寸较大(如半径 $1500$ 米圆盘的外包框达上万格点),盲扫不满足现实预算,应先继续
定位缩小候选集合。现实时间预算按“剩余请求数 $\times$ 实测单请求高分位耗时”估计,
不满足预算时转入其他任务或按预算退出。
\begin{table}[htbp]
\centering
\caption{问题~4 正式测试结果(按题目表~1 格式)}
\label{tab:q4formal}
\begin{tabular}{lcccc}
\toprule
& 测试案例编码 & 清除干扰源个数 & 平均定位清除时间 & 程序运行时间 \\
\midrule
测试~1 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
测试~2 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
测试~3 & \todonote{待填} & \todonote{待填} & \todonote{待填} & \todonote{待填} \\
\bottomrule
\end{tabular}
\end{table}
\section{模型评价与推广}
\textbf{优点}:(1)四个问题复用同一几何内核(角域半平面交—直径—最小包围圆),
模型一致、实现可复用;(2)全程坚持保守几何:有界误差不取平均、无信号只排除
$1000$ 米、\texttt{no\_signal} 对定向源不删位置、停止条件需覆盖证明,所有“清除
完毕”的结论都可验证;(3)虚拟时间公式把调度目标显式化,且区分了虚拟时间与程序
运行时间两类约束。
\textbf{缺点与改进}:(1)主动选点采用最坏情形采样,是启发式而非全局最优,可研究
对候选集合的更精细离散化;(2)$49$ 点覆盖基线存在冗余,自适应跳点须以保留逐频道
覆盖证据为前提;(3)后备清除请求数较大,宜结合朝向可行集合减小候选集合;(4)
当前演练验证限于问题~1 的几何内核,问题~3、4 的闭环策略与统计结果有待演练填充。
\begin{thebibliography}{9}
\zihao{5}
\bibitem{preparata} Preparata F P, Shamos M I. Computational Geometry: An
Introduction[M]. New York: Springer-Verlag, 1985.
\bibitem{welzl} Welzl E. Smallest enclosing disks (balls and ellipsoids)[C]//
Maurer H. New Results and New Trends in Computer Science. Lecture Notes in
Computer Science, vol 555. Berlin: Springer, 1991: 359--370.
\bibitem{toussaint} Toussaint G T. Solving geometric problems with the rotating
calipers[C]//Proceedings of IEEE MELECON. Athens: IEEE, 1983.
\bibitem{mcgill} CGAL Project. Bounding Volumes: Min\_circle\_2[EB/OL].
\url{https://doc.cgal.org/latest/Bounding_volumes/}, 2026.
\bibitem{cgrl} McGill School of Computer Science. Rotating Calipers[EB/OL].
\url{https://www-cgrl.cs.mcgill.ca/~godfried/research/calipers.html}, 2026.
\bibitem{boyd} Boyd S, Vandenberghe L. Convex Optimization[M]. Cambridge:
Cambridge University Press, 2004.
\end{thebibliography}
\clearpage
% ============================================================
% 附录(页数不限;电子版与纸质版均须包含)
% ============================================================
\appendix
\section{支撑材料文件列表}
\todonote{提交前更新为实际支撑材料压缩包内容,须与附录~B 源码一致}
\begin{table}[htbp]
\centering
\caption{支撑材料文件列表}
\begin{tabular}{lll}
\toprule
文件/目录 & 内容 & 说明 \\
\midrule
\texttt{geometry/} & 几何内核源代码 & 角域交、直径、最小包围圆 \\
\texttt{planning.py} & 问题~2 安全候选盘计算 & \texttt{first\_bearing\_candidate\_disk} \\
\texttt{examples/q1/} & 问题~1 输入样例 & 含等边三角形反例 \\
\texttt{output/q1/} & 问题~1 输出与演练记录 & 优化报告、可视化 \\
\bottomrule
\end{tabular}
\end{table}
\section{程序源代码}
以下为支撑模型计算的核心源代码,完整可运行代码以支撑材料压缩包为准。
\subsection{\texttt{src/mcm26b/geometry/localization.py}:交会定位几何内核}
\lstinputlisting[language=Python]{../../src/mcm26b/geometry/localization.py}
\subsection{\texttt{src/mcm26b/geometry/planning.py}:问题~2 安全候选区域}
\lstinputlisting[language=Python]{../../src/mcm26b/geometry/planning.py}
\end{document}
+107
View File
@@ -0,0 +1,107 @@
% ============================================================
% 2026 年高教社杯全国大学生数学建模竞赛论文模板(B 题)
% ============================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mcm26b-paper}[2026/09/11 MCM 2026 paper class]
% 电子版为默认模式;纸质版通过 class option `paper' 开启。
\newif\ifpaper
\paperfalse
\DeclareOption{paper}{\papertrue}
\DeclareOption{electronic}{\paperfalse}
% 将其余选项(如 zihao=-4、a4paper)交给 ctexart。
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{ctexart}}
\ProcessOptions\relax
\LoadClass{ctexart}
% ---------- 页面与基础宏包 ----------
\RequirePackage[left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm]{geometry}
\RequirePackage{amsmath,amssymb,bm}
\RequirePackage{graphicx}
\RequirePackage{booktabs,array,multirow,longtable}
\RequirePackage[font=small,labelsep=quad]{caption}
\RequirePackage{xcolor}
\RequirePackage{listings}
\RequirePackage{enumitem}
\RequirePackage[hidelinks]{hyperref}
% ---------- 字体设置(使用模板目录 fonts/ 下的字体) ----------
% 中文正文:宋体(Songti SC);标题/强调:黑体(Heiti SC)
% 西文与数字:Times New Roman
% 若未携带 fonts/ 目录,可将下面设置替换为系统字体,例如:
% \setCJKmainfont{SimSun} \setCJKsansfont{SimHei}
\setmainfont{Times New Roman}[
Path = fonts/, Extension = .ttf,
BoldFont = {Times New Roman Bold},
ItalicFont = {Times New Roman Italic},
BoldItalicFont = {Times New Roman Bold Italic},
]
\setCJKmainfont{SongtiSC}[
Path = fonts/, Extension = .ttf,
UprightFont = SongtiSC-Regular,
BoldFont = SongtiSC-Bold,
ItalicFont = SongtiSC-Regular,
BoldItalicFont = SongtiSC-Bold,
]
\setCJKsansfont{HeitiSC}[
Path = fonts/, Extension = .ttf,
UprightFont = HeitiSC-Light,
BoldFont = HeitiSC-Medium,
]
\setCJKmonofont{SongtiSC}[Path = fonts/, Extension = .ttf, UprightFont = SongtiSC-Regular]
\setCJKfamilyfont{zhsong}{SongtiSC}[Path = fonts/, Extension = .ttf, UprightFont = SongtiSC-Regular, BoldFont = SongtiSC-Bold]
\setCJKfamilyfont{zhei}{HeitiSC}[Path = fonts/, Extension = .ttf, UprightFont = HeitiSC-Light, BoldFont = HeitiSC-Medium]
\setCJKfamilyfont{zhkai}{SongtiSC}[Path = fonts/, Extension = .ttf, UprightFont = SongtiSC-Regular]
% ---------- 标题层级:一级四号黑体居中,二级小四黑体左对齐 ----------
\ctexset{
section = {
format = {\centering\heiti\zihao{4}},
aftername = {\quad},
beforeskip = {1.2ex plus 0.3ex},
afterskip = {1.0ex plus 0.2ex},
},
subsection = {
format = {\heiti\zihao{-4}},
aftername = {\quad},
beforeskip = {1.0ex plus 0.2ex},
afterskip = {0.8ex plus 0.2ex},
},
subsubsection = {
format = {\heiti\zihao{-4}},
aftername = {\quad},
},
}
\linespread{1.4}
\setlength{\parskip}{0.3ex}
\setlength{\emergencystretch}{3em}
% 规范:页码位于页脚中部,阿拉伯数字从摘要页 1 开始连续编号。
\pagestyle{plain}
% ---------- 草稿批注宏(定稿前必须全部删除或落实) ----------
\newcommand{\todonote}[1]{\textcolor{red}{【#1】}}
% ---------- 代码排版设置(附录) ----------
\lstset{
language=Python,
basicstyle=\ttfamily\zihao{-5},
keywordstyle=\bfseries,
commentstyle=\color{black!60},
stringstyle=\color{black!60},
columns=fullflexible,
keepspaces=true,
breaklines=true,
breakatwhitespace=false,
showstringspaces=false,
numbers=left,
numberstyle=\tiny\color{black!50},
frame=single,
framerule=0.3pt,
rulecolor=\color{black!40},
tabsize=4,
}
% ---------- 常用数学简写 ----------
\newcommand{\R}{\mathbb{R}}
\newcommand{\diff}{\,\mathrm{d}}
+261
View File
@@ -0,0 +1,261 @@
# 训练前端 Windows 兼容性与「暂停」审计(结论 + 修复方案)
> 审计对象:`src/mcm26b/training_ui/`、`src/mcm26b/process_control.py`、
> `scripts/train_hrl_high.py`。
> 触发问题:「无法暂停」「频繁出现 os 无 killpg 等」。
> 结论一句话:**这两个现象同源——训练前端的停止/暂停路径是纯 POSIX 设计;
> Windows 上 `os.killpg` 根本不存在,异常又没被兜住,所以点了停止等于没点。**
---
## 0. 结论摘要
| # | 现象 | 根因 | 严重度 |
| --- | --- | --- | --- |
| 1 | 点「停止训练」返回 500 / 无效果,训练照跑,于是「无法暂停」 | `TrainingJob.stop()` 直接调用 `os.killpg(os.getpgid(...))`;这两个符号**只存在于 POSIX**,Windows 上抛 `AttributeError`,而旧 `except` 只接 `ProcessLookupError/PermissionError` | 阻断 |
| 2 | 控制台/日志反复出现 `module 'os' has no attribute 'killpg'` | 同上:错误最终落到 `_UIHandler.do_POST` 的兜底 `except Exception`,返回 500 并带出 `AttributeError` 文本;每点一次复现一次 | 阻断 |
| 3 | 即使把 killpg 换成 `terminate()`,停止后模型/元数据仍然丢失(Windows 上) | Windows 的 `os.kill(pid, SIGTERM)` 语义是 `TerminateProcess` **硬杀**,训练脚本里"收到信号后在 step 边界保存"的处理器不会执行 | 高 |
| 4 | 界面根本没有「暂停」能力(POSIX 也没有) | 原设计只有 start/stop;且 `SIGSTOP/SIGCONT` 在 Windows 上不存在,**原生暂停在 Windows 上无法实现**,必须改成协作式 | 高 |
| 5 | 子进程进程组隔离在 Windows 上失效 | `Popen(start_new_session=True)` 在 Windows 被**静默忽略**(CPython 的 Windows `_execute_child` 形参名就是 `unused_start_new_session`) | 中 |
| 6 | subproc worker 在 Windows 下可能抢在主进程收尾前退出 | worker 只忽略 `SIGTERM/SIGINT`,没处理 Windows 的 `SIGBREAK`(`CTRL_BREAK_EVENT` 的落点) | 中 |
**修复原则**:把"暂停/继续/停止"从**信号语义**改成**控制文件语义**。
控制文件在 POSIX 与 Windows 上都只是普通文件 IO,行为完全一致;信号与强杀退居
兜底。这样 Windows 上暂停、继续、优雅停止、落盘保证全部成立。
---
## 1. 失败链复现(旧代码)
```
用户点「停止训练」
└─ POST /api/train/stop
└─ TrainingUI.stop() → TrainingJob.stop()
└─ os.killpg(os.getpgid(process.pid), signal.SIGTERM)
├─ POSIX :成功,进程组收到 SIGTERM,脚本优雅收尾
└─ Windows:AttributeError: module 'os' has no attribute 'killpg'
↑ 只 except (ProcessLookupError, PermissionError),接不住
└─ _UIHandler.do_POST 兜底 except Exception → HTTP 500
└─ 训练子进程完全没收到任何指令,继续跑 → 「无法暂停 / 停止没反应」
```
关键代码(修复前,`src/mcm26b/training_ui/server.py`):
```python
def stop(self) -> bool:
with self._lock:
process = self.process
if process is None or process.poll() is not None:
return False
try:
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
except (ProcessLookupError, PermissionError):
process.terminate()
self.status = "stopping"
return True
```
---
## 2. 根因逐条(含证据)
### 2.1 `os.killpg` / `os.getpgid` 是 POSIX-only
CPython 只在 `posix` 构建里注册这两个函数;Windows 的 `os` 模块没有它们。
访问会得到 `AttributeError`(不是 `OSError` 子类),所以旧 `except` 接不住。
### 2.2 `start_new_session=True` 在 Windows 被静默忽略
`subprocess.Popen` 接受该参数,但 Windows 的 `_execute_child` 形参名是
`unused_start_new_session`,也就是**根本不读**。要隔离进程组,Windows 必须传
`creationflags=CREATE_NEW_PROCESS_GROUP`。
### 2.3 Windows 的 `SIGTERM` 是硬杀
`os.kill(pid, sig)` 在 Windows 上只有 `CTRL_C_EVENT` / `CTRL_BREAK_EVENT` 是
"软"信号;**任何其它值**(含 `SIGTERM`)都会走 `TerminateProcess`。因此
`scripts/train_hrl_high.py` 里的:
```python
for _signum in (signal.SIGTERM, signal.SIGINT): # 旧代码
signal.signal(_signum, _on_stop_signal)
```
在 Windows 上形同虚设——处理器注册了,但没人会用它。这也解释了为什么"停止后
模型没保存"。
### 2.4 Windows 没有 `SIGSTOP`,暂停无法用信号实现
暂停(挂起/继续)在 POSIX 上可以用 `SIGSTOP/SIGCONT`,但 Windows 既无这两个
信号,也无等价的"无侵入挂起"用户态 API(真正的挂起要 `SuspendThread`/调试 API)。
所以**任何跨平台暂停都必须是协作式的**:由训练进程自己在 step 边界检查标志并
让出执行。本项目原先没有这条通道,界面也没有暂停按钮。
### 2.5 `SIGBREAK` 未处理
Windows 的 `CTRL_BREAK_EVENT`(发给进程组的软信号)在 Python 里落到
`signal.SIGBREAK`。旧的 handler 安装与 worker 屏蔽列表都只含
`SIGTERM/SIGINT`,Windows 下等于裸奔。
### 2.6 异常类型没兜住
`except (ProcessLookupError, PermissionError)` 漏掉 `AttributeError`、以及
更一般的 `OSError`;`_hard_kill` 里 `signal.SIGKILL` 在 Windows 上也不存在
(`getattr(signal, "SIGKILL", None) is None`),同样会 `AttributeError`。
---
## 3. 修复方案(已实施)
### 3.1 新增 `src/mcm26b/process_control.py`(零第三方依赖)
| 能力 | 实现 | 作用 |
| --- | --- | --- |
| 子进程隔离 | `spawn_kwargs()`:POSIX `start_new_session=True`;Windows `creationflags=CREATE_NEW_PROCESS_GROUP` | 前端 Ctrl+C 不误伤训练;Windows 也能组杀进程树 |
| 控制协议读写 | `write_control()` / `read_control()`:JSON + 同目录临时文件 + `os.replace` 原子替换;损坏/缺失一律视为"无指令" | 两端统一的暂停/停止通道 |
| 强杀兜底 | `terminate_process_tree(process, grace_s)`:先等宽限期;超时后 POSIX 走 `killpg(SIGKILL)`、Windows 走 `taskkill /F /T /PID`;所有 POSIX 符号用 `getattr` 探测 | 彻底移除 `os.killpg` 无条件调用;返回"是否动用了强杀" |
`IS_WINDOWS` 是运行期常量而非导入期分支,便于测试直接 monkeypatch 模拟 Windows。
### 3.2 控制文件协议
路径由前端生成并随命令下发:`--control-file <abs>`(默认落在
`output/hrl/ui/control/<job_id>.control.json`,`output/` 已 gitignore)。
```json
{"paused": false, "stop": false, "seq": 1712345678901234567, "ts": 1712345678.9}
```
- 前端**只写**:`pause()` → `paused=true`;`resume()` → `paused=false`;
`stop()` → `stop=true`(同时清零 paused,保证阻塞中的暂停循环能被唤醒)。
- 训练脚本**只读**:`_ControlPoll` 每 32 个 step 抽样读一次盘(避免每 step 一次
文件 IO);暂停时在 `_on_step` 内阻塞轮询(`poll_s=0.2`),进程存活、显存仍占用,
但不消耗算力。
- 墙钟上限 `--max-wall-s` **扣除累计暂停时长**,避免"挂起一小时回来直接判超时"。
### 3.3 训练脚本 `scripts/train_hrl_high.py`
- 新增 `--control-file`;`_ControlPoll`(纯标准库、可单测)+ 薄薄的
`_ControlChannel(BaseCallback)` 接到 SB3 回调链**最前面**。
- 收尾信号集合扩为 `_stop_signals()`:POSIX `SIGTERM/SIGINT`;Windows 追加
`SIGBREAK`。worker 屏蔽同一集合,保证主进程 `vec_env.close()` 之前 worker 不先退。
- 落盘保证不变:停止后仍写最终模型 + 元数据,`stopped_by_signal=true`,
`stop_signal` 记 `control_file` 或信号名;异常仍落 `*_emergency.zip`。
### 3.4 训练前端 `server.py` / `static/`
- 新增 `POST /api/train/pause`、`POST /api/train/resume`;`stop` 语义改为
"写控制文件 → 宽限期内自行退出;超时强杀",强杀在**独立看门狗线程**里做,
HTTP 请求不会被 15s 等待卡住。
- 状态机新增 `paused`;`_sync_control_events()` 用训练脚本回显的
`paused/resumed/stop_requested` 事件校正状态。
- 快照新增 `forced_kill`,前端横幅区分"优雅停止"与"超时强杀"。
- 前端新增「暂停训练 / 继续训练」按钮、暂停横幅;停止确认文案更新。
### 3.5 停止/暂停时序
```
pause: UI 写 {paused:true} ──► 脚本 _on_step 读到 ──► 回显 paused,阻塞轮询
resume: UI 写 {paused:false} ─► 暂停循环退出 ────────► 回显 resumed,继续训练
stop: UI 写 {stop:true} ────► 脚本 step 边界收尾落盘 ──► 退出码 0
│
└─(宽限 15s 未退)─► terminate_process_tree 强杀;forced_kill=true
```
### 3.6 急停(强杀)也必须可恢复
宽限期一到就强杀,训练脚本**没有任何 Python 收尾机会**——不写最终模型、不写
元数据、不写 `training_failure.json`。如果磁盘上只有 `--checkpoint-every` 的稀疏
历史 checkpoint,急停就可能丢掉上万步,或者在"保存途中被杀"时留下一个打不开的
半截 zip。为此加了四条保证:
| 保证 | 实现 | 效果 |
| --- | --- | --- |
| 起步基线 | `recovery_every > 0` 时,`learn()` 之前先写一份 `<stem>_latest.zip` | 训练刚起就急停,也有可加载、可 `--resume` 的产物 |
| 滚动恢复点 | 每 `--recovery-every`(默认 2000)环境步覆盖写同一份 `<stem>_latest.zip` | 急停最多丢 `recovery_every` 步,而不是 `checkpoint-every` 步 |
| 原子落盘 | 模型 zip / 旁挂 json / `resume.json` 一律「同目录 `.tmp-` + `os.replace`」 | 保存途中被强杀,目标路径仍是上一份**完整**快照;不会出现半截文件 |
| 权威恢复指针 | 每次落盘刷新 `<run_dir>/resume.json`(model / timesteps / 增量语义 / 生效 PPO 超参);前端 `/api/train/state` 暴露为 `recovery` | 无论怎么停,都有一份明确的"从哪继续";界面一键「用最近检查点续训」 |
前端在强杀后还会补写 `<run_dir>/forced_stop.json`(`job_id`、`pid`、`reason`、
`recovery.model`),因为此时训练脚本已经无法记录任何事情。
---
## 4. 平台兼容性矩阵(修复后)
| 能力 | POSIX | Windows |
| --- | --- | --- |
| 启动子进程并隔离 | `start_new_session=True`(setsid) | `CREATE_NEW_PROCESS_GROUP` |
| 暂停 / 继续 | 控制文件(协作式) | 控制文件(协作式) |
| 优雅停止 + 落盘 | 控制文件;`SIGTERM` 亦可 | 控制文件;`CTRL_BREAK_EVENT`→`SIGBREAK` 亦可 |
| 超时强杀进程树 | `killpg(SIGKILL)` | `taskkill /F /T /PID` |
| `os.killpg` 依赖 | 有 | **无(不再调用)** |
| 暂停期间是否算墙钟 | 否(扣除) | 否(扣除) |
---
## 5. 验证
- 新增/更新回归测试:
- `tests/test_training_ui.py`:控制文件协议往返与损坏容错、`spawn_kwargs`
平台分支、Windows 强杀走 `taskkill`、**无 `killpg` 环境下强杀不抛异常**
(直接复现旧 bug)、暂停/继续/停止全链路、控制文件被忽略时强杀并写
`forced_stop.json` 恢复指引、`discover_recovery` 的
`resume.json`/扫描/悬空指针三分支、HTTP `pause/resume` 端到端。
- `tests/test_hrl_checkpoint.py`:控制文件状态机单测;原子保存失败不破坏上一份
快照;JSON 原子替换;历史清理不误删滚动恢复点;起步基线可加载;
**强杀急停后 `resume.json` + 滚动恢复点仍可 `--resume`**;控制文件停止后
模型/元数据落盘(`stop_signal=control_file`)与暂停→继续;POSIX 信号路径
单列并加平台跳过。以上集成用例都用**真实训练脚本**跑 subproc。
- 手工验证:`--recovery-every 32` 短程实跑后强杀,`resume.json` 指向
`q3_ckpt_latest.zip`;以它为 `--resume` 目标再跑 32 步,元数据
`actual_timesteps` 从 64 变 96、`timesteps_semantics=additional`。
- 全量测试:`pytest tests referee/tests` 全绿。
- 全仓库 `pylint src scripts project tests referee main.py` 达到 10.00/10
(口径见 §7)。
---
## 6. 残余风险与后续建议
1. **暂停粒度** = `poll_every` 个 env step(默认 32,约 0.1–3s 量级),不是即时;
若要更快可调小 `_ControlChannel(poll_every=...)`,代价是更频繁的文件 stat。
2. **宽限期固定 15s**(`server.STOP_GRACE_S`)。大模型保存可能更久;但因为落盘是
原子的,即使宽限期到点被强杀,也只是"新的最终模型没写成",**上一份滚动恢复点
与历史 checkpoint 完好**,不会出现半截文件。需要更长可调大该常量。
3. **急停的损失上界 = `--recovery-every`**(默认 2000 环境步)。要更小就调小它;
调到 0 表示放弃滚动恢复点(此时只剩 `--checkpoint-every` 的稀疏历史
checkpoint 与起步基线)。
4. **Windows 强杀依赖 `taskkill`**(系统自带)。若被安全策略禁用,会退回
`Popen.kill()`(只杀主进程,spawn 的 worker 可能残留)。
5. 更严格的 Windows 方案是 **Job Object**(子进程随 job 句柄一起销毁),但需要
`ctypes`/`pywin32`,本仓库基础依赖刻意保持轻量,未引入。
6. **前端进程重启后**,内存中的任务对象没了,「用最近检查点续训」按钮不会自动
出现;但恢复信息都落在磁盘上(`<run_dir>/resume.json`、`forced_stop.json`、
`checkpoints/<stem>_latest.zip`),在表单里填同一个模型输出路径并勾选
`--resume` 即可继续。
7. 界面 `--device mps` 选项在 Windows 上无意义;`auto` 会回退 cuda/cpu,属既有
行为,未改。
8. `_ControlPoll` 的暂停循环会占用一个 Python 线程的调度(每 0.2s 一次读盘),
长暂停期间 CPU 占用可忽略。
---
## 7. pylint 口径说明
配置写在 `pyproject.toml` 的 `[tool.pylint.*]`,目标是
`pylint src scripts project tests referee main.py` = 10.00/10。
**改代码修掉的真实问题**(不是 disable):未使用的 import/变量/参数、重复字典键
(`reward_version`)、`value != value` 判 NaN、`__dataclass_fields__` 私有访问、
`raise` 非异常类型、`pytest.importorskip` 之外的赋值不确定、过长行、无谓括号、
`len(x)` 判空、循环闭包变量、`subprocess.run` 未显式 `check`、`os.path` 循环导入等。
**有意 disable 的类别**(每条在 pyproject 里写了理由):项目刻意的懒加载
(`import-outside-toplevel`)、防御式宽异常(`broad-exception-caught`)、测试访问
内部状态(`protected-access`)、pytest fixture 同名(`redefined-outer-name`)、
无头环境不实现 `gym.Env.render`(`abstract-method`)、以及静态分析的已知误报
(`possibly-used-before-assignment`)。
**注意**:`good-names` 不覆盖 `redefined-builtin`,stdlib 回调签名里的
`log_message(self, format, ...)` 只能在对应 `def` 上行内 disable。
+160
View File
@@ -0,0 +1,160 @@
# 模型训练前端(training-ui)
本地回环 Web UI,用于**实时观察一次 HRL 高层 PPO 训练**:子进程状态、步进进度、
参数收敛曲线、逐回合记录与完整 stdout 日志。设计与评测前端(`referee/` WebUI)
同构——同一套暗色面板语言、同一个「只监听 127.0.0.1 + 静态白名单 + JSON 轮询
API」模式——差别在于本页托管的是一个**训练子进程**而不是评测会话。
## 启动
```bash
uv run python -m mcm26b.training_ui --ui-port 8036 # 打开 http://127.0.0.1:8036
uv run python scripts/train_hrl_ui.py --ui-port 8036 # 等价薄入口(支撑材料命令)
uv run python -m mcm26b.training_ui --print-schema # 只看配置契约,不起服务
uv run python -m mcm26b.training_ui --print-preview # 只看离线示例快照
```
`--no-browser` 阻止自动打开浏览器;Ctrl+C 退出时会先停止训练子进程。
无训练进程时,界面顶栏「离线预览」可渲染三组合成快照(上升 / 平台期 / KL 过猛),
用于检查曲线、指标卡、时间线与日志着色——预览不启动任何进程、不写任何文件。
## 界面结构
| 区块 | 内容 |
| --- | --- |
| 顶栏 | 任务摘要、进程/进度/墙钟/设备/连接五个状态 chip、刷新·预览·暂停/继续·停止 |
| 执行进度与进程 | 步进进度条、剩余时间与预计结束、PID/吞吐/退出码、PPO 阶段时间线、完整命令行 |
| 训练配置 | 由 `/api/train/schema` 生成的五组表单 + 四个预设,运行中锁定 |
| 参数收敛状态 | 判读 chip + 判据说明,每个指标一张卡片(最新值、增量、迷你趋势线、异常高亮) |
| 曲线 | 主指标(平均回合奖励)+ 可切换诊断量,悬停十字线读数、KL=0.05 等参考线 |
| 实时运行日志 | 关键字过滤、错误/进度 JSON 开关、自动跟随、最近 4000 行 |
| 逐回合记录 | Monitor CSV 的每回合奖励/长度/时刻 |
## 数据来源与契约
三个端点都在 `src/mcm26b/training_ui/server.py`:
| 端点 | 说明 |
| --- | --- |
| `GET /api/train/schema` | 字段/分组/预设/指标字典,**与 `TrainConfig` 同源**(`schema.py`) |
| `GET /api/train/state` | 快照;支持 `log_tail`、`metric_limit`、`after_metric` 游标与 `preview=1` |
| `POST /api/train/start` | 允许只提交部分字段(其余取默认值),校验失败返回 409 |
| `POST /api/train/pause` | 写控制文件请求在 step 边界挂起(跨平台) |
| `POST /api/train/resume` | 解除挂起,从暂停处继续 |
| `POST /api/train/stop` | 请求优雅停止;宽限期(`STOP_GRACE_S`,默认 15s)后强杀进程树 |
暂停/停止走**控制文件**而不是信号,原因与平台差异见
[`training-ui-windows-audit.md`](training-ui-windows-audit.md):Windows 没有
`SIGSTOP`,且 `os.kill(pid, SIGTERM)` 会退化成 `TerminateProcess` 硬杀,训练脚本
"保存模型再退出"的收尾分支不会执行。控制文件在 POSIX 与 Windows 上都只是普通
文件 IO,语义完全一致;信号(POSIX `SIGTERM/SIGINT`、Windows `SIGBREAK`)只作兜底。
进度数据的两个来源,服务端都已解析:
1. **progress JSON**(主来源):`train_hrl_high.py --progress-json` 每若干环境步打印
一行 `{"event": "progress", "timesteps": ..., "ep_rew_mean": ...}`,字段最全;
热身阶段间隔会自动缩小,短程 smoke 也能看到完整曲线。
2. **SB3 verbose 表格**(补充来源):解析 `| key | value |` 表格,用于补
`clip_fraction`/`learning_rate` 等诊断量。表格按段分组缓存、等本表的
`total_timesteps` 到位后统一打横轴刻度;与 JSON 同一步数的表格版本会被跳过,
避免重复点。
`timesteps` 是整个前端的横轴:服务端不伪造刻度(缺刻度的表宁可丢弃,截断的表
按末尾已知刻度兜底并在收尾提交),前端不再自行编号。
## 收敛判读口径
`summarize_convergence()` 只做**可解释的启发式判读**,不替代正式学习曲线分析:
| 状态 | 触发条件 |
| --- | --- |
| 等待首个 rollout | 尚无任何指标 |
| 预热阶段 | 进度点 < 3,无法判断趋势 |
| KL 偏大,策略更新可能过猛 | 最近 `approx_kl` > 0.05(判定优先级最高) |
| 价值函数尚未拟合 | 最近 `explained_variance` < 0 |
| 奖励未形成上升趋势 | 最近窗口奖励斜率为负 |
| 已趋于平稳(疑似收敛) | 窗口对半位移 ≤ 逐点噪声、变异系数 ≤ 0.15、极差 ≤ 15% 量级 |
| 收敛趋势良好 | 其余(斜率正向) |
平台判据特意用「对半窗口位移 / 逐点噪声」而不是单看斜率绝对值:慢速但持续的
提升(斜率很小)不会被误判成收敛。所有判据数字都会写进 `notes`,便于人工复核。
## 安全边界
- 只监听 `127.0.0.1`;静态资源是固定白名单,不提供目录遍历。
- 命令由服务端以**参数列表**构造,不经过 shell;字符串参数只拒绝控制字符。
- 同一时刻只允许一个训练任务;暂停中的任务仍算「在跑」,必须先停止才能开新一局。
- 暂停/停止走控制文件(`--control-file`,默认 `output/hrl/ui/control/<job_id>.control.json`),
进程组隔离按平台选择(POSIX `setsid` / Windows `CREATE_NEW_PROCESS_GROUP`),
超时强杀按平台选择(POSIX `killpg(SIGKILL)` / Windows `taskkill /F /T`)。
- 产物路径限定在仓库根下解析,模型输出沿用训练脚本自身的 `--force`/`--resume`
语义(两者互斥,由后端校验)。
## 暂停、停止与落盘保证
「暂停」是**协作式**的:前端原子写控制文件,`train_hrl_high.py` 的
`_ControlPoll` 每 32 个环境步抽样读一次;暂停时训练阻塞在 `_on_step` 的轮询里,
进程与显存保留、不消耗算力,点「继续」从同一个 step 边界恢复。暂停时长不计入
`--max-wall-s`(否则"挂起一小时回来直接判超时")。
「停止」同样是控制文件请求(**跨平台**)。`train_hrl_high.py` 有多层兜底,
点一下「停止」不再等于这一局白跑;而**急停**(强杀,例如 `SIGKILL` /
`taskkill /F`,进程没有任何收尾机会)也保证可恢复:
| 机制 | 行为 |
| --- | --- |
| 滚动恢复点 | `--recovery-every`(默认 2000 环境步)把 `<checkpoints>/<stem>_latest.zip` **原子覆盖写**一次;训练开始前先写一份**起步基线**。因此急停后最多只丢 `--recovery-every` 个环境步,且磁盘上始终有一份完整、可加载、可 `--resume` 的产物 |
| 原子落盘 | 模型 zip、旁挂 json、`resume.json` 都是「同目录临时文件 + `os.replace`」:保存途中被强杀不会留下半截文件,也不会破坏上一份完整快照 |
| 恢复指针 | `<run_dir>/resume.json` 记录当前最佳恢复目标 + 步数(增量语义)+ 生效过的 PPO 超参;前端顶部的「用最近检查点续训」按钮直接读它 |
| 定期 checkpoint | `--checkpoint-every`(默认 20000 环境步)另留 `<stem>_<步数>.zip`,`--checkpoint-keep` 只保留最近 K 个(默认 3),供返祖对比与多档恢复;滚动恢复点与起步基线不受清理影响 |
| 优雅停止 | 控制文件 `stop=true`(或 POSIX 信号 / Windows `SIGBREAK`)后,主进程在 step 边界收尾,保存最终模型与元数据(`stopped_by_signal=true`、`stop_signal`、`checkpoint_files`、`recovery_model`)并正常关闭环境 |
| 超时强杀 | 宽限期(`STOP_GRACE_S`,默认 15s)内没退出则强杀整棵进程树,快照 `forced_kill=true`,并在 `<run_dir>/forced_stop.json` 写明 `recovery.model`(可直接续训的目标) |
| 异常兜底 | `learn()` 抛出任何异常时先落 `*_emergency.zip` + 元数据 + `resume.json`,再写 `training_failure.json` 并抛出 |
急停后恢复的操作方式:界面点「用最近检查点续训」;命令行则
`--resume --model <resume.json 里的 model>`,`--timesteps` 按**追加**步数理解。
checkpoint 与最终模型共用同一份 json 契约,因此 `--resume <checkpoint.zip>` 直接
续训(`--timesteps` 为增量步数)。注意 `--resume`/`--init` 会沿用 checkpoint 内的
PPO 超参(`n_steps`/`batch_size`/`n_epochs`):命令行这三项被忽略,脚本会打一条
`hyperparams_from_checkpoint` 事件说明差异,元数据 `ppo_hyperparams` 记录**实际生效**值。
回归测试见 `tests/test_hrl_checkpoint.py`,其中端到端用例真起 subproc 子进程,覆盖
控制文件停止、POSIX 信号停止、**强杀后仍可续训**与暂停→继续(信号路径在 Windows
上自动跳过)。
## 测试
```bash
.venv/bin/python -m pytest tests/test_training_ui.py tests/test_training_ui_js.py tests/test_hrl_checkpoint.py -q
```
- `tests/test_training_ui.py`:配置契约同源、预设可直接提交、参数校验、SB3 表格
刻度打点、游标分页、`describe_process` 进度/ETA、示例快照与真实快照同键;
用**桩训练脚本真起子进程**覆盖启动/轮询/暂停/继续/停止/退出码全链路;并覆盖
跨平台进程控制——控制文件往返与损坏容错、`spawn_kwargs` 平台分支、Windows 走
`taskkill`、**无 `killpg` 环境下强杀不抛异常**(旧 bug 的直接回归)、控制文件被
忽略时强杀并写 `forced_stop.json` 恢复指引、`discover_recovery` 的
`resume.json`/扫描/悬空指针三分支、HTTP `pause/resume`。
- `tests/js/training_ui_harness.cjs`(经 `tests/test_training_ui_js.py` 调起):
DOM 桩加载发布的 `charts.js`/`app.js` 原文,用服务端生成的真实快照驱动渲染,
断言表单/指标卡/曲线/日志/逐回合表都拿到数据,覆盖增量游标三条分支与
`classList`、HTML 转义、极端数值等边界。
- `tests/test_hrl_checkpoint.py`:落盘与恢复的端到端回归——原子保存失败不破坏
上一份快照、JSON 原子替换、历史清理不误删滚动恢复点、起步基线可加载、
**强杀急停后 `resume.json` 与滚动恢复点仍可继续训练**、控制文件停止落盘、
暂停→继续、POSIX 信号停止。
## 已知取舍
- 进度点保留上限 5000(服务端 deque 与前端本地缓存同值),超长训练只保留最近一段。
- 表格解析依赖 SB3 的段名(`rollout/`/`time/`/`train/`/`system/`);SB3 若改表格
格式,退化路径是「只显示 progress JSON」,不会导致界面崩溃。
- 收敛判读是启发式;正式结论仍需用 `scripts/benchmark_hrl.py` 的配对评测与
学习曲线人工复核。
- 暂停粒度是 `poll_every` 个环境步(默认 32),不是即时挂起;停止宽限期默认 15s。
- Windows 强杀依赖系统自带的 `taskkill`;若被策略禁用会退回 `Popen.kill()`
(只杀主进程)。更严格的 Job Object 方案需要额外依赖,未引入。
Windows 兼容性问题的完整根因与修复记录见
[`training-ui-windows-audit.md`](training-ui-windows-audit.md)。
+215
View File
@@ -0,0 +1,215 @@
# 协议规则表、字段表与状态机(P0 交付)
依据:`issue/附件/附件1.docx`《模拟器使用说明》、`issue/附件/附件2.docx`《模拟器通信接口说明及编程指南》。
本文是人类可读版本;**可执行版本**是 `src/mcm26b/protocol/rules.py`(字段表与错误语义)、
`src/mcm26b/protocol/timing.py`(计时模型)与 `src/mcm26b/config.py`(全部常量),
三者由 `tests/test_protocol_timing.py`、`tests/test_protocol_client.py` 固化验收。
## 1. 动作与耗时规则表
| 动作 | 指令 | 虚拟耗时 | 说明 |
| --- | --- | --- | --- |
| 开始 | `POST /enter` | 0 | 初始位置 (0,0),初始频道 1;虚拟/程序时钟开始 |
| 检测 | `POST /measure` | 5 + 移动 + 换频道 | 无论结果(no_signal/near/direction)均为 5s |
| 清除 | `POST /clear` | 未发现 3 / 成功 5 + 移动 | 5 = 光学定位 3 + 激光清除 2;**不切换测向频道** |
| 结束 | `POST /exit` | 0 | 成功响应中 exit_reason 固定 `user_exit` |
| 切换频道 | 无独立指令 | 1 | 只由合法 `/measure` 的 channel 变化推断 |
| 移动 | 无独立指令 | 直线距离/5(m/s) | 由 `/measure` 或 `/clear` 的 position 推断 |
派生事实(易错点):
- 一次合法 `/measure` 完成后,测向机频道更新为本次检测频道;
- `/clear` 的 channel 只是目标频道,既不切频道、也不产生切换耗时,因此
"清除后原地再测"的耗时只取决于上一次 **/measure** 的频道;
- 只有 accepted=true 的请求推进虚拟时钟;`accepted=false` 的 virtual_time_s=0 不是当前时刻;
- 5 秒检测只是虚拟耗时,不要求现实等待。
## 2. 字段表
公共请求字段(4 条指令都必填):
| 字段 | 类型 | 约束 |
| --- | --- | --- |
| arena_id | string | 必须为 `"default"` |
| robot_id | string | 逐字节等于登录参赛队号;UTF-8 长度 1..64;无控制字符 |
| request_id | string | 会话内幂等键;UTF-8 长度 1..128;无控制字符 |
动作字段(实现见 `rules.ACTION_FIELDS`):
| 指令 | 字段 | 约束 |
| --- | --- | --- |
| /enter | (无附加) | |
| /measure | position{x,y}, channel | x/y 有限数值且 \|v\|<=2,000,000;channel 整数 1..20(1.0 亦接受,1.5 拒绝) |
| /clear | position{x,y}, channel | 同上;channel 是目标频道 |
| /exit | (无附加) | |
响应字段:
| 场景 | 字段 |
| --- | --- |
| 所有响应 | accepted, real_timestamp_ms, virtual_time_s |
| accepted=false | 仅上述 3 个字段(virtual_time_s=0) |
| /enter 成功 | + max_virtual_duration_s, max_real_duration_s, remaining_real_duration_s |
| /measure 成功 | + measure_result ∈ {no_signal, near, direction};direction 时另有 svd_deg(保留两位小数) |
| /clear 成功 | + clear_result ∈ {success, no_target_in_range} |
| /exit 成功 | + exit_reason = "user_exit" |
错误语义(必须同时检查 HTTP 状态与 accepted):
| 情形 | 结果 | 对 request_id 的影响 |
| --- | --- | --- |
| JSON 语法/重复键/缺字段/类型/坐标频道范围 | HTTP 400 | 不占用,修正后可复用 |
| 未知字段(含 position 下)、arena/robot 不匹配、测试状态拒绝 | HTTP 200, accepted=false | 不占用 |
| 动作被接受 | HTTP 200, accepted=true | 占用 |
| 同 ID 不同内容,或并发不同动作 | HTTP 409 | — |
| 网络失败重试同一动作 | 复用原 ID+原内容,服务器回放首次响应 | 不重复生效 |
| 429/500 | 可原样重试 | — |
| 404/405/413/415 | 确定性错误,不得重试 | — |
物理规则速查:Ω 半径 1800m;源数 10–16;频道 1–20;接收半径 [1000,1500]m(逐源未知);
near 阈值 5m;清除半径 20m(与定向朝向无关);定向覆盖 = 朝向两侧各 90°(含边界);
示向度误差幅度 ±1°,保留两位小数;虚拟限时 360000s;程序限时 1200s(以 /enter 的
remaining_real_duration_s 为准,不得假定恒为 1200);测试窗口 25 分钟。
## 3. 状态机
机器狗会话状态(`protocol.state.RobotState` + 客户端会话标志):
```
/enter accepted /exit accepted
[未进入] ───────────────▶ [已进入] ───────────────▶ [已退出]
│ accepted=false │ accepted=false │ 任何动作 accepted=false
└── 不变 └── 不变 └── 不变
```
[已进入] 状态内跟踪:position、测向机 channel、virtual_time_s。转移规则:
| 事件 | position | channel | virtual_time_s |
| --- | --- | --- | --- |
| /enter accepted | (0,0) | 1 | 0 |
| /measure accepted | ← 本次 position | ← 本次 channel | ← 响应值(=旧值+移动+切换+5) |
| /clear accepted | ← 本次 position | **不变** | ← 响应值(=旧值+移动+3或5) |
| /exit accepted | 不变 | 不变 | ← 响应值 |
| accepted=false / 网络 / 400 | 不变 | 不变 | 不变 |
虚拟时刻以最近一次 accepted=true 的响应为准;本地预测(timing 模块)只用于
规划与一致性核对,偏差记入 `RobotState.mismatches` 并写日志(strict 模式抛错)。
## 4. 计时示例逐步推演(附件1表2 = 附件2第10节)
| 步 | 指令 | 移动 | 换频道 | 动作 | 本步 | 累计 |
| --- | --- | --- | --- | --- | --- | --- |
| 1 | /enter | 0 | 0 | 0 | 0 | **0** |
| 2 | /measure (300,400) ch1 | 500m→100s | 0(初始即1) | 5 | 105 | **105** |
| 3 | /measure (300,400) ch2 | 0 | 1 | 5 | 6 | **111** |
| 4 | /clear (300,0) 目标ch3 | 400m→80s | 0(clear不切频道) | 3(未发现) | 83 | **194** |
| 5 | /measure (300,0) ch2 | 0 | 0(第3步后已是2,clear未改) | 5 | 5 | **199** |
| 6 | /exit | 0 | 0 | 0 | 0 | **199** |
验收:`uv run mcm26b sim-check` 通过完整客户端→本地模拟器链路复现
`[105, 111, 194, 199]`;`tests/test_protocol_timing.py::TimingModelTests`
逐步断言每个分项。
## 5. 客户端设计要点(P1 交付)
- **串行**:完全同步,一个动作未决不发下一个;
- **幂等重试**:请求体一次性序列化为 bytes,网络失败/429/500 时原样重发
(同 request_id 同内容),最多 `max_attempts` 次,指数退避;400/404/405/409/413/415 立即失败;
- **accepted=false**:抛 `ActionRejected`,状态不更新;virtual_time_s=0 不入时钟;
- **现实预算**:/enter 成功后 `deadline = monotonic() + remaining_real_duration_s`;
新动作前检查 `剩余 > reserve_exit_s`(默认 60s [工程]),/exit 豁免;
- **日志**:`SessionLog` 逐事件追加 JSONL(attempt/transport_error/accepted),
进程崩溃不丢已发记录,回放测试与 evaluation 复算共用同一格式;
- **本地预校验**:channel 范围、坐标有限性与 2e6 上限、robot_id/request_id 格式
在发送前拒绝(与服务器 400 语义一致,省一次往返)。
## 6. 策略层如何使用本协议(P3/P4 交付)
第 5 节的客户端是策略层唯一的事实来源;`belief`(候选集)、`planner`(选点与闭环)
不绕开它直接发请求。衔接约定:
- **串行不变**:闭环每个决策步只发一个动作,`measure`/`clear` 的返回值
(`MeasureOutcome`/`ClearOutcome`)是 belief 更新的唯一输入;
- **状态同步**:机器人位置/测向频道/虚拟时刻一律读 `client.state`,
频道规则(§3 状态机表)由状态机自动维护,策略层不自行推算;
- **预算驱动退出**:`DeadlineExceeded` 只在 `/exit` 之外的动作前抛出;
闭环捕获后立即 `/exit`(豁免检查),并把该局记为"未证明完成",
不与全清成功混记;
- **选点的接收保证**:选点器只在保证接收盘 B(mec, 1000-ρ) 内取点,
盘内任一点到候选集每点距离 < 1000 ≤ 最小接收半径,因此定位阶段
不会浪费 `no_signal`(ρ>1000 的一般候选集退化为探索 MEC 圆心,允许
no_signal,理由字段中如实标注);
- **清除证书**:候选集外包多边形半径(含近似误差与工程余量)
≤ 20m 才发起 `/clear`;证书有效但清除失败视为异常,先补测再重试,
不在同一证书上重复消耗 3 秒/次的失败清除;
- **停止条件与完成判定**(2026-09-11 用户决策后):找全证明达成
(每频道均"已清除或覆盖证明不存在",或清除数达 16 数量上界)后
**不提前退出**:按 `search.persistent_search`(默认开)只复扫未清除
频道,直到清除数达 16、实机预算耗尽或虚拟安全余量
(`virtual_reserve_s`,防触及附件2 §4.5 的 100 小时上限;
本地模拟器对达限后的动作以 accepted=false 兜底)不足——"扫到限时为止"。
summary 中 `completed` 表示任务证明完成(无中断且结束时每频道
CLEARED/ABSENT,或 16 清除);`accounted_virtual_time_s` 记录首次
证明找全的虚拟时刻(计算"平均定位清除时间"建议用它,而非复扫
耗尽后的最终时刻);`stop_reason` 记录循环结束原因。发现若干源、
连续 no_signal、候选采样为空都不是停止条件;
- **每步计时留痕**(同上决策):客户端每个被接受动作写一条 `step`
事件(实机墙钟耗时 `real_elapsed_s`/`real_since_enter_s` + 比赛虚拟
耗时分项 `virtual_cost`:移动=直线距离/5、切频道 1s、检测 5s、
清除成功 5s/未发现 3s),summary 以 `steps` 数组与 `step_totals`
汇总,并给出题面口径的 `avg_locate_clear_time_s`;
- **验收**:`tests/test_loop_q3.py` 在自建模拟器上覆盖 10/16/0 源、
近边界源、预算耗尽与故障注入;`uv run mcm26b run --robot-id <队号>
--self-test` 可离线复跑随机场景,正式模式去掉 `--self-test` 即对接
模拟器(日志用 `--log` 落盘,格式同 §5 JSONL)。
## 7. 定向扩展如何使用本协议(P5 交付)
问题4的定向源在**协议字段上与全向源完全不可区分**:`/measure` 仍只返回
no_signal/near/direction(direction 附 svd_deg),`/clear` 仍只看 20m 半径。
"该源是定向的"无法从报文读出,只能由观测推理。因此 §5/§6 的协议用法全部
照用,定向性只改变策略层的解释与决策:
- **发现阶段零改动**:49 点覆盖保证对定向源同样成立——源位于某网格单元
凸包内时,任意发射半平面(朝向 ±90°,含边界)必含至少一个顶点,且该
顶点距离 ≤ 700√2 ≈ 989.95 < 1000 ≤ 最小接收半径,覆盖阶段无需知道
源类型;
- **no_signal 联合约束基线**:定向源的 no_signal 约束的是"位置×半径×朝向"
联合假设,单独维护空间候选会被误删,基线**不据此删任何候选**
(`belief.update_measure` 对 no_signal 无操作);缺席证明仍只由完整覆盖
给出。唯一启用的推理:若 no_signal 发生在保证接收盘 B(mec, 1000-ρ) 内
(该盘内任一全向源必然可收),则只能由朝向遮挡解释 [观测推理]——该频道
记为"观测到定向",进入探点升级梯子:对 MEC 圆心取对跖方向复核(偏移
裁进保证接收盘),再绕 MEC、半径 = ρ 的圆环按 45° 步进探点。**几何边界
必须如实陈述**:环上可见弧没有下界——源可位于环上(|g−c| = ρ)且朝向
沿外切线,此时可见集退化为单个切点,固定步进环探可以全部漏过。梯子
只提高提前命中概率,不构成接收或命中保证;完备性完全由后备清除兜底。
被遮挡探点不消耗定位步数,单轮被遮挡探点(首次选点、对跖复核、环探
合计)达 `max_blocked_probes`(4 [工程])即转后备清除;
- **后备清除的协议用法**:定位停滞(候选集有界但未达 §6 清除证书)时,
对候选外包多边形构造 20m 有限圆盘覆盖(`fallback_clear_cells`:全局
半开网格索引、相交判定带正容差,格内任一点距某格心 ≤ 10√2 < 20m),
按"距机器人最近优先"逐格发 `/clear`(同频道、不同位置)——清除与朝向
无关 [题面],是定向源不依赖可见性的完备后备。两条预算硬门槛(任一
不满足即跳过并留痕,绝不盲扫):
- 格数上界:N ≤ `fallback_max_cells`(400 [工程]);外包框枚举先按
(⌈w/20⌉+2)(⌈h/20⌉+2) 做规模检查,宽候选集(如仅一次读数的 750m
截断角域,数千格)必须继续定位而非硬扫;
- 现实预算:N × `real_rtt_p95_s` + `reserve_exit_s` ≤ 剩余现实时间。
虚拟耗时上界 ≈ 移动 L/5 + 3N(全失败)或 3(N-1)+5(末次成功)。
后备 /clear 请求**计入总请求口径**:summary 的 `total_requests`
(measures+clears)与 `fallback_clear_attempts`(后备逐格尝试数)
如实上报——仅统计检测次数会明显低估现实耗时;
- **真源不误删**:no_signal、失败的 `/clear`(含后备逐格全失败)均不删
空间候选;后备全失败按守恒性破坏记异常(格心距格内任一点 < 20m,
理论上必命中);
- **停止条件与预算语义不变**:仍是清除数达 16、每频道均"已清除或覆盖
证明不存在"、现实预算耗尽(记未证明完成)三种;断连/协议错误/
守恒性破坏中断时同样尽力 /exit 并产出未完成 summary(`stop_reason`
记 `transport_failure`/`protocol_error`/`inconsistent_belief` 等,
附逐频道状态快照),不静默丢失会话;
- **验收**:`tests/test_loop_q4.py`(15 项:覆盖格无空洞与格线两侧保留、
退化多边形、格数上界公式;混合 10/16 源全清、朝向背离圆心的近边界源
不漏、批量种子回归;no_signal 不删候选;格数硬顶与预算跳过;后备
正路径命中与全失败异常留痕);`uv run mcm26b run --robot-id <队号>
--problem 4 --self-test` 可离线复跑混合场景(`--directional` 指定
定向源数),正式模式同 §6。
@@ -0,0 +1,165 @@
# 第三、四问强化学习适用性审核与改进
本轮审核第一版强化学习代码、专家数据、模型及官方演练归档,修复训练与部署不一致的问题,训练两个新的 Maskable PPO 模型,并用独立实现的本地 `referee` 完成同场景对照。所有新性能数字均为本地结果,没有启动新的官方演练。
结论:强化学习适合在现有几何算法内尝试“下一检测点”的排序,第四问比第三问更有收益空间。当前证据支持第四问的混合方案优于手写 `directional` 基线;尚不能证明新模型稳定优于旧 PPO。第三问没有稳定增益,应保留 `bayes` 默认策略。新模型作为实验版本显式加载,没有覆盖旧默认模型。
## 1. 题设和方法适用范围
附录2(3)的交会必须使用带误差的角域,不能把两条示向线的交点当作真值;同地重测不会提供新的独立误差样本。附录2(4)的单接收机逐频道检测,结合动作规则,须计入移动、5秒检测及实际1秒换频。第三问的全向假设允许用无信号排除接收圆盘;第四问的无信号还可能来自方向遮挡,不能沿用这一排除结论。题设及几何算法的完整审核见[算法审核与优化](算法审核与优化-20260911.md)。
当前 RL 实际只替换 `RLBayesLoop._select_point` 和 `RLDirectionalLoop._next_probe`。七站/49站覆盖、频道发现、全局任务调度、保守候选集、清除证书和第四问后备清除仍由原算法负责。因此,完整场景全清验证的是混合系统,不是神经网络独立获得了完备性证明。
401维输入概括几何、历史读数和60个候选点,但省略完整历史、候选多边形细节及位置—朝向联合约束,不能直接称为完整马尔可夫状态。局部单源训练也没有学习全场覆盖路线与多源调度。PPO可以作为这种压缩观测下的近似策略尝试,但其目标并不自动等于全场最短时间;评估必须使用独立完整场景。[SB3官方训练与评估建议](https://stable-baselines3.readthedocs.io/en/master/guide/rl_tips.html)也强调独立评估、多随机种子和状态信息完整性。
## 2. 确认的实现缺陷及修复
| 缺陷 | 证据和影响 | 已实施修复 |
| --- | --- | --- |
| 训练传入整个 `BeliefState`,部署传入 `ChannelBelief` | 同一状态的特征索引7、14、15、17、18不同;训练丢失测量次数、末次结果和方位信息 | `env._observe` 使用目标频道信念;测试逐位比较部署输入,并覆盖跨频道交接 |
| BC使用ReLU,接收权重的PPO使用Tanh | 仅复制线性权重无法保留函数。原始专家输入探针中,Q3的90.96%、Q4的67.42%出现不同argmax | BC改为Tanh;复制时检查完整前向输出,重新初始化critic;旧ReLU/旧特征检查点拒绝直接迁移 |
| BC按观测行随机拆分 | 同一episode的相关状态可能同时出现在训练和验证中,分类准确率不足以说明独立场景泛化 | 保存episode编号,按episode划分训练/验证 |
| 第四问训练遮挡状态与运行时不一致 | 训练只记录距离保证盘内的无信号,且获得新方向后未正确重置连续遮挡;后备清除触发轨迹偏离部署 | 所有连续无信号记录为探测序列,仅盘内无信号用于确认定向;正观测清空序列,统一4次遮挡/8次定位阈值 |
| 奖励鼓励首次遮挡等中间事件 | “获得遮挡证据”额外+2、半径收缩等奖励会改变实际时间目标;较高回报不一定更快 | 主要奖励改为实际虚拟耗时的负值,成功清除统一+20,失败/截断重罚;取消这些中间奖励,采用gamma=1 |
| 未屏蔽同地重测、重合候选和第三问盘外梯子点 | 浪费固定误差条件下的检测时间;旧文档“所有候选保证接收”不成立 | 训练/推理共用动作屏蔽,排除已测0.5m格位置、重复候选、越界点;第三问存在距离保证盘时排除盘外点 |
| 保证盘半径恰为0时动作数量可能改变 | 依赖去重后的候选生成器会破坏固定60动作接口 | 即使位置重合也保留编号,交由动作屏蔽处理 |
| 只校验401/60维度不能识别语义变化 | 接收机频道被目标频道替代;旧模型与新模型同形但输入含义不同 | 加入特征版本与算法元数据,v2使用实际接收机频道,旧版保留原输入语义;拒绝问题编号或屏蔽模型元数据不匹配 |
| 基准将 `completed` 当作全清 | 内部状态自洽不代表全部真实源已清除 | 用评测端真实频道集合对照成功清除集合,并检查真实频道没有被误判缺席、正常退出、异常及逐步计时;旧基准新增 `all_valid` 和失败退出码 |
| 官方审计没有严格对应问题与策略名称 | 第三问/第四问摘要可能交叉通过名称检查 | `verify_rl_practice.py` 分别要求 `rl` / `rl_q4` |
BC探针是对旧网络和“拷贝后换激活”的网络进行比较,并不是新模型错误率,也不是重新测得的BC验证准确率。旧报告38.9%/65.3%的分类准确率不能直接解释为已迁移PPO的模仿准确率。本轮训练的新模型均从随机初始化开始,未使用BC;BC修复通过前向一致性测试,未据此声称重新训练BC已经带来收益。
动作屏蔽采用官方 `MaskablePPO` 的 `action_masks` 接口,训练和确定性推理都传入相同规则。[SB3-Contrib官方文档](https://sb3-contrib.readthedocs.io/en/master/modules/ppo_mask.html)说明了这两处的用法。第四问仍允许探索盘外候选,距离保证不等于方向可见。退化到所有动作均被屏蔽时保留中心动作,由步数/预算边界处理,因此不能把本次零重复观测扩展为所有可能状态的严格保证。
正常成功episode的累计奖励为 `20 - 局部实际虚拟时间/100`;环境仍保留异常与失败处理,包括证书清除失败的额外惩罚。局部时间从首测与可选交接完成后开始,不能用训练报告中的局部均值替代整场成绩。第三问训练自动清除仍使用证书圆心,而完整 `BayesLoop` 可在证书范围内平移清除点;全局调度、预算与局部环境也有差异,完整闭环验证因此不可省略。
## 3. 训练和数据
第一版Q3为120000步随机初始化PPO;第一版Q4为BC初始化后40000步PPO。原专家数据分别为5141、14181条,原5场完整测试均值分别是Q3:3088.33/3124.76秒、Q4:14250.15/13230.20秒(手写/RL)。这些历史数字受旧环境和特征影响,不与本轮新课程的单源成功率直接比较。
修订课程保留首次有效测向,并加入35%的跨频道、跨位置交接,20%的区域边缘且最小接收半径场景。定向首测覆盖朝向±89.9°,更接近半平面边界。源位置、朝向、半径和逐点误差的抽样仍是自建分布,不是已知的官方生成分布;真值仅用于布设和评测,不进入策略观测或动作屏蔽。
两模型使用 `[128,128]` Tanh MLP、2个内存环境、`n_steps=512`、`batch_size=128`、6轮更新、学习率0.0003。实际均完成60416步,来自完整rollout批次向上取整;元数据中的60000是请求步数。安装版本为SB3 2.9.0、SB3-Contrib 2.9.0、Torch 2.11.0+cu128。本次选择CPU、单Torch线程,机器CUDA可用。
| 项目 | Q3新模型 | Q4新模型 |
| --- | ---: | ---: |
| 训练种子 | 310001 | 410001 |
| 定向概率 | 0 | 0.75 |
| 训练墙钟时间 | 276.6s | 250.6s |
| 独立单源评估成功 | 59/60 | 60/60 |
| 单源平均局部时间 | 270.04s | 349.51s |
| 平均动作步数 | 2.42 | 3.13 |
Q3有一次局部训练任务未完成,不能声称单源成功率100%。完整闭环仍有自身调度与后备路径。两问题各只有一个新模型训练种子,未覆盖训练随机性。
## 4. 完整场景同条件对照
比较三种固定策略:当前手写基线(Q3 `bayes`、Q4 `directional`)、旧默认PPO、新Maskable PPO。相同场景使用相同源位置、频道、半径、朝向及逐点固定误差种子。`referee` 为单独实现,策略不读取模拟器真值。每场保存场景、完整请求/响应、summary、模型哈希和计时核验。
开发集为种子700—702、10/16源,各问题6场。随后固定新模型,不再据验证成绩调参;验证集为种子91000—91005、10/13/16源,各问题18场。第四问定向数覆盖1、约半数、仅一个全向三种组成。另加两种圆周边界压力场景。开发、验证、压力共52个不同场景,三策略共156次完整运行,全部满足真实源全清、缺席无误判、正常exit、零异常、逐步耗时复算一致。
### 开发集平均整场时间
| 问题 | 手写基线 | 旧PPO | 新模型 |
| --- | ---: | ---: | ---: |
| Q3,6场 | 3294.62s | 3206.20s | 3264.62s |
| Q4,6场 | 14289.76s | 12443.43s | 11758.72s |
### 独立验证集
| 问题/指标 | 手写基线 | 旧PPO | 新模型 |
| --- | ---: | ---: | ---: |
| Q3有效全清 | 18/18 | 18/18 | 18/18 |
| Q3平均时间 | 3330.72s | 3254.61s | 3307.65s |
| Q3中位时间 | 3309.16s | 3262.64s | 3222.50s |
| Q3最大时间 | 3690.11s | 3786.98s | 3776.55s |
| Q4有效全清 | 18/18 | 18/18 | 18/18 |
| Q4平均时间 | 13778.82s | 12070.53s | 11797.57s |
| Q4中位时间 | 14587.80s | 12891.83s | 12488.23s |
| Q4最大时间 | 17273.98s | 15365.76s | 15894.44s |
| Q4累计未成功clear尝试 | 616 | 719 | 1380 |
| Q4累计同频道同点重测 | 12 | 28 | 0 |
Q3三组都没有失败clear或同点重测。Q4新模型减少了重测,但更多使用后备光学清除尝试,平均耗时降低的同时尾部表现有所退化。失败clear本身可来自允许的后备搜索,不能仅凭该计数认定证书错误;其移动和3秒动作耗时全部纳入结果。
对独立验证场景做10000次配对bootstrap,负值表示新模型更快:
| 对比 | 均值相对变化 | 95%场景重采样区间 | 新模型更快场数 |
| --- | ---: | ---: | ---: |
| Q3新模型对手写 | -0.69% | [-4.50%, +2.95%] | 9/18 |
| Q3新模型对旧PPO | +1.63% | [-1.64%, +5.19%] | 8/18 |
| Q4新模型对手写 | -14.38% | [-17.93%, -11.48%] | 18/18 |
| Q4新模型对旧PPO | -2.26% | [-6.08%, +1.71%] | 13/18 |
新旧PPO的区间均跨0,不能据小幅平均变化宣称稳定改进。区间只反映固定模型在这些场景上的差异,不覆盖训练种子、未知官方分布或所有合法边界。此外本轮同时修改多项训练因素,这不是能归因到单个修复的消融实验。
### 边界压力与4000秒目标
源全部放在半径1800m圆周、接收半径1000m;第四问隔一个源采用向外发射方向。10/16源各一场,各策略都完成全清。
| 问题 | 手写平均 | 旧PPO平均 | 新模型平均 |
| --- | ---: | ---: | ---: |
| Q3 | 4472.58s | 4429.04s | 4648.26s |
| Q4 | 18248.87s | 14404.01s | 15210.08s |
新Q3的两场分别为4659.06s、4637.46s,仍超过4000s;新Q4为14573.62s、15846.54s,且比旧PPO退化。此前几何优化在另一独立Q3验证组达到平均3315.89s、最大3981.74s,本轮新Q3验证组最大3776.55s;二者只能说明各自验证组达标,不能承诺全部题设场景小于4000s。第四问尚未达到4000s。
## 5. 官方证据与测试
重新审计已有官方归档,三次均通过题号/策略、官方包SHA、源数、完整清除、正常退出、请求时窗及逐步计时检查,未改写原归档:
| 问题 | 既有官方案例 | 全清 | 整场时间 |
| --- | --- | ---: | ---: |
| Q3 | F38Y-9Q9J-B82V-CB9Z | 13/13 | 3538.81s |
| Q4,3个定向源 | X43X-VMRF-8GRZ-3SYA | 10/10 | 14003.09s |
| Q4,10个定向源 | BXSA-TFQ3-2DJ6-DHH7 | 10/10 | 14562.82s |
这些是旧模型的官方可运行证据,不是新模型成绩;不同案例也不能直接计算优化百分比。新模型目前通过本地验证,未在官方新演练中运行。
全量回归:`python -m pytest -q --tb=short`,243项通过。初次沙箱运行有24个临时目录权限导致的fixture错误,获得权限后重跑全部通过。新增5项测试覆盖训练/部署观测、动作屏蔽、方向读数重置遮挡、实际成本奖励和BC完整前向一致性。之后对基准/官方审计入口的小修补分别用4次完整场景冒烟运行及三份官方归档复核通过。
## 6. 产物与复现
主目录为 `output/rl/review-20260911/`:
- `q3_masked.zip` / `.json`、`q4_masked.zip` / `.json`:新模型与训练元数据,必须成对保存。
- `evaluation/development/{controls,revised}/results.json`:开发对照。
- `evaluation/validation/final/results.json`:独立验证与每场完整日志。
- `evaluation/stress/final/results.json`:边界压力结果与日志。
- `review_evidence.json`:配对区间、BC/特征错位探针、旧官方重审结果和代码哈希。
- `benchmark-smoke.json`:旧基准有效性口径修复后的冒烟结果。
新Q3模型SHA-256:`b8b3a2bb103588348d8d7791bde9a2b0635c04778f0ac64f91c6f5c7cf87ca6e`。
新Q4模型SHA-256:`6865d541ff9bdee81886d327345f2660d5f7d72f4b39810a58ae4b867ab37e42`。
从项目根目录复现训练时,使用新目录保留本轮检查点:
```powershell
.venv/Scripts/python.exe scripts/train_rl.py --problem 3 --algorithm maskable_ppo --timesteps 60000 --seed 310001 --device cpu --model output/rl/reproduction/q3_masked.zip --eval-episodes 60 --verbose 0
.venv/Scripts/python.exe scripts/train_rl.py --problem 4 --algorithm maskable_ppo --timesteps 60000 --seed 410001 --directional-probability 0.75 --device cpu --model output/rl/reproduction/q4_masked.zip --eval-episodes 60 --verbose 0
```
复核本轮冻结模型的完整对照(label须使用尚不存在的名称):
```powershell
.venv/Scripts/python.exe scripts/evaluate_rl_revision.py --split validation --label rerun-validation
.venv/Scripts/python.exe scripts/evaluate_rl_revision.py --split stress --label rerun-stress
.venv/Scripts/python.exe scripts/summarize_rl_revision.py
```
本地内存自检可显式加载对应检查点;`--self-test`不会连接官方模拟器:
```powershell
.venv/Scripts/mcm26b.exe run --robot-id 2026001 --self-test --strategy rl --rl-model output/rl/review-20260911/q3_masked.zip
.venv/Scripts/mcm26b.exe run --robot-id 2026001 --self-test --problem 4 --q4-strategy rl --rl-model output/rl/review-20260911/q4_masked.zip
```
在用户另行启动相应问题的官方演练后,使用实际登录队号和`--base-url`连接。例如第三问(路径使用本轮尚未创建的官方演练目录):
```powershell
.venv/Scripts/mcm26b.exe run --robot-id 2026001 --base-url http://127.0.0.1:2026 --problem 3 --strategy rl --rl-model output/rl/review-20260911/q3_masked.zip --log output/rl/review-20260911/practice-q3/session.jsonl
```
该命令保存请求/响应日志,汇总输出到终端;官方结果文件与汇总还需按原归档流程保存。第四问改用`--problem 4 --q4-strategy rl`及对应模型。本轮未执行上述官方连接命令。
进一步研究应先缩小单源训练与完整调度的差异,并处理Q4后备清除和边界退化,再做多个训练种子及新的冻结验证集。当前结果不足以将新模型自动替换为默认策略,也不足以把训练步数增加当作达到4000秒的依据。
+102
View File
@@ -0,0 +1,102 @@
# 第三、四问算法审核与优化
依据:原始 `issue/B题.pdf` 第1—3页,重点为附录2(3)(4),并结合(1)(2)(5)(6)(8)与第三、四问要求。
审核起点为 `9cf9428` 的程序;最后一次官方第三问演练为 `3BW5-9R54-NZNA-MYB9`,
13/13源成功清除、虚拟总时间4058.709750秒。本轮改进验证使用本地模拟器,没有启动或消耗官方测试。
## 1. 题设约束及审查结论
附录2(3)中的交会是有宽度的角域交集。不能把两条示向线的交点当作精确真值,
也不能利用同地重测求平均缩小±1°误差。程序已保留完整角域及0.005°舍入裕量,
本轮继续使用该证据颁发清除证书。统计评分仅用于选点,不能替代保守几何证书。
附录2(4)要求逐频道检测,换频1秒;结合(5),每次停靠检测5秒且不能在移动中检测。
已有HTTP客户端是串行的,没有把20频道视为一次免费测量。缺陷在于规划成本和站点利用:
| 审核发现 | 影响 | 当前改进 |
| --- | --- | --- |
| 已停靠点只测UNKNOWN频道,已发现频道容易错失交会机会 | 之后为第二条方位线另走一段路 | 对DETECTED频道预测收缩;当前位置到整个候选集均小于1000m、未在此处测过且预测半径减少35%时,逐频道补测;每次仍支付5秒和实际换频成本 |
| 定位选点只计到测点的移动 | 测完后到清除区域的路程没有进入选点目标 | 加入候选检测点→候选源中心的接近代价,保留后续根据真实响应重新规划 |
| 候选方向固定在全局角度网格 | 与当前交会几何不对齐,可能产生多余绕行 | 增加以当前位置到候选中心为轴的对称候选;均仍位于距离保证盘内 |
| 路线代价中的service_s按初始频道一次估计 | 2-opt比较不同顺序时没有正确传递频道状态 | 路径成本逐任务传递频道,站内当前频道优先,clear保持频道;两个任务也比较完整开放路径成本 |
| 清除默认走到候选集包围圆心 | 未利用20米光学定位/清除范围 | 在证书允许范围内向当前位置平移目标;平移距离+原包围半径不超过阈值,保留三角不等式证明 |
| 七站环半径可调但没有执行覆盖校验 | 不合法调参可能把“都没测到”误作不存在 | 构造时检查解析覆盖界;不满足条件直接拒绝运行 |
| 第四问盘外探点无信号也可能记为定向遮挡 | 把接收距离不足误诊为已确认定向 | 仅当实际探点位于距离保证盘内才据无信号确认定向;盘外无信号保留不确定性 |
| 第四问发现一个源就离站定位,后续频道再返回原站 | 同站频道间产生长距离往返 | 保留49站定向覆盖,先逐频道扫完本站,再按当前位置就近处理已发现源 |
| 后备清除按初始位置距离静态排序 | 狭长候选集可能反复折返,且循环内无虚拟预算检查 | 每一步从当前位置选最近未处理格,并逐次检查虚拟预算 |
第三问所有源均为全向,才能用no_signal排除1000米圆盘。第四问源类型与朝向未知,
no_signal还可能是半平面遮挡,不能用上述排除规则,也不能直接沿用七站缺席证明。
本轮没有把BayesLoop套到第四问;第四问继续采用49站覆盖和独立的定向定位/后备清除。
回归用例包含(1800,0)向外发射的源:七站全无信号,49站中有站可检出。
七站覆盖界为 `max(r/√3, sqrt(R²+r²−√3Rr))`,前提是`0<r≤√3R`。
当前R=1800m、r=1159.7m,通过小于1000m的校验。网格滤波额外带Voronoi裕量,
故无源时仍可能留下边界格;此时完整七站覆盖可以证明缺席,不要求PF一定为空。
## 2. 验收口径
4000秒目标按整场虚拟总时间(包含移动、换频、全部检测、清除和缺席确认)比较,
没有在4000秒强行停止,也没有以只清除部分源或最后一次成功清除的时刻代替总时间。
题面表格的平均定位清除时间仍等于总时间除以实际清除源数。
第三问优化开发集固定为种子0—5、10/16源,加两个最小接收半径的圆周边界场景(14场)。
选择实现后停止调整,再运行种子100—105、10/13/16源的独立验证集(18场)。
同场景前后使用相同位置、频道、有效半径和逐点固定误差种子。
真值只传给本地模拟器和执行后的校验,不提供给算法;全部请求和响应保存。
有效运行要求:全部真实源清除、没有误判真实频道缺席、正常exit、无算法异常、逐步耗时复算一致。
| 第三问指标 | 旧版 | 改进后 |
| --- | ---: | ---: |
| 开发集全清且有效 | 14/14 | 14/14 |
| 开发集平均总时间 | 3812.97s | 3390.88s |
| 开发集最大总时间 | 5535.13s | 4624.97s |
| 开发集中小于4000s | 10/14 | 12/14 |
| 独立验证集全清且有效 | 18/18 | 18/18 |
| 独立验证集平均总时间 | 3799.72s | **3315.89s(减少12.73%)** |
| 独立验证集最大总时间 | 4569.47s | **3981.74s** |
| 独立验证集中小于4000s | 12/18 | **18/18** |
两个人工圆周边界场景改进后仍为4145.19s、4624.97s左右。因此本轮实现达成的是
独立验证组每场小于4000秒,**不是对全部合法题目场景的最坏时间保证**。
旧官方案例已经结束,无法对新路线查询其未知响应;本地结果不冒充官方同案例重跑。
更新后的官方成绩仍需新演练验证,不能由前后不同案例的数字直接得出提升比例。
## 3. 第四问结果
固定四场:10源/3定向,种子0、1;16源/8定向,种子2、3。覆盖朝向未知场景,
每场源分布与误差种子前后相同。旧版、改进版均4/4全清、正常退出、零异常和零计时偏差。
| 场景 | 旧版总时间 | 改进后总时间 |
| --- | ---: | ---: |
| 10源,种子0 | 18599.317s | 13652.140s |
| 10源,种子1 | 16709.225s | 14918.134s |
| 16源,种子2 | 16388.604s | 11635.398s |
| 16源,种子3 | 16983.270s | 12453.274s |
| 平均 | 17170.104s | **13164.737s(减少23.33%)** |
第四问尚未降到4000秒。保留域外49站是为未知朝向源提供发现证据;本轮优化减少重复移动,
没有用第三问假设缩小第四问覆盖范围。其后备清除仍是有预算上限的算法,不能据四场结果声称所有混合场景必定在预算内完成。
## 4. 数据及复现
- 第三问数据根目录:`output/q3/optimization-20260911/`,含冻结旧版代码、配置、逐场景真值、动作日志、summary及汇总。
- 最终开发集:`development/improved/results.json`;独立验证:`validation/verified/results.json`;对应旧版在各自`baseline/results.json`。
- 第四问:`output/q4/optimization-20260911/{baseline,improved}-{10,16}.json`。
- 中间开发试验也保留:同点补测、移动前瞻、路线终点、来向候选、路径计费及自适应发现。最终未采用均值变差的路线终点估计和未知频道自适应补扫。
- 回归测试:`pytest -q`,**166项全部通过**。新增用例验证串行6秒补测、不重复同地读数、频道状态成本、清除圆平移证书、无信号诊断及七站/49站的适用边界。
在项目根目录运行(label使用未存在的名称以保护已有证据):
```powershell
.venv/Scripts/python.exe scripts/benchmark_q3_revision.py --label rerun-development
.venv/Scripts/python.exe scripts/benchmark_q3_revision.py --label rerun-validation --suite validation
.venv/Scripts/python.exe scripts/benchmark_q3_revision.py --label rerun-baseline --suite validation --baseline
.venv/Scripts/python.exe scripts/benchmark_q4.py --seeds 0,1 --sources 10 --directional 3 --out output/q4/rerun-10.json
.venv/Scripts/python.exe scripts/benchmark_q4.py --seeds 2,3 --sources 16 --directional 8 --out output/q4/rerun-16.json
```
概率限制:网格幸存集是保守可行集,不是已知官方概率模型的精确贝叶斯后验。
均匀源分布、接收半径分布、代表读数和哈希误差均属测试或启发式假设。
完备覆盖与清除证书依赖题面给出的确定性边界,性能数字则依赖具体测试分布。
+12 -12
View File
@@ -182,15 +182,15 @@ $$
## 八、运行方式和代码入口 ## 八、运行方式和代码入口
核心算法仅用Python标准库,支持Python3.10及以上;本次在Python3.12.14中验证。在项目根目录运行: 核心算法仅用Python标准库,支持Python3.10及以上;工程依赖仅 `requests`(测试另需 `pytest`)。在项目根目录运行:
```powershell ```powershell
python -m geometry examples/q1/triangle.json -o output/q1/triangle_recomputed.json uv run python -m mcm26b.geometry examples/q1/triangle.json -o output/q1/triangle_recomputed.json
python main.py examples/q1/normal.json uv run mcm26b q1 examples/q1/normal.json
python -m geometry examples/q1/normal.json --rounding-margin-deg 0.005 uv run python -m mcm26b.geometry examples/q1/normal.json --rounding-margin-deg 0.005
python -m unittest discover -s tests -v uv run pytest
python scripts/build_q1_demo.py uv run python scripts/build_q1_demo.py
python scripts/benchmark_q1.py uv run python scripts/benchmark_q1.py
``` ```
输入JSON的最小格式: 输入JSON的最小格式:
@@ -209,22 +209,22 @@ python scripts/benchmark_q1.py
| 文件 | 职责 | | 文件 | 职责 |
| --- | --- | | --- | --- |
| `geometry/localization.py` | 测向角域、半平面、区域分类、直径和包围圆 | | `src/mcm26b/geometry/localization.py` | 测向角域、半平面、区域分类、直径和包围圆 |
| `geometry/planning.py` | 问题二首次测向的距离保证候选圆盘;独立于问题一模型 | | `src/mcm26b/geometry/planning.py` | 问题二首次测向的距离保证候选圆盘;独立于问题一模型 |
| `geometry/__main__.py`、`main.py` | JSON命令行输入输出 | | `src/mcm26b/geometry/__main__.py`、`src/mcm26b/cli.py` | JSON命令行输入输出 |
| `tests/test_geometry.py` | 解析反例、随机几何、独立裁剪对照与退化测试 | | `tests/test_geometry.py` | 解析反例、随机几何、独立裁剪对照与退化测试 |
| `tests/test_practice_replay.py` | 离线复算演练计时与观测结果,不连接模拟器 | | `tests/test_practice_replay.py` | 离线复算演练计时与观测结果,不连接模拟器 |
| `tests/test_geometry_certificates.py` | 增量圆与穷举法对照、覆盖证据、清除阈值、舍入选项及首次选点证书 | | `tests/test_geometry_certificates.py` | 增量圆与穷举法对照、覆盖证据、清除阈值、舍入选项及首次选点证书 |
| `scripts/benchmark_q1.py` | 局部性能对比与官方演练误差界敏感性复算 | | `scripts/benchmark_q1.py` | 局部性能对比与官方演练误差界敏感性复算 |
| `scripts/capture_practice.py` | 在已经启动且已核验的演练中采集少量测向 | | `scripts/capture_practice.py` | 在已经启动且已核验的演练中采集少量测向 |
| `scripts/build_q1_demo.py` | 用Python算法生成案例、结果和交互图数据 | | `scripts/build_q1_demo.py` | 用Python算法生成案例、结果和交互图数据 |
| `visualization/q1.template.html` | 可视化源模板;不另写一套求解算法 | | `scripts/assets/q1.template.html` | 可视化源模板;不另写一套求解算法 |
| `output/q1/question1.html` | 可直接打开的离线交互式模拟,所有数据已内嵌 | | `output/q1/question1.html` | 可直接打开的离线交互式模拟,所有数据已内嵌 |
如需再次采集,先在模拟器明确启动“问题3演练测试”,等待接口就绪,读取案例编码,然后运行: 如需再次采集,先在模拟器明确启动“问题3演练测试”,等待接口就绪,读取案例编码,然后运行:
```powershell ```powershell
python scripts/capture_practice.py --robot-id 你的参赛队号 --practice-confirmed --case-code 界面中的演练案例编码 uv run python scripts/capture_practice.py --robot-id 你的参赛队号 --practice-confirmed --case-code 界面中的演练案例编码
``` ```
接口协议没有返回演练/正式模式的字段,`--practice-confirmed` 是操作者确认已核验界面的显式参数,不能替代界面核查。采集脚本没有启动测试的功能,没有正式模式选项,只会调用 `/enter`、`/measure`、`/exit`。禁止在正式测试会话中运行。 接口协议没有返回演练/正式模式的字段,`--practice-confirmed` 是操作者确认已核验界面的显式参数,不能替代界面核查。采集脚本没有启动测试的功能,没有正式模式选项,只会调用 `/enter`、`/measure`、`/exit`。禁止在正式测试会话中运行。
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
# logs/
正式测试/演练导出的 JSONL 与汇总日志放置目录。本地 P1 训练/评测日志实际写入
`output/hrl/...`;本目录用于最终支撑材料归档,不修改文件名。
+3 -3
View File
@@ -1,5 +1,5 @@
from geometry.__main__ import main """兼容入口,转发到统一 CLI(mcm26b)。"""
from mcm26b.cli import main
if __name__ == "__main__": if __name__ == "__main__":
main() raise SystemExit(main())
+4
View File
@@ -0,0 +1,4 @@
# models/
最终冻结模型归档目录。训练脚本默认把模型写到 `--model` 指定路径;
P1 smoke 产物见 `output/hrl/p1-smoke-time/`。正式提交前把冻结模型复制到本目录并保留同名 `.json` 元数据。
-815
View File
@@ -1,815 +0,0 @@
[
{
"id": "normal",
"name": "三点交会",
"source": "synthetic",
"target": [
80,
90
],
"measurements": [
{
"x": -600,
"y": -250,
"bearing_deg": 27.21505117707799,
"half_angle_deg": 1.0
},
{
"x": 650,
"y": -100,
"bearing_deg": 161.015051177078,
"half_angle_deg": 1.0
},
{
"x": 100,
"y": 700,
"bearing_deg": 268.4721225527146,
"half_angle_deg": 1.0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
-600.0,
-250.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
0.8971423583981722,
0.44174154068614097
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "polygon",
"vertices": [
[
45.3908396669742,
96.27384560337686
],
[
80.26352724282751,
84.95314961314784
],
[
106.24825816469405,
97.74770218809789
],
[
71.61376404345356,
110.34332460542697
]
],
"tolerance_m": 6.294839156007086e-07,
"diameter_infinite": false,
"diameter_m": 60.87526295170263,
"diameter_pair": [
[
45.3908396669742,
96.27384560337686
],
[
106.24825816469405,
97.74770218809789
]
],
"area_m2": 778.9645078415749,
"diameter_circle": {
"center": [
75.81954891583413,
97.01077389573737
],
"radius_m": 30.437631475851315,
"max_vertex_distance_m": 30.43763147585132,
"covers": true,
"coverage_tolerance_m": 2.5179356624028345e-06,
"max_excess_m": 4.367922104569409e-15,
"outside_vertex_indices": [],
"witness_vertex": null
},
"minimum_enclosing_circle": {
"center": [
75.81954891583412,
97.01077389573737
],
"radius_m": 30.437631475851326
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 2.5179356624028345e-06,
"radius_with_margin_m": 30.437633993786985,
"remaining_margin_m": -10.437633993786985,
"center": [
75.81954891583412,
97.01077389573737
]
}
},
{
"status": "polygon",
"vertices": [
[
72.95144059951443,
87.32686714676511
],
[
80.26352724282755,
84.95314961314779
],
[
94.39740997503758,
91.91249455495989
],
[
94.49056873706193,
102.02365367196415
],
[
73.93038642999645,
109.5008321248877
]
],
"tolerance_m": 7.462871059079371e-07,
"diameter_infinite": false,
"diameter_m": 26.986082918182134,
"diameter_pair": [
[
94.39740997503758,
91.91249455495989
],
[
73.93038642999645,
109.5008321248877
]
],
"area_m2": 382.03705547378974,
"diameter_circle": {
"center": [
84.163898202517,
100.7066633399238
],
"radius_m": 13.493041459091067,
"max_vertex_distance_m": 17.45675089097608,
"covers": false,
"coverage_tolerance_m": 2.9851484236317485e-06,
"max_excess_m": 3.96370943188501,
"outside_vertex_indices": [
0,
1
],
"witness_vertex": [
72.95144059951443,
87.32686714676511
]
},
"minimum_enclosing_circle": {
"center": [
81.87363979249537,
98.04155797588491
],
"radius_m": 13.943107186092131
},
"guaranteed_clearable_at_mec_center": true,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 2.9851484236317485e-06,
"radius_with_margin_m": 13.943110171240557,
"remaining_margin_m": 6.056889828759443,
"center": [
81.87363979249537,
98.04155797588491
]
}
}
]
},
{
"id": "triangle",
"name": "直径圆反例",
"source": "synthetic",
"target": [
20,
11.547005383792515
],
"measurements": [
{
"x": -1000,
"y": 0,
"bearing_deg": 1,
"half_angle_deg": 1.0
},
{
"x": 540,
"y": -866.0254037844386,
"bearing_deg": 121,
"half_angle_deg": 1.0
},
{
"x": 520,
"y": 900.6664199358162,
"bearing_deg": 241,
"half_angle_deg": 1.0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
-1000.0,
0.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
1.0,
0.0
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "polygon",
"vertices": [
[
-22.483050583603557,
34.1356440648463
],
[
-1.1527327997955013,
0.0
],
[
40.000000000000284,
0.0
],
[
19.44641513032613,
35.59985327195466
]
],
"tolerance_m": 8.83402513014311e-07,
"diameter_infinite": false,
"diameter_m": 71.19953515266143,
"diameter_pair": [
[
-22.483050583603557,
34.1356440648463
],
[
40.000000000000284,
0.0
]
],
"area_m2": 1463.776307271084,
"diameter_circle": {
"center": [
8.75847470819835,
17.06782203242318
],
"radius_m": 35.59976757633071,
"max_vertex_distance_m": 35.59976757633074,
"covers": true,
"coverage_tolerance_m": 3.533610052057244e-06,
"max_excess_m": 2.4519345249005315e-14,
"outside_vertex_indices": [],
"witness_vertex": null
},
"minimum_enclosing_circle": {
"center": [
8.75847470819835,
17.06782203242318
],
"radius_m": 35.59976757633074
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 3.533610052057244e-06,
"radius_with_margin_m": 35.59977110994079,
"remaining_margin_m": -15.59977110994079,
"center": [
8.75847470819835,
17.06782203242318
]
}
},
{
"status": "polygon",
"vertices": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
],
[
19.999999999999847,
34.64101615137823
]
],
"tolerance_m": 1.0200653573832087e-06,
"diameter_infinite": false,
"diameter_m": 40.00000000000081,
"diameter_pair": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
]
],
"area_m2": 692.8203230275786,
"diameter_circle": {
"center": [
19.99999999999983,
0.0
],
"radius_m": 20.000000000000405,
"max_vertex_distance_m": 34.641016151378224,
"covers": false,
"coverage_tolerance_m": 4.080261429532835e-06,
"max_excess_m": 14.641016151377823,
"outside_vertex_indices": [
2
],
"witness_vertex": [
19.999999999999847,
34.64101615137823
]
},
"minimum_enclosing_circle": {
"center": [
19.99999999999983,
11.547005383792735
],
"radius_m": 23.094010767585495
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 4.080261429532835e-06,
"radius_with_margin_m": 23.094014847846925,
"remaining_margin_m": -3.0940148478469247,
"center": [
19.99999999999983,
11.547005383792735
]
}
}
]
},
{
"id": "poor",
"name": "近共线检测点",
"source": "synthetic",
"target": [
900,
50
],
"measurements": [
{
"x": 0,
"y": 0,
"bearing_deg": 3.1798301198642345,
"half_angle_deg": 1.0
},
{
"x": 100,
"y": 0,
"bearing_deg": 3.576334374997351,
"half_angle_deg": 1.0
},
{
"x": 200,
"y": 0,
"bearing_deg": 4.085616779974877,
"half_angle_deg": 1.0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
0.0,
0.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
0.9992763681850043,
0.03803603537420482
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "unbounded",
"vertices": [
[
190.67332308426802,
7.257709171010532
],
[
649.0783141257873,
24.706243940862326
],
[
1149.8860918066787,
84.03538833511422
]
],
"tolerance_m": 5.0000000000000004e-08,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
0.9973401975299315,
0.07288710716551386
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "unbounded",
"vertices": [
[
349.47112173238565,
13.302121787008087
],
[
649.0783141257873,
24.706243940862326
],
[
704.9784261478786,
27.221516841665565
],
[
1149.886091806679,
84.03538833511422
],
[
1094.1078143807658,
79.57076189541714
]
],
"tolerance_m": 1.0000000000000001e-07,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
0.9973401975299315,
0.07288710716551386
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
}
]
},
{
"id": "empty",
"name": "不相容观测",
"source": "synthetic",
"target": null,
"measurements": [
{
"x": -100,
"y": 0,
"bearing_deg": 180,
"half_angle_deg": 1.0
},
{
"x": 100,
"y": 0,
"bearing_deg": 0,
"half_angle_deg": 1.0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
-100.0,
0.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
-0.9998476951563913,
0.01745240643728344
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "empty",
"vertices": [],
"diameter_m": null,
"diameter_infinite": false,
"tolerance_m": 1.0000000000000001e-07,
"message": "测向角域没有公共点;检查频道、数据及误差界"
}
]
},
{
"id": "segment",
"name": "零误差退化线段",
"source": "synthetic",
"target": [
40,
0
],
"measurements": [
{
"x": 0,
"y": 0,
"bearing_deg": 0,
"half_angle_deg": 0
},
{
"x": 100,
"y": 0,
"bearing_deg": 180,
"half_angle_deg": 0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
0.0,
0.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
1.0,
0.0
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "segment",
"vertices": [
[
0.0,
0.0
],
[
100.0,
0.0
]
],
"tolerance_m": 5.0000000000000004e-08,
"diameter_infinite": false,
"diameter_m": 100.0,
"diameter_pair": [
[
0.0,
0.0
],
[
100.0,
0.0
]
],
"area_m2": 0.0,
"diameter_circle": {
"center": [
50.0,
0.0
],
"radius_m": 50.0,
"max_vertex_distance_m": 50.0,
"covers": true,
"coverage_tolerance_m": 2.0000000000000002e-07,
"max_excess_m": 0.0,
"outside_vertex_indices": [],
"witness_vertex": null
},
"minimum_enclosing_circle": {
"center": [
50.0,
0.0
],
"radius_m": 50.0
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 2.0000000000000002e-07,
"radius_with_margin_m": 50.0000002,
"remaining_margin_m": -30.000000200000002,
"center": [
50.0,
0.0
]
}
}
]
},
{
"id": "practice-U5ZW-P9KN-TCAG-R7ST",
"name": "官方演练 U5ZW-P9KN-TCAG-R7ST",
"source": "official_practice",
"target": null,
"measurements": [
{
"x": 0,
"y": 0,
"bearing_deg": 131.52,
"half_angle_deg": 1.0
},
{
"x": -613.7618853216438,
"y": 391.53077545248124,
"bearing_deg": 34.92,
"half_angle_deg": 1.0
},
{
"x": -314.2721344680094,
"y": 656.6833525352392,
"bearing_deg": 227.19,
"half_angle_deg": 1.0
}
],
"frames": [
{
"status": "unbounded",
"vertices": [
[
0.0,
0.0
]
],
"tolerance_m": 1e-09,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
-0.6497134405131868,
0.7601792191427741
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
},
{
"status": "polygon",
"vertices": [
[
-460.69830582516533,
502.4117755118043
],
[
-456.18958970820563,
497.4948221803977
],
[
-436.511353451526,
510.7280211898303
],
[
-441.37035594940073,
516.4131625064848
]
],
"tolerance_m": 3.6400549446402593e-07,
"diameter_infinite": false,
"diameter_m": 25.57672002626576,
"diameter_pair": [
[
-460.69830582516533,
502.4117755118043
],
[
-436.511353451526,
510.7280211898303
]
],
"area_m2": 167.16830387852585,
"diameter_circle": {
"center": [
-448.6048296383457,
506.5698983508173
],
"radius_m": 12.78836001313288,
"max_vertex_distance_m": 12.788360013132888,
"covers": true,
"coverage_tolerance_m": 1.4560219778561037e-06,
"max_excess_m": 7.577386519575496e-15,
"outside_vertex_indices": [],
"witness_vertex": null
},
"minimum_enclosing_circle": {
"center": [
-448.6048296383457,
506.5698983508173
],
"radius_m": 12.788360013132888
},
"guaranteed_clearable_at_mec_center": true,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 1.4560219778561037e-06,
"radius_with_margin_m": 12.788361469154864,
"remaining_margin_m": 7.211638530845136,
"center": [
-448.6048296383457,
506.5698983508173
]
}
},
{
"status": "polygon",
"vertices": [
[
-460.69830582516533,
502.41177551180425
],
[
-456.4242356873799,
497.75071394627366
],
[
-440.56989343525083,
515.4766035082919
],
[
-441.3703559494006,
516.4131625064849
]
],
"tolerance_m": 4.666666666666667e-07,
"diameter_infinite": false,
"diameter_m": 23.996723024535473,
"diameter_pair": [
[
-460.69830582516533,
502.41177551180425
],
[
-440.56989343525083,
515.4766035082919
]
],
"area_m2": 89.48455568449387,
"diameter_circle": {
"center": [
-450.6340996302081,
508.9441895100481
],
"radius_m": 11.998361512267737,
"max_vertex_distance_m": 12.60236369723464,
"covers": false,
"coverage_tolerance_m": 1.8666666666666669e-06,
"max_excess_m": 0.604002184966904,
"outside_vertex_indices": [
1
],
"witness_vertex": [
-456.4242356873799,
497.75071394627366
]
},
"minimum_enclosing_circle": {
"center": [
-449.97695530423994,
507.9528348831342
],
"radius_m": 12.068583013309823
},
"guaranteed_clearable_at_mec_center": true,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 1.8666666666666669e-06,
"radius_with_margin_m": 12.068584879976491,
"remaining_margin_m": 7.931415120023509,
"center": [
-449.97695530423994,
507.9528348831342
]
}
}
]
}
]
-8
View File
@@ -1,8 +0,0 @@
{
"status": "empty",
"vertices": [],
"diameter_m": null,
"diameter_infinite": false,
"tolerance_m": 1.0000000000000001e-07,
"message": "测向角域没有公共点;检查频道、数据及误差界"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

-77
View File
@@ -1,77 +0,0 @@
{
"status": "polygon",
"vertices": [
[
72.95144059951443,
87.32686714676511
],
[
80.26352724282755,
84.95314961314779
],
[
94.39740997503758,
91.91249455495989
],
[
94.49056873706193,
102.02365367196415
],
[
73.93038642999645,
109.5008321248877
]
],
"tolerance_m": 7.462871059079371e-07,
"diameter_infinite": false,
"diameter_m": 26.986082918182134,
"diameter_pair": [
[
94.39740997503758,
91.91249455495989
],
[
73.93038642999645,
109.5008321248877
]
],
"area_m2": 382.03705547378974,
"diameter_circle": {
"center": [
84.163898202517,
100.7066633399238
],
"radius_m": 13.493041459091067,
"max_vertex_distance_m": 17.45675089097608,
"covers": false,
"coverage_tolerance_m": 2.9851484236317485e-06,
"max_excess_m": 3.96370943188501,
"outside_vertex_indices": [
0,
1
],
"witness_vertex": [
72.95144059951443,
87.32686714676511
]
},
"minimum_enclosing_circle": {
"center": [
81.87363979249537,
98.04155797588491
],
"radius_m": 13.943107186092131
},
"guaranteed_clearable_at_mec_center": true,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 2.9851484236317485e-06,
"radius_with_margin_m": 13.943110171240557,
"remaining_margin_m": 6.056889828759443,
"center": [
81.87363979249537,
98.04155797588491
]
}
}
-67
View File
@@ -1,67 +0,0 @@
{
"python": "3.12.14",
"timing_method": "median perf_counter; warm local process",
"timing_scope": "MEC only; not whole solver speedup or simulator/network performance",
"circle_benchmarks": [
{
"vertices": 4,
"reference_ms": 0.021899999410379678,
"incremental_ms": 0.028999995265621692,
"speedup": 0.7551725167466228,
"radius_difference_m": 0.0
},
{
"vertices": 20,
"reference_ms": 4.815899999812245,
"incremental_ms": 0.055900003644637764,
"speedup": 86.15205162467306,
"radius_difference_m": 3.552713678800501e-15
},
{
"vertices": 60,
"reference_ms": 306.5234000023338,
"incremental_ms": 0.09600000339560211,
"speedup": 3192.9519704202016,
"radius_difference_m": 0.0
}
],
"practice_sensitivity": [
{
"additional_half_angle_deg": 0,
"solve_ms": 0.09890000364976004,
"diameter_m": 23.996723024535473,
"mec_radius_m": 12.068583013309823,
"diameter_circle_excess_m": 0.604002184966904,
"clearance_margin_m": 7.931415120023509
},
{
"additional_half_angle_deg": 0.005,
"solve_ms": 0.0962999984039925,
"diameter_m": 24.119088149560866,
"mec_radius_m": 12.130376957888465,
"diameter_circle_excess_m": 0.608486475900504,
"clearance_margin_m": 7.869621175444868
}
],
"q2_first_bearing_certificate": {
"source_model": "first_bearing_sector_with_range_upper_bound",
"sector_enclosing_circle": {
"center": [
750.1153914962542,
0.0
],
"radius_m": 750.1153914962542
},
"sufficient_candidate_disk": {
"center": [
750.1153914962542,
0.0
],
"radius_m": 249.88460850374577
},
"candidate_nonempty_certified": true,
"distance_only": true,
"max_range_m": 1500,
"guaranteed_range_m": 1000
}
}
-33
View File
@@ -1,33 +0,0 @@
{
"status": "unbounded",
"vertices": [
[
349.47112173238565,
13.302121787008087
],
[
649.0783141257873,
24.706243940862326
],
[
704.9784261478786,
27.221516841665565
],
[
1149.886091806679,
84.03538833511422
],
[
1094.1078143807658,
79.57076189541714
]
],
"tolerance_m": 1.0000000000000001e-07,
"diameter_infinite": true,
"diameter_m": null,
"recession_direction": [
0.9973401975299315,
0.07288710716551386
],
"message": "存在非零衰退方向,区域无界,直径为无穷大"
}
@@ -1,72 +0,0 @@
{
"status": "polygon",
"vertices": [
[
-460.69830582516533,
502.41177551180425
],
[
-456.4242356873799,
497.75071394627366
],
[
-440.56989343525083,
515.4766035082919
],
[
-441.3703559494006,
516.4131625064849
]
],
"tolerance_m": 4.666666666666667e-07,
"diameter_infinite": false,
"diameter_m": 23.996723024535473,
"diameter_pair": [
[
-460.69830582516533,
502.41177551180425
],
[
-440.56989343525083,
515.4766035082919
]
],
"area_m2": 89.48455568449387,
"diameter_circle": {
"center": [
-450.6340996302081,
508.9441895100481
],
"radius_m": 11.998361512267737,
"max_vertex_distance_m": 12.60236369723464,
"covers": false,
"coverage_tolerance_m": 1.8666666666666669e-06,
"max_excess_m": 0.604002184966904,
"outside_vertex_indices": [
1
],
"witness_vertex": [
-456.4242356873799,
497.75071394627366
]
},
"minimum_enclosing_circle": {
"center": [
-449.97695530423994,
507.9528348831342
],
"radius_m": 12.068583013309823
},
"guaranteed_clearable_at_mec_center": true,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 1.8666666666666669e-06,
"radius_with_margin_m": 12.068584879976491,
"remaining_margin_m": 7.931415120023509,
"center": [
-449.97695530423994,
507.9528348831342
]
}
}
@@ -1,278 +0,0 @@
[
{
"path": "/enter",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-1"
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227659,
"virtual_time_s": 0,
"max_virtual_duration_s": 360000,
"max_real_duration_s": 1200,
"remaining_real_duration_s": 1200
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-2",
"position": {
"x": 0,
"y": 0
},
"channel": 1
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227678,
"virtual_time_s": 5,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-3",
"position": {
"x": 0,
"y": 0
},
"channel": 2
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227694,
"virtual_time_s": 11,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-4",
"position": {
"x": 0,
"y": 0
},
"channel": 3
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227696,
"virtual_time_s": 17,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-5",
"position": {
"x": 0,
"y": 0
},
"channel": 4
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227697,
"virtual_time_s": 23,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-6",
"position": {
"x": 0,
"y": 0
},
"channel": 5
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227709,
"virtual_time_s": 29,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-7",
"position": {
"x": 0,
"y": 0
},
"channel": 6
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227725,
"virtual_time_s": 35,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-8",
"position": {
"x": 0,
"y": 0
},
"channel": 7
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227727,
"virtual_time_s": 41,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-9",
"position": {
"x": 0,
"y": 0
},
"channel": 8
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227729,
"virtual_time_s": 47,
"measure_result": "no_signal"
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-10",
"position": {
"x": 0,
"y": 0
},
"channel": 9
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227740,
"virtual_time_s": 53,
"measure_result": "direction",
"svd_deg": 131.52
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-11",
"position": {
"x": 0,
"y": 0
},
"channel": 9
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227755,
"virtual_time_s": 58,
"measure_result": "direction",
"svd_deg": 131.52
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-12",
"position": {
"x": -613.7618853216438,
"y": 391.53077545248124
},
"channel": 9
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227770,
"virtual_time_s": 208.602198,
"measure_result": "direction",
"svd_deg": 34.92
},
"retries": 0
},
{
"path": "/measure",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-13",
"position": {
"x": -314.2721344680094,
"y": 656.6833525352392
},
"channel": 9
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227772,
"virtual_time_s": 293.602198,
"measure_result": "direction",
"svd_deg": 227.19
},
"retries": 0
},
{
"path": "/exit",
"request": {
"arena_id": "default",
"robot_id": "202608023016",
"request_id": "q1-536f4d679c4f-14"
},
"response": {
"accepted": true,
"real_timestamp_ms": 1789041227775,
"virtual_time_s": 293.602198,
"exit_reason": "user_exit"
},
"retries": 0
}
]
@@ -1,87 +0,0 @@
{
"name": "官方问题3演练观测",
"source": "official_practice",
"case_code": "U5ZW-P9KN-TCAG-R7ST",
"channel": 9,
"ground_truth": null,
"measurements": [
{
"x": 0,
"y": 0,
"bearing_deg": 131.52,
"half_angle_deg": 1.0
},
{
"x": -613.7618853216438,
"y": 391.53077545248124,
"bearing_deg": 34.92,
"half_angle_deg": 1.0
},
{
"x": -314.2721344680094,
"y": 656.6833525352392,
"bearing_deg": 227.19,
"half_angle_deg": 1.0
}
],
"repeated_station_response": {
"accepted": true,
"real_timestamp_ms": 1789041227755,
"virtual_time_s": 58,
"measure_result": "direction",
"svd_deg": 131.52
},
"result": {
"status": "polygon",
"vertices": [
[
-460.69830582516533,
502.41177551180425
],
[
-456.4242356873799,
497.75071394627366
],
[
-440.56989343525083,
515.4766035082919
],
[
-441.3703559494006,
516.4131625064849
]
],
"tolerance_m": 4.666666666666667e-07,
"diameter_infinite": false,
"diameter_m": 23.996723024535473,
"diameter_pair": [
[
-460.69830582516533,
502.41177551180425
],
[
-440.56989343525083,
515.4766035082919
]
],
"area_m2": 89.48455568449387,
"diameter_circle": {
"center": [
-450.6340996302081,
508.9441895100481
],
"radius_m": 11.998361512267737,
"max_vertex_distance_m": 12.60236369723464,
"covers": false
},
"minimum_enclosing_circle": {
"center": [
-449.97695530423994,
507.9528348831342
],
"radius_m": 12.068583013309823
},
"guaranteed_clearable_at_mec_center": true
},
"scope": "仅采集问题一观测,不执行问题三全清除任务;没有调用clear"
}
File diff suppressed because one or more lines are too long
-59
View File
@@ -1,59 +0,0 @@
{
"status": "segment",
"vertices": [
[
0.0,
0.0
],
[
100.0,
0.0
]
],
"tolerance_m": 5.0000000000000004e-08,
"diameter_infinite": false,
"diameter_m": 100.0,
"diameter_pair": [
[
0.0,
0.0
],
[
100.0,
0.0
]
],
"area_m2": 0.0,
"diameter_circle": {
"center": [
50.0,
0.0
],
"radius_m": 50.0,
"max_vertex_distance_m": 50.0,
"covers": true,
"coverage_tolerance_m": 2.0000000000000002e-07,
"max_excess_m": 0.0,
"outside_vertex_indices": [],
"witness_vertex": null
},
"minimum_enclosing_circle": {
"center": [
50.0,
0.0
],
"radius_m": 50.0
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 2.0000000000000002e-07,
"radius_with_margin_m": 50.0000002,
"remaining_margin_m": -30.000000200000002,
"center": [
50.0,
0.0
]
}
}
-48
View File
@@ -1,48 +0,0 @@
{
"status": "polygon",
"vertices": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
],
[
19.999999999999847,
34.64101615137823
]
],
"tolerance_m": 1.0200653573832087e-06,
"diameter_infinite": false,
"diameter_m": 40.00000000000081,
"diameter_pair": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
]
],
"area_m2": 692.8203230275786,
"diameter_circle": {
"center": [
19.99999999999983,
0.0
],
"radius_m": 20.000000000000405,
"max_vertex_distance_m": 34.641016151378224,
"covers": false
},
"minimum_enclosing_circle": {
"center": [
19.99999999999983,
11.547005383792735
],
"radius_m": 23.094010767585495
},
"guaranteed_clearable_at_mec_center": false
}
-68
View File
@@ -1,68 +0,0 @@
{
"status": "polygon",
"vertices": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
],
[
19.999999999999847,
34.64101615137823
]
],
"tolerance_m": 1.0200653573832087e-06,
"diameter_infinite": false,
"diameter_m": 40.00000000000081,
"diameter_pair": [
[
-5.755396159656812e-13,
0.0
],
[
40.000000000000234,
0.0
]
],
"area_m2": 692.8203230275786,
"diameter_circle": {
"center": [
19.99999999999983,
0.0
],
"radius_m": 20.000000000000405,
"max_vertex_distance_m": 34.641016151378224,
"covers": false,
"coverage_tolerance_m": 4.080261429532835e-06,
"max_excess_m": 14.641016151377823,
"outside_vertex_indices": [
2
],
"witness_vertex": [
19.999999999999847,
34.64101615137823
]
},
"minimum_enclosing_circle": {
"center": [
19.99999999999983,
11.547005383792735
],
"radius_m": 23.094010767585495
},
"guaranteed_clearable_at_mec_center": false,
"clearance_certificate": {
"model": "angular_intersection_only",
"clear_radius_m": 20.0,
"numerical_margin_m": 4.080261429532835e-06,
"radius_with_margin_m": 23.094014847846925,
"remaining_margin_m": -3.0940148478469247,
"center": [
19.99999999999983,
11.547005383792735
]
}
}
-7
View File
@@ -1,7 +0,0 @@
{
"interaction_states_checked": 32,
"missing_selectors": 0,
"nonfinite_svg_values": 0,
"browser_layout_verified": false,
"note": "Browser local-file navigation blocked by browser URL policy. Event handlers checked in minimal DOM; SVG statically inspected separately."
}
+29
View File
@@ -0,0 +1,29 @@
# project/ 薄兼容层
题目 Prompt 要求 `project/` 目录树;本仓库的真实算法保持唯一一份,
位于 `src/mcm26b`、`scripts/`。本目录只做 re-export/转发,不复制实现。
| Prompt 路径 | 真实实现 |
|---|---|
| `env/simulator_client.py` | `src/mcm26b/protocol/client.py` |
| `env/local_env.py` | `src/mcm26b/hrl/hierarchical_env.py`, `low_level_env.py` |
| `env/particle_filter.py` | `src/mcm26b/particles.py` |
| `policies/high_level_ppo.py` | `src/mcm26b/hrl/policy.py` |
| `policies/low_level_ppo.py` | `src/mcm26b/hrl/policy.py`, `low_level_env.py` |
| `train/curriculum.py` | `src/mcm26b/hrl/curriculum.py` |
| `train/domain_randomization.py` | `src/mcm26b/hrl/curriculum.py` + 配置包装 |
| `eval/evaluate.py` | `scripts/benchmark_hrl.py` |
| `eval/ablation.py` | `scripts/ablate_hrl.py`(P2) |
| `baselines/heuristic.py` | `src/mcm26b/planner/hrl_loop.py` 启发式降级 |
| `baselines/end_to_end_ppo.py` | 显式未实现;单源局部 PPO 不冒充 E2E |
使用示例:
```python
from project.env.local_env import make_local_env
env = make_local_env(problem=3, stage=1, seed=7)
obs, info = env.reset(seed=7)
```
P1 当前交付:`benchmark_hrl.py`、`train_hrl_high.py`、CLI `--strategy hrl`、
`--q4-strategy hrl`。P2 的 BC/Optuna/消融在 smoke 通过后另开。
+4
View File
@@ -0,0 +1,4 @@
"""题目 Prompt 所需目录树的薄兼容层。
真实实现仍位于 ``src/mcm26b``;本包只做 re-export / CLI 转发,避免两份算法逻辑。
"""
+3
View File
@@ -0,0 +1,3 @@
from .heuristic import HeuristicHRL, run_heuristic
__all__ = ["HeuristicHRL", "run_heuristic"]
+16
View File
@@ -0,0 +1,16 @@
"""端到端 PPO 基线占位。
按本轮确认:当前只交付局部 PPO 基线;raw-observation/raw-action 的真正
端到端 PPO 不在 P0+P1 范围内,因此显式标记未实现,避免把单源局部选点
PPO 误称为端到端 baseline。
"""
from __future__ import annotations
def train_end_to_end_ppo(*args, **kwargs):
raise NotImplementedError(
"本轮只交付局部 PPO 基线;真正的端到端 PPO 基线标记为未实现,"
"需单独立项定义原始观测、动作与安全执行边界。")
__all__ = ["train_end_to_end_ppo"]
+16
View File
@@ -0,0 +1,16 @@
"""兼容入口:信息增益/TSP/覆盖规则 + 高层启发式调度。"""
from mcm26b.planner.bayes_loop import BayesLoop
from mcm26b.planner.hrl_loop import HRLLoop
def HeuristicHRL(*args, **kwargs): # pylint: disable=invalid-name # 兼容入口保留题面公开名
"""返回无模型的高层 HRL 闭环(heuristic_action 降级路径)。"""
kwargs.setdefault("high_policy", None)
return HRLLoop(*args, **kwargs)
def run_heuristic(*args, **kwargs):
return HeuristicHRL(*args, **kwargs).run()
__all__ = ["HeuristicHRL", "run_heuristic", "BayesLoop", "HRLLoop"]
+6
View File
@@ -0,0 +1,6 @@
from .simulator_client import SimulatorClient
from .local_env import HierarchicalEnv, LowLevelEnv, HRLReward, make_local_env
from .particle_filter import ChannelParticles
__all__ = ["SimulatorClient", "HierarchicalEnv", "LowLevelEnv", "HRLReward",
"make_local_env", "ChannelParticles"]
+22
View File
@@ -0,0 +1,22 @@
"""兼容入口:本地简化训练环境。
HierarchicalEnv 是高层宏动作环境;LowLevelEnv 是独立八方向导航环境。
本文件不复制实现,只转发 mcm26b.hrl 下的真实类。
"""
from mcm26b.hrl.hierarchical_env import HRLReward, HierarchicalEnv
from mcm26b.hrl.low_level_env import LowLevelEnv
__all__ = ["HierarchicalEnv", "LowLevelEnv", "HRLReward", "make_local_env"]
def make_local_env(*, problem: int = 3, stage: int = 4, seed: int | None = None,
fidelity: str = "production"):
"""按题目 Prompt 的四阶段编号创建训练环境。"""
from mcm26b.hrl.curriculum import STAGES
if not 1 <= int(stage) <= len(STAGES):
raise ValueError(f"stage 必须在 1..{len(STAGES)}")
env = HierarchicalEnv(problem=problem, stage=STAGES[int(stage) - 1],
fidelity=fidelity)
if seed is not None:
env.reset(seed=seed)
return env
+4
View File
@@ -0,0 +1,4 @@
"""兼容入口:逐频道网格粒子/幸存集。"""
from mcm26b.particles import ChannelParticles, angular_gap
__all__ = ["ChannelParticles", "angular_gap"]
+8
View File
@@ -0,0 +1,8 @@
"""兼容入口:真实类见 mcm26b.protocol.client。"""
from mcm26b.protocol.client import (ActionRejected, ClearOutcome, DeadlineExceeded,
ExitInfo, MeasureOutcome, ProtocolError,
ProtocolViolation, SimulatorClient)
__all__ = ["SimulatorClient", "MeasureOutcome", "ClearOutcome", "ExitInfo",
"ProtocolError", "ActionRejected", "ProtocolViolation",
"DeadlineExceeded"]
+4
View File
@@ -0,0 +1,4 @@
from .evaluate import run_benchmark
from .ablation import run_ablation
__all__ = ["run_benchmark", "run_ablation"]
+20
View File
@@ -0,0 +1,20 @@
"""兼容入口:调用 scripts/ablate_hrl.py(P2 后启用)。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_ablation(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "ablate_hrl.py"
if not path.exists():
raise NotImplementedError(
"scripts/ablate_hrl.py 尚未实现;P1 阶段只保证 benchmark/training/CLI。")
spec = importlib.util.spec_from_file_location("ablate_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_ablation"]
+17
View File
@@ -0,0 +1,17 @@
"""兼容入口:调用 scripts/benchmark_hrl.py。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_benchmark(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "benchmark_hrl.py"
spec = importlib.util.spec_from_file_location("benchmark_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_benchmark"]
+5
View File
@@ -0,0 +1,5 @@
from .high_level_ppo import HighLevelPolicy, load_high_policy
from .low_level_ppo import LowLevelPolicy, load_low_policy
__all__ = ["HighLevelPolicy", "load_high_policy",
"LowLevelPolicy", "load_low_policy"]
+10
View File
@@ -0,0 +1,10 @@
"""兼容入口:高层 MaskablePPO 推理策略。"""
from mcm26b.hrl.policy import HighLevelPolicy
def load_high_policy(model_path: str, *, device: str = "auto",
problem: int | None = None) -> HighLevelPolicy:
return HighLevelPolicy(model_path, device=device, problem=problem)
__all__ = ["HighLevelPolicy", "load_high_policy"]
+9
View File
@@ -0,0 +1,9 @@
"""兼容入口:低层八方向到达策略(离线导航实验)。"""
from mcm26b.hrl.policy import LowLevelPolicy
def load_low_policy(model_path: str, *, device: str = "auto") -> LowLevelPolicy:
return LowLevelPolicy(model_path, device=device)
__all__ = ["LowLevelPolicy", "load_low_policy"]
+5
View File
@@ -0,0 +1,5 @@
from .curriculum import STAGES, Stage, make_scene, training_config
from .domain_randomization import randomize_problem_config
__all__ = ["STAGES", "Stage", "make_scene", "training_config",
"randomize_problem_config"]
+6
View File
@@ -0,0 +1,6 @@
"""兼容入口:课程学习与域随机化。"""
from mcm26b.hrl.curriculum import (STAGES, Stage, make_scene, stage_with_noise,
training_config, training_spec)
__all__ = ["STAGES", "Stage", "make_scene", "stage_with_noise",
"training_config", "training_spec"]
+31
View File
@@ -0,0 +1,31 @@
"""兼容入口:本地域随机化参数包装。
当前真实随机化在 mcm26b.hrl.curriculum.make_scene 内完成;这里只暴露
ProblemConfig 的显式替换助手,便于 Optuna/消融在实验配置中记录随机化范围。
"""
from __future__ import annotations
import dataclasses
from random import Random
from mcm26b.config import ProblemConfig
def randomize_problem_config(base: ProblemConfig, *, seed: int,
bearing_error_half_deg: float | None = None,
r_eff_range: tuple[float, float] | None = None
) -> ProblemConfig:
"""返回带域随机化标量的新配置;不修改全局默认配置。"""
_rng = Random(seed) # 固定种子留作兼容:真实随机化在 make_scene 内完成
field = base.field
if bearing_error_half_deg is None:
bearing_error_half_deg = field.bearing_error_half_deg
if r_eff_range is not None:
lo, hi = r_eff_range
if not 0 <= lo <= hi:
raise ValueError("r_eff_range 必须为递增非负区间")
return dataclasses.replace(base, field=dataclasses.replace(
field, bearing_error_half_deg=float(bearing_error_half_deg)))
__all__ = ["randomize_problem_config"]
+20
View File
@@ -0,0 +1,20 @@
"""兼容入口:调用 scripts/tune_hrl.py(P2 后启用)。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_tuning(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "tune_hrl.py"
if not path.exists():
raise NotImplementedError(
"scripts/tune_hrl.py 尚未实现;P1 阶段先冻结超参并留待 P2。")
spec = importlib.util.spec_from_file_location("tune_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_tuning"]
+116 -4
View File
@@ -1,7 +1,119 @@
[project] [project]
name = "math" name = "mcm26b"
version = "0.1.0" version = "0.2.0"
description = "B题问题一:带误差方位交会定位与可视化" description = "CUMCM 2026 B题:无线电干扰源的快速自动定位与清除(协议基线、几何内核与策略骨架)"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [] dependencies = [
"requests>=2.31",
]
[dependency-groups]
dev = [
"optuna>=5.0.0",
"pytest>=8",
# 独立评测机(自建模拟器):仅测试侧依赖,运行时代码零导入(懒加载 + 守卫测试)
"mcm26b-referee",
]
rl = [
"gymnasium>=1.1",
"sb3-contrib==2.9.0",
"stable-baselines3>=2.6",
"torch==2.11.0",
]
# uv 工作区:referee/ 是独立包(零第三方依赖、不依赖 mcm26b),双方仅通过 HTTP 协议耦合
[tool.uv.workspace]
members = ["referee"]
# RL 训练使用 CUDA 12.8 版 PyTorch(本机 RTX 4060;运行时依赖保持轻量)。
[[tool.uv.index]]
name = "pytorch-cu128"
url = "https://download.pytorch.org/whl/cu128"
explicit = true
[tool.uv.sources]
mcm26b-referee = { workspace = true }
# CUDA 12.8 版 PyTorch 仅限 Windows/Linux(RTX 4060 训练机);
# macOS (Apple Silicon, MPS) 回落到 PyPI 官方轮子。
torch = [
{ index = "pytorch-cu128", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/mcm26b"]
[project.scripts]
mcm26b = "mcm26b.cli:main"
[tool.pytest.ini_options]
testpaths = ["tests", "referee/tests"]
# ---------------------------------------------------------------------------
# pylint:全仓库静态检查口径
#
# 目标:`python -m pylint src scripts project tests referee main.py` 拿 10.00/10。
# 原则:真实的逻辑 / 资源 / 命名 / 死代码问题一律改代码;下面 disable 的每一条
# 都对应项目刻意的设计选择或已确认的静态分析误报,并写明理由,不做"一键静音"。
# ---------------------------------------------------------------------------
[tool.pylint.main]
py-version = "3.10"
jobs = 0
# 不写 ~/Library/Caches/pylint:CI 与受限沙箱里没有该目录,会刷警告
persistent = false
recursive = true
ignore = [".venv", ".uv-cache", "output"]
[tool.pylint.format]
max-line-length = 100
[tool.pylint.design]
# 阈值按"实际最长函数 + 余量"设定,而不是关闭检查:超过即说明该拆了
max-args = 14
max-positional-arguments = 10
max-locals = 45
max-branches = 26
max-statements = 180
max-attributes = 32
max-nested-blocks = 6
max-returns = 12
max-module-lines = 4000
min-public-methods = 0
[tool.pylint.basic]
# 这些是既有代码里的短名/别名(importorskip 后的模块句柄、几何单字母常量、
# 坐标系里的 x/y/z),让命名检查接受它们。
# 注意:good-names 不覆盖 redefined-builtin——stdlib 回调签名里的 `format`
# 之类只能在对应 def 上写行内 disable(见 server.py / referee 的 log_message)。
good-names = [
"i", "j", "k", "n", "m", "x", "y", "z", "_", "ex",
"id", "pytest", "numpy", "S", "ROOT", "FONT", "ET",
]
# http.server 要求 do_GET/do_POST 这类方法名,不能改成 snake_case
method-rgx = "[a-z_][a-z0-9_]{2,49}$|do_(GET|POST|PUT|DELETE|HEAD|PATCH|OPTIONS)$"
[tool.pylint."messages control"]
disable = [
# —— 项目刻意风格 ——
"missing-module-docstring", # 内部小模块与 __main__ 不强制
"missing-class-docstring",
"missing-function-docstring",
"import-outside-toplevel", # torch/SB3/referee 等重依赖与可选依赖懒加载
"wrong-import-position", # 同上:importorskip 守卫后的延迟导入
"ungrouped-imports", # 同上:延迟导入无法与顶部导入分组
"broad-exception-caught", # 子进程 / IO / HTTP 边界防御式兜底,逐处注释
"protected-access", # 测试与 mixin 有意检查内部状态
"duplicate-code", # 脚本与测试夹具存在结构性相似,非复制粘贴缺陷
"redefined-outer-name", # pytest 要求测试参数与 fixture 同名
"attribute-defined-outside-init", # 轻量对象在 helper 里补字段
"multiple-statements", # 单行守卫 (if x: return) 是可读性选择
"use-dict-literal", # dict(...) 与 {...} 混用是既有风格
"abstract-method", # 无头训练环境不需要实现 gym.Env.render
# —— 已确认的静态分析误报 ——
"possibly-used-before-assignment", # pytest.importorskip 成功即赋值,skip 会抛异常
]
@@ -0,0 +1,126 @@
{"event": "session_start", "case_code": "6X58-XQ7U-CJ24-JQQR", "module": "q4_practice", "robot_id": "1", "seed": 477239471, "countdown_s": 5.0, "window_s": 1500.0, "max_real_duration_s": 1200.0, "truth": [{"channel": 17, "x": -1178.1831977517415, "y": -1351.4242739803465, "r_eff_m": 1058.2857083120255, "directional": true, "heading_deg": 228.91780452670704}, {"channel": 1, "x": 616.704399833097, "y": 1665.0757168990908, "r_eff_m": 1324.912278063795, "directional": true, "heading_deg": 69.67656996032791}, {"channel": 7, "x": 875.9714308961434, "y": -356.413074975542, "r_eff_m": 1417.6410943244593, "directional": true, "heading_deg": 226.02323139790843}, {"channel": 15, "x": 77.58288789485773, "y": -1312.1259181145524, "r_eff_m": 1099.6028939269304, "directional": false, "heading_deg": 0.0}, {"channel": 10, "x": 569.7512600859908, "y": -287.53357300110514, "r_eff_m": 1163.1765321843473, "directional": false, "heading_deg": 0.0}, {"channel": 20, "x": -669.5662948265503, "y": -665.215319006332, "r_eff_m": 1376.2325668493522, "directional": false, "heading_deg": 0.0}, {"channel": 5, "x": -508.03938834052923, "y": 606.335297392372, "r_eff_m": 1447.9949377114212, "directional": false, "heading_deg": 0.0}, {"channel": 13, "x": 306.16535401564636, "y": 115.13724934212215, "r_eff_m": 1379.981981356019, "directional": false, "heading_deg": 0.0}, {"channel": 19, "x": 611.4980531732139, "y": 346.74044433389514, "r_eff_m": 1363.037307441268, "directional": false, "heading_deg": 0.0}, {"channel": 8, "x": -1328.739848763958, "y": 356.8075133866415, "r_eff_m": 1184.9420447581683, "directional": false, "heading_deg": 0.0}, {"channel": 16, "x": 1381.669496042516, "y": -1070.127602503145, "r_eff_m": 1413.4108109277565, "directional": false, "heading_deg": 0.0}, {"channel": 12, "x": -417.0933355563403, "y": -928.2011450309352, "r_eff_m": 1356.0447298689226, "directional": false, "heading_deg": 0.0}, {"channel": 2, "x": -1498.1076807839925, "y": -382.17536931742296, "r_eff_m": 1189.186960250608, "directional": false, "heading_deg": 0.0}]}
{"event": "action", "seq": 1, "wall_ts_ms": 1789097890374, "method": "POST", "path": "/enter", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0001"}, "response": {"accepted": true, "real_timestamp_ms": 1789097890374, "virtual_time_s": 0.0, "max_virtual_duration_s": 360000.0, "max_real_duration_s": 1200, "remaining_real_duration_s": 1200}}
{"event": "action", "seq": 2, "wall_ts_ms": 1789097890402, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0002", "position": {"x": 0.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097890402, "virtual_time_s": 5.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 3, "wall_ts_ms": 1789097890411, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0003", "position": {"x": 0.0, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097890411, "virtual_time_s": 11.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 4, "wall_ts_ms": 1789097890417, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0004", "position": {"x": 0.0, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097890417, "virtual_time_s": 17.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 5, "wall_ts_ms": 1789097890424, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0005", "position": {"x": 0.0, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097890424, "virtual_time_s": 23.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 6, "wall_ts_ms": 1789097890428, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0006", "position": {"x": 0.0, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097890428, "virtual_time_s": 29.0, "measure_result": "direction", "svd_deg": 129.52}}
{"event": "action", "seq": 7, "wall_ts_ms": 1789097890457, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0007", "position": {"x": 0.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097890457, "virtual_time_s": 35.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 8, "wall_ts_ms": 1789097890461, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0008", "position": {"x": 0.0, "y": 0.0}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097890461, "virtual_time_s": 41.0, "measure_result": "direction", "svd_deg": 338.47}}
{"event": "action", "seq": 9, "wall_ts_ms": 1789097890490, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0009", "position": {"x": 0.0, "y": 0.0}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097890490, "virtual_time_s": 47.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 10, "wall_ts_ms": 1789097890495, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0010", "position": {"x": 0.0, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097890495, "virtual_time_s": 53.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 11, "wall_ts_ms": 1789097890499, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0011", "position": {"x": 0.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097890499, "virtual_time_s": 59.0, "measure_result": "direction", "svd_deg": 333.15}}
{"event": "action", "seq": 12, "wall_ts_ms": 1789097890528, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0012", "position": {"x": 0.0, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097890528, "virtual_time_s": 65.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 13, "wall_ts_ms": 1789097890536, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0013", "position": {"x": 0.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097890535, "virtual_time_s": 71.0, "measure_result": "direction", "svd_deg": 246.6}}
{"event": "action", "seq": 14, "wall_ts_ms": 1789097890576, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0014", "position": {"x": 0.0, "y": 0.0}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097890576, "virtual_time_s": 77.0, "measure_result": "direction", "svd_deg": 21.6}}
{"event": "action", "seq": 15, "wall_ts_ms": 1789097890619, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0015", "position": {"x": 0.0, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097890619, "virtual_time_s": 83.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 16, "wall_ts_ms": 1789097890626, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0016", "position": {"x": 0.0, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097890626, "virtual_time_s": 89.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 17, "wall_ts_ms": 1789097890632, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0017", "position": {"x": 0.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097890632, "virtual_time_s": 95.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 18, "wall_ts_ms": 1789097890638, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0018", "position": {"x": 0.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097890638, "virtual_time_s": 101.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 19, "wall_ts_ms": 1789097890644, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0019", "position": {"x": 0.0, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097890644, "virtual_time_s": 107.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 20, "wall_ts_ms": 1789097890649, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0020", "position": {"x": 0.0, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097890649, "virtual_time_s": 113.0, "measure_result": "direction", "svd_deg": 30.39}}
{"event": "action", "seq": 21, "wall_ts_ms": 1789097890682, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0021", "position": {"x": 0.0, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097890682, "virtual_time_s": 119.0, "measure_result": "direction", "svd_deg": 224.38}}
{"event": "action", "seq": 22, "wall_ts_ms": 1789097890911, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0022", "position": {"x": -56.50838450880073, "y": -623.7611294008199}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097890911, "virtual_time_s": 250.263106, "measure_result": "direction", "svd_deg": 220.85}}
{"event": "action", "seq": 23, "wall_ts_ms": 1789097891082, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0023", "position": {"x": -395.918006797198, "y": -649.411475208361}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097891082, "virtual_time_s": 324.338603, "measure_result": "direction", "svd_deg": 182.47}}
{"event": "action", "seq": 24, "wall_ts_ms": 1789097891085, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0024", "position": {"x": -395.918006797198, "y": -649.411475208361}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097891085, "virtual_time_s": 330.338603, "measure_result": "direction", "svd_deg": 266.06}}
{"event": "action", "seq": 25, "wall_ts_ms": 1789097891235, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0025", "position": {"x": -677.2147882619608, "y": -662.0789583420399}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097891235, "virtual_time_s": 392.654975, "measure_result": "direction", "svd_deg": 338.23}}
{"event": "action", "seq": 26, "wall_ts_ms": 1789097891236, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0026", "position": {"x": -677.2147882619608, "y": -662.0789583420399}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097891236, "virtual_time_s": 397.654975, "clear_result": "success"}}
{"event": "action", "seq": 27, "wall_ts_ms": 1789097891371, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0027", "position": {"x": -416.69419258062, "y": -934.0015882185094}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097891371, "virtual_time_s": 477.971081, "clear_result": "success"}}
{"event": "action", "seq": 28, "wall_ts_ms": 1789097891504, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0028", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097891504, "virtual_time_s": 519.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 29, "wall_ts_ms": 1789097891508, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0029", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097891508, "virtual_time_s": 525.504646, "measure_result": "direction", "svd_deg": 145.0}}
{"event": "action", "seq": 30, "wall_ts_ms": 1789097891531, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0030", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097891531, "virtual_time_s": 531.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 31, "wall_ts_ms": 1789097891536, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0031", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097891536, "virtual_time_s": 537.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 32, "wall_ts_ms": 1789097891544, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0032", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097891544, "virtual_time_s": 543.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 33, "wall_ts_ms": 1789097891547, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0033", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097891547, "virtual_time_s": 549.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 34, "wall_ts_ms": 1789097891551, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0034", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097891551, "virtual_time_s": 555.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 35, "wall_ts_ms": 1789097891556, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0035", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097891556, "virtual_time_s": 561.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 36, "wall_ts_ms": 1789097891567, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0036", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097891567, "virtual_time_s": 567.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 37, "wall_ts_ms": 1789097891579, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0037", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097891579, "virtual_time_s": 573.504646, "measure_result": "direction", "svd_deg": 334.49}}
{"event": "action", "seq": 38, "wall_ts_ms": 1789097891600, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0038", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097891600, "virtual_time_s": 579.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 39, "wall_ts_ms": 1789097891608, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0039", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097891608, "virtual_time_s": 585.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 40, "wall_ts_ms": 1789097891611, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0040", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097891611, "virtual_time_s": 591.504646, "measure_result": "no_signal"}}
{"event": "action", "seq": 41, "wall_ts_ms": 1789097891814, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0041", "position": {"x": -1015.3031768622058, "y": -487.18523982583633}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097891814, "virtual_time_s": 732.716749, "measure_result": "direction", "svd_deg": 168.65}}
{"event": "action", "seq": 42, "wall_ts_ms": 1789097891986, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0042", "position": {"x": -1445.1368680915793, "y": -399.765559583966}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097891986, "virtual_time_s": 825.443416, "measure_result": "direction", "svd_deg": 160.85}}
{"event": "action", "seq": 43, "wall_ts_ms": 1789097892159, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0043", "position": {"x": -1475.621893761271, "y": -389.72231937134376}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097892159, "virtual_time_s": 836.862773, "measure_result": "direction", "svd_deg": 161.74}}
{"event": "action", "seq": 44, "wall_ts_ms": 1789097892162, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0044", "position": {"x": -1488.5778163464163, "y": -385.4540125603667}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097892162, "virtual_time_s": 844.590955, "clear_result": "success"}}
{"event": "action", "seq": 45, "wall_ts_ms": 1789097892328, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0045", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097892328, "virtual_time_s": 951.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 46, "wall_ts_ms": 1789097892331, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0046", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097892331, "virtual_time_s": 957.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 47, "wall_ts_ms": 1789097892333, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0047", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097892333, "virtual_time_s": 963.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 48, "wall_ts_ms": 1789097892336, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0048", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097892336, "virtual_time_s": 969.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 49, "wall_ts_ms": 1789097892338, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0049", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097892338, "virtual_time_s": 975.929085, "measure_result": "direction", "svd_deg": 114.49}}
{"event": "action", "seq": 50, "wall_ts_ms": 1789097892355, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0050", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097892355, "virtual_time_s": 981.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 51, "wall_ts_ms": 1789097892362, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0051", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097892362, "virtual_time_s": 987.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 52, "wall_ts_ms": 1789097892365, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0052", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097892365, "virtual_time_s": 993.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 53, "wall_ts_ms": 1789097892369, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0053", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097892369, "virtual_time_s": 999.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 54, "wall_ts_ms": 1789097892372, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0054", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097892372, "virtual_time_s": 1005.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 55, "wall_ts_ms": 1789097892374, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0055", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097892374, "virtual_time_s": 1011.929085, "measure_result": "no_signal"}}
{"event": "action", "seq": 56, "wall_ts_ms": 1789097892550, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0056", "position": {"x": -1156.2699064822978, "y": 431.08058643700474}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097892550, "virtual_time_s": 1104.147932, "measure_result": "direction", "svd_deg": 204.2}}
{"event": "action", "seq": 57, "wall_ts_ms": 1789097892554, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0057", "position": {"x": -1311.9381820719905, "y": 361.24482040167044}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097892554, "virtual_time_s": 1143.27103, "clear_result": "success"}}
{"event": "action", "seq": 58, "wall_ts_ms": 1789097892723, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0058", "position": {"x": -718.1413851639411, "y": 643.7959617866113}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097892723, "virtual_time_s": 1280.789817, "measure_result": "direction", "svd_deg": 350.4}}
{"event": "action", "seq": 59, "wall_ts_ms": 1789097892862, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0059", "position": {"x": -500.89208942120797, "y": 606.5963774288548}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097892862, "virtual_time_s": 1329.872043, "measure_result": "direction", "svd_deg": 182.0}}
{"event": "action", "seq": 60, "wall_ts_ms": 1789097892864, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0060", "position": {"x": -500.89208942120797, "y": 606.5963774288548}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097892864, "virtual_time_s": 1334.872043, "clear_result": "success"}}
{"event": "action", "seq": 61, "wall_ts_ms": 1789097893000, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0061", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097893000, "virtual_time_s": 1421.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 62, "wall_ts_ms": 1789097893003, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0062", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097893003, "virtual_time_s": 1427.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 63, "wall_ts_ms": 1789097893006, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0063", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097893006, "virtual_time_s": 1433.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 64, "wall_ts_ms": 1789097893009, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0064", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097893009, "virtual_time_s": 1439.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 65, "wall_ts_ms": 1789097893012, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0065", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097893012, "virtual_time_s": 1445.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 66, "wall_ts_ms": 1789097893015, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0066", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097893015, "virtual_time_s": 1451.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 67, "wall_ts_ms": 1789097893019, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0067", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097893019, "virtual_time_s": 1457.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 68, "wall_ts_ms": 1789097893022, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0068", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893022, "virtual_time_s": 1463.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 69, "wall_ts_ms": 1789097893027, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0069", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097893027, "virtual_time_s": 1469.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 70, "wall_ts_ms": 1789097893029, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0070", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097893029, "virtual_time_s": 1475.971024, "measure_result": "no_signal"}}
{"event": "action", "seq": 71, "wall_ts_ms": 1789097893175, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0071", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097893175, "virtual_time_s": 1712.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 72, "wall_ts_ms": 1789097893178, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0072", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097893178, "virtual_time_s": 1718.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 73, "wall_ts_ms": 1789097893181, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0073", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097893181, "virtual_time_s": 1724.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 74, "wall_ts_ms": 1789097893184, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0074", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097893184, "virtual_time_s": 1730.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 75, "wall_ts_ms": 1789097893187, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0075", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097893187, "virtual_time_s": 1736.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 76, "wall_ts_ms": 1789097893189, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0076", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097893189, "virtual_time_s": 1742.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 77, "wall_ts_ms": 1789097893192, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0077", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097893192, "virtual_time_s": 1748.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 78, "wall_ts_ms": 1789097893194, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0078", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097893194, "virtual_time_s": 1754.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 79, "wall_ts_ms": 1789097893197, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0079", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893197, "virtual_time_s": 1760.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 80, "wall_ts_ms": 1789097893200, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0080", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097893200, "virtual_time_s": 1766.911024, "measure_result": "no_signal"}}
{"event": "action", "seq": 81, "wall_ts_ms": 1789097893337, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0081", "position": {"x": 620.5177715246222, "y": 627.4795573759427}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097893337, "virtual_time_s": 1848.718641, "measure_result": "direction", "svd_deg": 267.9}}
{"event": "action", "seq": 82, "wall_ts_ms": 1789097893338, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0082", "position": {"x": 610.3522309687227, "y": 358.7211633093649}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097893338, "virtual_time_s": 1907.508756, "clear_result": "success"}}
{"event": "action", "seq": 83, "wall_ts_ms": 1789097893340, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0083", "position": {"x": 610.3522309687227, "y": 358.7211633093649}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097893340, "virtual_time_s": 1913.508756, "measure_result": "direction", "svd_deg": 218.89}}
{"event": "action", "seq": 84, "wall_ts_ms": 1789097893428, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0084", "position": {"x": 324.9336720474606, "y": 129.42995154285606}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097893428, "virtual_time_s": 1991.731215, "measure_result": "direction", "svd_deg": 217.51}}
{"event": "action", "seq": 85, "wall_ts_ms": 1789097893429, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0085", "position": {"x": 319.81645135573456, "y": 125.64271630078247}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097893429, "virtual_time_s": 1998.004464, "clear_result": "success"}}
{"event": "action", "seq": 86, "wall_ts_ms": 1789097893508, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0086", "position": {"x": 633.1131080089233, "y": -33.88884703594749}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893508, "virtual_time_s": 2074.319502, "measure_result": "no_signal"}}
{"event": "action", "seq": 87, "wall_ts_ms": 1789097893511, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0087", "position": {"x": 633.1131080089233, "y": -33.88884703594749}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097893511, "virtual_time_s": 2080.319502, "measure_result": "direction", "svd_deg": 256.29}}
{"event": "action", "seq": 88, "wall_ts_ms": 1789097893538, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0088", "position": {"x": 1159.7, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097893538, "virtual_time_s": 2191.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 89, "wall_ts_ms": 1789097893542, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0089", "position": {"x": 1159.7, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097893542, "virtual_time_s": 2197.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 90, "wall_ts_ms": 1789097893545, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0090", "position": {"x": 1159.7, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097893545, "virtual_time_s": 2203.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 91, "wall_ts_ms": 1789097893548, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0091", "position": {"x": 1159.7, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097893548, "virtual_time_s": 2209.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 92, "wall_ts_ms": 1789097893550, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0092", "position": {"x": 1159.7, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097893550, "virtual_time_s": 2215.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 93, "wall_ts_ms": 1789097893552, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0093", "position": {"x": 1159.7, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097893552, "virtual_time_s": 2221.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 94, "wall_ts_ms": 1789097893554, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0094", "position": {"x": 1159.7, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097893554, "virtual_time_s": 2227.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 95, "wall_ts_ms": 1789097893557, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0095", "position": {"x": 1159.7, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893557, "virtual_time_s": 2233.854749, "measure_result": "direction", "svd_deg": 282.51}}
{"event": "action", "seq": 96, "wall_ts_ms": 1789097893567, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0096", "position": {"x": 1159.7, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097893567, "virtual_time_s": 2239.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 97, "wall_ts_ms": 1789097893569, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0097", "position": {"x": 1159.7, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097893569, "virtual_time_s": 2245.854749, "measure_result": "no_signal"}}
{"event": "action", "seq": 98, "wall_ts_ms": 1789097893620, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0098", "position": {"x": 1400.966492396071, "y": -459.8888959615904}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893620, "virtual_time_s": 2355.721455, "measure_result": "direction", "svd_deg": 268.11}}
{"event": "action", "seq": 99, "wall_ts_ms": 1789097893652, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0099", "position": {"x": 1384.3965578790708, "y": -1021.7034041040436}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893652, "virtual_time_s": 2473.133217, "measure_result": "direction", "svd_deg": 266.90999999999997}}
{"event": "action", "seq": 100, "wall_ts_ms": 1789097893684, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0100", "position": {"x": 1383.126942952607, "y": -1056.5770079707515}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893684, "virtual_time_s": 2485.112558, "measure_result": "direction", "svd_deg": 264.22}}
{"event": "action", "seq": 101, "wall_ts_ms": 1789097893685, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0101", "position": {"x": 1382.2283880591076, "y": -1067.33389922316}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097893685, "virtual_time_s": 2492.271429, "clear_result": "success"}}
{"event": "action", "seq": 102, "wall_ts_ms": 1789097893713, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0102", "position": {"x": 348.3821957575218, "y": -1265.9247435227858}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097893712, "virtual_time_s": 2708.820832, "measure_result": "direction", "svd_deg": 190.35}}
{"event": "action", "seq": 103, "wall_ts_ms": 1789097893717, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0103", "position": {"x": 73.53358401969189, "y": -1315.6136497521597}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097893717, "virtual_time_s": 2769.68164, "measure_result": "direction", "svd_deg": 40.45}}
{"event": "action", "seq": 104, "wall_ts_ms": 1789097893719, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0104", "position": {"x": 73.53358401969189, "y": -1315.6136497521597}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097893719, "virtual_time_s": 2774.68164, "clear_result": "success"}}
{"event": "action", "seq": 105, "wall_ts_ms": 1789097893721, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0105", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097893721, "virtual_time_s": 2899.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 106, "wall_ts_ms": 1789097893724, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0106", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097893724, "virtual_time_s": 2905.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 107, "wall_ts_ms": 1789097893727, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0107", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097893727, "virtual_time_s": 2911.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 108, "wall_ts_ms": 1789097893730, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0108", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097893730, "virtual_time_s": 2917.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 109, "wall_ts_ms": 1789097893732, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0109", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097893732, "virtual_time_s": 2923.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 110, "wall_ts_ms": 1789097893734, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0110", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097893734, "virtual_time_s": 2929.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 111, "wall_ts_ms": 1789097893736, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0111", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097893736, "virtual_time_s": 2935.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 112, "wall_ts_ms": 1789097893739, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0112", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097893739, "virtual_time_s": 2941.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 113, "wall_ts_ms": 1789097893741, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0113", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097893741, "virtual_time_s": 2947.551995, "measure_result": "no_signal"}}
{"event": "action", "seq": 114, "wall_ts_ms": 1789097893743, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0114", "position": {"x": 571.1154888652, "y": -294.661369661795}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097893743, "virtual_time_s": 3094.496403, "clear_result": "success"}}
{"event": "action", "seq": 115, "wall_ts_ms": 1789097893744, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0115", "position": {"x": 571.1154888652, "y": -294.661369661795}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893744, "virtual_time_s": 3100.496403, "measure_result": "direction", "svd_deg": 348.0}}
{"event": "action", "seq": 116, "wall_ts_ms": 1789097893775, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0116", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893775, "virtual_time_s": 3216.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 117, "wall_ts_ms": 1789097893806, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0117", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893806, "virtual_time_s": 3221.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 118, "wall_ts_ms": 1789097893838, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0118", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893838, "virtual_time_s": 3226.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 119, "wall_ts_ms": 1789097893870, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0119", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893870, "virtual_time_s": 3231.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 120, "wall_ts_ms": 1789097893903, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0120", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893903, "virtual_time_s": 3236.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 121, "wall_ts_ms": 1789097893937, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0121", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893937, "virtual_time_s": 3241.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 122, "wall_ts_ms": 1789097893971, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0122", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097893971, "virtual_time_s": 3246.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 123, "wall_ts_ms": 1789097894009, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0123", "position": {"x": 1071.0447634419545, "y": -59.153833413874054}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097894009, "virtual_time_s": 3251.021166, "measure_result": "no_signal"}}
{"event": "action", "seq": 124, "wall_ts_ms": 1789097894011, "method": "POST", "path": "/exit", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "8a2d7fbadd15-0124"}, "response": {"accepted": true, "real_timestamp_ms": 1789097894011, "virtual_time_s": 3251.021166, "exit_reason": "user_exit"}}
{"event": "session_end", "reason": "user_exit", "virtual_time_s": 3251.021166, "real_elapsed_s": 10.123456, "request_count": 124, "cleared_count": 10}
@@ -0,0 +1,112 @@
{
"case_code": "6X58-XQ7U-CJ24-JQQR",
"module": "q4_practice",
"robot_id": "1",
"seed": 477239471,
"truth": [
{
"channel": 17,
"x": -1178.1831977517415,
"y": -1351.4242739803465,
"r_eff_m": 1058.2857083120255,
"directional": true,
"heading_deg": 228.91780452670704
},
{
"channel": 1,
"x": 616.704399833097,
"y": 1665.0757168990908,
"r_eff_m": 1324.912278063795,
"directional": true,
"heading_deg": 69.67656996032791
},
{
"channel": 7,
"x": 875.9714308961434,
"y": -356.413074975542,
"r_eff_m": 1417.6410943244593,
"directional": true,
"heading_deg": 226.02323139790843
},
{
"channel": 15,
"x": 77.58288789485773,
"y": -1312.1259181145524,
"r_eff_m": 1099.6028939269304,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 10,
"x": 569.7512600859908,
"y": -287.53357300110514,
"r_eff_m": 1163.1765321843473,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 20,
"x": -669.5662948265503,
"y": -665.215319006332,
"r_eff_m": 1376.2325668493522,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 5,
"x": -508.03938834052923,
"y": 606.335297392372,
"r_eff_m": 1447.9949377114212,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 13,
"x": 306.16535401564636,
"y": 115.13724934212215,
"r_eff_m": 1379.981981356019,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 19,
"x": 611.4980531732139,
"y": 346.74044433389514,
"r_eff_m": 1363.037307441268,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 8,
"x": -1328.739848763958,
"y": 356.8075133866415,
"r_eff_m": 1184.9420447581683,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 16,
"x": 1381.669496042516,
"y": -1070.127602503145,
"r_eff_m": 1413.4108109277565,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 12,
"x": -417.0933355563403,
"y": -928.2011450309352,
"r_eff_m": 1356.0447298689226,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 2,
"x": -1498.1076807839925,
"y": -382.17536931742296,
"r_eff_m": 1189.186960250608,
"directional": false,
"heading_deg": 0.0
}
]
}
@@ -0,0 +1,133 @@
{"event": "session_start", "case_code": "BAU8-WBA6-KTVC-ZEXJ", "module": "q4_practice", "robot_id": "1", "seed": 1724280692, "countdown_s": 5.0, "window_s": 1500.0, "max_real_duration_s": 1200.0, "truth": [{"channel": 11, "x": -651.4491911816699, "y": -861.9941841983957, "r_eff_m": 1158.6608380331968, "directional": true, "heading_deg": 183.92591871574925}, {"channel": 12, "x": 1585.5153767709246, "y": -598.9783966903034, "r_eff_m": 1422.1912155936766, "directional": true, "heading_deg": 181.61389868883072}, {"channel": 6, "x": 31.50984974130298, "y": -1431.359436573822, "r_eff_m": 1485.36130365001, "directional": true, "heading_deg": 92.85184332916663}, {"channel": 1, "x": -108.01732725078004, "y": -1695.4363576323935, "r_eff_m": 1493.4753791235612, "directional": false, "heading_deg": 0.0}, {"channel": 13, "x": 1201.552514046707, "y": 190.10520305773161, "r_eff_m": 1303.4011108874158, "directional": false, "heading_deg": 0.0}, {"channel": 16, "x": 979.2068152143753, "y": 146.43846094844704, "r_eff_m": 1232.2441710447958, "directional": false, "heading_deg": 0.0}, {"channel": 8, "x": 567.6868428443917, "y": -32.68947299569081, "r_eff_m": 1242.1787489349902, "directional": false, "heading_deg": 0.0}, {"channel": 3, "x": -307.0094050788321, "y": 931.898187331384, "r_eff_m": 1339.2730119404985, "directional": false, "heading_deg": 0.0}, {"channel": 2, "x": 1385.5262555901513, "y": 595.9468914421283, "r_eff_m": 1050.5024603796926, "directional": false, "heading_deg": 0.0}, {"channel": 10, "x": 1365.446283577057, "y": -619.1808438513183, "r_eff_m": 1495.4685578869562, "directional": false, "heading_deg": 0.0}]}
{"event": "action", "seq": 1, "wall_ts_ms": 1789098286512, "method": "POST", "path": "/enter", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0001"}, "response": {"accepted": true, "real_timestamp_ms": 1789098286512, "virtual_time_s": 0.0, "max_virtual_duration_s": 360000.0, "max_real_duration_s": 1200, "remaining_real_duration_s": 1200}}
{"event": "action", "seq": 2, "wall_ts_ms": 1789098286526, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0002", "position": {"x": 0.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098286526, "virtual_time_s": 5.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 3, "wall_ts_ms": 1789098286530, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0003", "position": {"x": 0.0, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789098286530, "virtual_time_s": 11.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 4, "wall_ts_ms": 1789098286534, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0004", "position": {"x": 0.0, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789098286534, "virtual_time_s": 17.0, "measure_result": "direction", "svd_deg": 107.63}}
{"event": "action", "seq": 5, "wall_ts_ms": 1789098286562, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0005", "position": {"x": 0.0, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098286562, "virtual_time_s": 23.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 6, "wall_ts_ms": 1789098286566, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0006", "position": {"x": 0.0, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098286566, "virtual_time_s": 29.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 7, "wall_ts_ms": 1789098286570, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0007", "position": {"x": 0.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098286570, "virtual_time_s": 35.0, "measure_result": "direction", "svd_deg": 272.12}}
{"event": "action", "seq": 8, "wall_ts_ms": 1789098286597, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0008", "position": {"x": 0.0, "y": 0.0}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098286597, "virtual_time_s": 41.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 9, "wall_ts_ms": 1789098286602, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0009", "position": {"x": 0.0, "y": 0.0}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789098286602, "virtual_time_s": 47.0, "measure_result": "direction", "svd_deg": 356.22}}
{"event": "action", "seq": 10, "wall_ts_ms": 1789098286633, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0010", "position": {"x": 0.0, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098286633, "virtual_time_s": 53.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 11, "wall_ts_ms": 1789098286638, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0011", "position": {"x": 0.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789098286638, "virtual_time_s": 59.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 12, "wall_ts_ms": 1789098286645, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0012", "position": {"x": 0.0, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098286645, "virtual_time_s": 65.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 13, "wall_ts_ms": 1789098286659, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0013", "position": {"x": 0.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098286659, "virtual_time_s": 71.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 14, "wall_ts_ms": 1789098286669, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0014", "position": {"x": 0.0, "y": 0.0}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098286669, "virtual_time_s": 77.0, "measure_result": "direction", "svd_deg": 9.8}}
{"event": "action", "seq": 15, "wall_ts_ms": 1789098286741, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0015", "position": {"x": 0.0, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098286741, "virtual_time_s": 83.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 16, "wall_ts_ms": 1789098286753, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0016", "position": {"x": 0.0, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098286753, "virtual_time_s": 89.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 17, "wall_ts_ms": 1789098286762, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0017", "position": {"x": 0.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789098286762, "virtual_time_s": 95.0, "measure_result": "direction", "svd_deg": 8.45}}
{"event": "action", "seq": 18, "wall_ts_ms": 1789098286799, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0018", "position": {"x": 0.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098286799, "virtual_time_s": 101.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 19, "wall_ts_ms": 1789098286810, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0019", "position": {"x": 0.0, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098286810, "virtual_time_s": 107.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 20, "wall_ts_ms": 1789098286822, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0020", "position": {"x": 0.0, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098286822, "virtual_time_s": 113.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 21, "wall_ts_ms": 1789098286828, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0021", "position": {"x": 0.0, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098286828, "virtual_time_s": 119.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 22, "wall_ts_ms": 1789098286992, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0022", "position": {"x": 609.4509025457847, "y": 242.75812328833265}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789098286991, "virtual_time_s": 256.203949, "measure_result": "direction", "svd_deg": 344.42}}
{"event": "action", "seq": 23, "wall_ts_ms": 1789098286994, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0023", "position": {"x": 609.4509025457847, "y": 242.75812328833265}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789098286994, "virtual_time_s": 262.203949, "measure_result": "direction", "svd_deg": 261.55}}
{"event": "action", "seq": 24, "wall_ts_ms": 1789098286996, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0024", "position": {"x": 609.4509025457847, "y": 242.75812328833265}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098286996, "virtual_time_s": 268.203949, "measure_result": "direction", "svd_deg": 354.36}}
{"event": "action", "seq": 25, "wall_ts_ms": 1789098287066, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0025", "position": {"x": 1129.9723230767108, "y": 193.27058928343394}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098287066, "virtual_time_s": 377.777668, "measure_result": "direction", "svd_deg": 356.72}}
{"event": "action", "seq": 26, "wall_ts_ms": 1789098287068, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0026", "position": {"x": 1129.9723230767108, "y": 193.27058928343394}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789098287068, "virtual_time_s": 383.777668, "measure_result": "direction", "svd_deg": 196.38}}
{"event": "action", "seq": 27, "wall_ts_ms": 1789098287131, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0027", "position": {"x": 1177.3957914158104, "y": 191.3865914463714}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098287131, "virtual_time_s": 399.269843, "measure_result": "direction", "svd_deg": 357.33}}
{"event": "action", "seq": 28, "wall_ts_ms": 1789098287188, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0028", "position": {"x": 1201.1075255853598, "y": 190.44459252784014}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098287188, "virtual_time_s": 409.015931, "measure_result": "near"}}
{"event": "action", "seq": 29, "wall_ts_ms": 1789098287190, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0029", "position": {"x": 1201.1075255853598, "y": 190.44459252784014}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789098287190, "virtual_time_s": 414.015931, "clear_result": "success"}}
{"event": "action", "seq": 30, "wall_ts_ms": 1789098287261, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0030", "position": {"x": 1159.7, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098287261, "virtual_time_s": 458.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 31, "wall_ts_ms": 1789098287265, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0031", "position": {"x": 1159.7, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789098287265, "virtual_time_s": 464.994759, "measure_result": "direction", "svd_deg": 69.82}}
{"event": "action", "seq": 32, "wall_ts_ms": 1789098287291, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0032", "position": {"x": 1159.7, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098287291, "virtual_time_s": 470.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 33, "wall_ts_ms": 1789098287296, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0033", "position": {"x": 1159.7, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098287296, "virtual_time_s": 476.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 34, "wall_ts_ms": 1789098287300, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0034", "position": {"x": 1159.7, "y": 0.0}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098287300, "virtual_time_s": 482.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 35, "wall_ts_ms": 1789098287304, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0035", "position": {"x": 1159.7, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098287304, "virtual_time_s": 488.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 36, "wall_ts_ms": 1789098287308, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0036", "position": {"x": 1159.7, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789098287308, "virtual_time_s": 494.994759, "measure_result": "direction", "svd_deg": 287.57}}
{"event": "action", "seq": 37, "wall_ts_ms": 1789098287329, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0037", "position": {"x": 1159.7, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098287329, "virtual_time_s": 500.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 38, "wall_ts_ms": 1789098287333, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0038", "position": {"x": 1159.7, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098287333, "virtual_time_s": 506.994759, "measure_result": "direction", "svd_deg": 304.84000000000003}}
{"event": "action", "seq": 39, "wall_ts_ms": 1789098287362, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0039", "position": {"x": 1159.7, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098287362, "virtual_time_s": 512.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 40, "wall_ts_ms": 1789098287366, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0040", "position": {"x": 1159.7, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098287366, "virtual_time_s": 518.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 41, "wall_ts_ms": 1789098287369, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0041", "position": {"x": 1159.7, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098287369, "virtual_time_s": 524.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 42, "wall_ts_ms": 1789098287373, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0042", "position": {"x": 1159.7, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098287373, "virtual_time_s": 530.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 43, "wall_ts_ms": 1789098287377, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0043", "position": {"x": 1159.7, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098287377, "virtual_time_s": 536.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 44, "wall_ts_ms": 1789098287380, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0044", "position": {"x": 1159.7, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098287380, "virtual_time_s": 542.994759, "measure_result": "no_signal"}}
{"event": "action", "seq": 45, "wall_ts_ms": 1789098287513, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0045", "position": {"x": 964.0195882337356, "y": 143.6973976268055}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789098287513, "virtual_time_s": 596.549786, "clear_result": "success"}}
{"event": "action", "seq": 46, "wall_ts_ms": 1789098287624, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0046", "position": {"x": 1147.7195456894221, "y": 445.38724453588145}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789098287624, "virtual_time_s": 673.19324, "measure_result": "direction", "svd_deg": 32.39}}
{"event": "action", "seq": 47, "wall_ts_ms": 1789098287718, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0047", "position": {"x": 1377.593698088216, "y": 591.7213795881403}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789098287718, "virtual_time_s": 732.693077, "measure_result": "direction", "svd_deg": 28.81}}
{"event": "action", "seq": 48, "wall_ts_ms": 1789098287722, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0048", "position": {"x": 1377.593698088216, "y": 591.7213795881403}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789098287722, "virtual_time_s": 737.693077, "clear_result": "success"}}
{"event": "action", "seq": 49, "wall_ts_ms": 1789098287821, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0049", "position": {"x": 1510.5079041685437, "y": -165.55211232315685}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098287821, "virtual_time_s": 897.462948, "measure_result": "direction", "svd_deg": 280.71}}
{"event": "action", "seq": 50, "wall_ts_ms": 1789098287824, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0050", "position": {"x": 1510.5079041685437, "y": -165.55211232315685}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789098287824, "virtual_time_s": 903.462948, "measure_result": "direction", "svd_deg": 252.35}}
{"event": "action", "seq": 51, "wall_ts_ms": 1789098287901, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0051", "position": {"x": 1600.0757430229646, "y": -634.2319383410297}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098287901, "virtual_time_s": 1004.895265, "measure_result": "no_signal"}}
{"event": "action", "seq": 52, "wall_ts_ms": 1789098287905, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0052", "position": {"x": 1600.0757430229646, "y": -634.2319383410297}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789098287905, "virtual_time_s": 1010.895265, "measure_result": "direction", "svd_deg": 176.19}}
{"event": "action", "seq": 53, "wall_ts_ms": 1789098287970, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0053", "position": {"x": 1374.4959772224145, "y": -620.5386205711816}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789098287970, "virtual_time_s": 1061.094264, "clear_result": "success"}}
{"event": "action", "seq": 54, "wall_ts_ms": 1789098287971, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0054", "position": {"x": 1374.4959772224145, "y": -620.5386205711816}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098287971, "virtual_time_s": 1067.094264, "measure_result": "direction", "svd_deg": 4.98}}
{"event": "action", "seq": 55, "wall_ts_ms": 1789098288029, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0055", "position": {"x": 1579.038663733305, "y": -602.8124850846476}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789098288029, "virtual_time_s": 1113.156133, "clear_result": "success"}}
{"event": "action", "seq": 56, "wall_ts_ms": 1789098288091, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0056", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098288091, "virtual_time_s": 1334.525028, "measure_result": "direction", "svd_deg": 224.86}}
{"event": "action", "seq": 57, "wall_ts_ms": 1789098288107, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0057", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098288107, "virtual_time_s": 1340.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 58, "wall_ts_ms": 1789098288110, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0058", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098288110, "virtual_time_s": 1346.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 59, "wall_ts_ms": 1789098288113, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0059", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098288113, "virtual_time_s": 1352.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 60, "wall_ts_ms": 1789098288117, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0060", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098288117, "virtual_time_s": 1358.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 61, "wall_ts_ms": 1789098288120, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0061", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288120, "virtual_time_s": 1364.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 62, "wall_ts_ms": 1789098288123, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0062", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098288123, "virtual_time_s": 1370.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 63, "wall_ts_ms": 1789098288129, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0063", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098288129, "virtual_time_s": 1376.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 64, "wall_ts_ms": 1789098288132, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0064", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098288132, "virtual_time_s": 1382.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 65, "wall_ts_ms": 1789098288135, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0065", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098288135, "virtual_time_s": 1388.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 66, "wall_ts_ms": 1789098288138, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0066", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098288138, "virtual_time_s": 1394.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 67, "wall_ts_ms": 1789098288141, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0067", "position": {"x": 579.8500000000001, "y": -1004.3296607688135}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098288141, "virtual_time_s": 1400.525028, "measure_result": "no_signal"}}
{"event": "action", "seq": 68, "wall_ts_ms": 1789098288226, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0068", "position": {"x": 254.04553841852473, "y": -854.2212845947172}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098288226, "virtual_time_s": 1478.269316, "measure_result": "direction", "svd_deg": 248.48000000000002}}
{"event": "action", "seq": 69, "wall_ts_ms": 1789098288278, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0069", "position": {"x": 109.51724182376685, "y": -1232.1472944851855}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098288278, "virtual_time_s": 1565.193107, "measure_result": "direction", "svd_deg": 244.24}}
{"event": "action", "seq": 70, "wall_ts_ms": 1789098288282, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0070", "position": {"x": 109.51724182376685, "y": -1232.1472944851855}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098288282, "virtual_time_s": 1571.193107, "measure_result": "direction", "svd_deg": 248.97}}
{"event": "action", "seq": 71, "wall_ts_ms": 1789098288319, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0071", "position": {"x": 50.30435176463236, "y": -1389.531228036628}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098288319, "virtual_time_s": 1609.823967, "measure_result": "direction", "svd_deg": 246.48000000000002}}
{"event": "action", "seq": 72, "wall_ts_ms": 1789098288353, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0072", "position": {"x": 39.195887560088515, "y": -1416.3295871617352}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098288353, "virtual_time_s": 1620.625863, "measure_result": "direction", "svd_deg": 243.70999999999998}}
{"event": "action", "seq": 73, "wall_ts_ms": 1789098288355, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0073", "position": {"x": 35.823200123353644, "y": -1423.469399884071}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789098288355, "virtual_time_s": 1627.205128, "clear_result": "success"}}
{"event": "action", "seq": 74, "wall_ts_ms": 1789098288386, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0074", "position": {"x": -118.1861771959669, "y": -1700.8617020167337}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098288386, "virtual_time_s": 1696.660743, "measure_result": "direction", "svd_deg": 28.76}}
{"event": "action", "seq": 75, "wall_ts_ms": 1789098288387, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0075", "position": {"x": -118.1861771959669, "y": -1700.8617020167337}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789098288387, "virtual_time_s": 1701.660743, "clear_result": "success"}}
{"event": "action", "seq": 76, "wall_ts_ms": 1789098288416, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0076", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098288416, "virtual_time_s": 1874.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 77, "wall_ts_ms": 1789098288420, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0077", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098288420, "virtual_time_s": 1880.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 78, "wall_ts_ms": 1789098288423, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0078", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098288422, "virtual_time_s": 1886.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 79, "wall_ts_ms": 1789098288425, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0079", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098288425, "virtual_time_s": 1892.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 80, "wall_ts_ms": 1789098288428, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0080", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288428, "virtual_time_s": 1898.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 81, "wall_ts_ms": 1789098288430, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0081", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098288430, "virtual_time_s": 1904.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 82, "wall_ts_ms": 1789098288433, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0082", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098288433, "virtual_time_s": 1910.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 83, "wall_ts_ms": 1789098288435, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0083", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098288435, "virtual_time_s": 1916.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 84, "wall_ts_ms": 1789098288439, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0084", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098288439, "virtual_time_s": 1922.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 85, "wall_ts_ms": 1789098288443, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0085", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098288443, "virtual_time_s": 1928.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 86, "wall_ts_ms": 1789098288448, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0086", "position": {"x": -579.8500000000006, "y": -1004.3296607688133}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098288448, "virtual_time_s": 1934.788283, "measure_result": "no_signal"}}
{"event": "action", "seq": 87, "wall_ts_ms": 1789098288479, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0087", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098288479, "virtual_time_s": 2171.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 88, "wall_ts_ms": 1789098288481, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0088", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098288481, "virtual_time_s": 2177.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 89, "wall_ts_ms": 1789098288484, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0089", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098288484, "virtual_time_s": 2183.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 90, "wall_ts_ms": 1789098288486, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0090", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098288486, "virtual_time_s": 2189.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 91, "wall_ts_ms": 1789098288489, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0091", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098288489, "virtual_time_s": 2195.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 92, "wall_ts_ms": 1789098288491, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0092", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288491, "virtual_time_s": 2201.728283, "measure_result": "direction", "svd_deg": 301.47}}
{"event": "action", "seq": 93, "wall_ts_ms": 1789098288503, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0093", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098288503, "virtual_time_s": 2207.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 94, "wall_ts_ms": 1789098288507, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0094", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098288507, "virtual_time_s": 2213.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 95, "wall_ts_ms": 1789098288510, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0095", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098288510, "virtual_time_s": 2219.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 96, "wall_ts_ms": 1789098288516, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0096", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098288516, "virtual_time_s": 2225.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 97, "wall_ts_ms": 1789098288518, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0097", "position": {"x": -1159.7, "y": 1.4202228929711856e-13}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098288518, "virtual_time_s": 2231.728283, "measure_result": "no_signal"}}
{"event": "action", "seq": 98, "wall_ts_ms": 1789098288550, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0098", "position": {"x": -774.2496286053656, "y": -389.8030122282429}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288550, "virtual_time_s": 2347.367396, "measure_result": "direction", "svd_deg": 283.74}}
{"event": "action", "seq": 99, "wall_ts_ms": 1789098288579, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0099", "position": {"x": -435.04585346585066, "y": 576.4769379998097}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789098288579, "virtual_time_s": 2558.184987, "measure_result": "direction", "svd_deg": 70.1}}
{"event": "action", "seq": 100, "wall_ts_ms": 1789098288582, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0100", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098288582, "virtual_time_s": 2654.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 101, "wall_ts_ms": 1789098288585, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0101", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098288585, "virtual_time_s": 2660.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 102, "wall_ts_ms": 1789098288588, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0102", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098288588, "virtual_time_s": 2666.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 103, "wall_ts_ms": 1789098288591, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0103", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098288591, "virtual_time_s": 2672.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 104, "wall_ts_ms": 1789098288594, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0104", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098288594, "virtual_time_s": 2678.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 105, "wall_ts_ms": 1789098288598, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0105", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098288598, "virtual_time_s": 2684.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 106, "wall_ts_ms": 1789098288602, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0106", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098288602, "virtual_time_s": 2690.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 107, "wall_ts_ms": 1789098288606, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0107", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098288606, "virtual_time_s": 2696.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 108, "wall_ts_ms": 1789098288610, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0108", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098288610, "virtual_time_s": 2702.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 109, "wall_ts_ms": 1789098288613, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0109", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098288613, "virtual_time_s": 2708.523504, "measure_result": "no_signal"}}
{"event": "action", "seq": 110, "wall_ts_ms": 1789098288618, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0110", "position": {"x": -579.8499999999998, "y": 1004.3296607688136}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789098288618, "virtual_time_s": 2714.523504, "measure_result": "direction", "svd_deg": 346.0}}
{"event": "action", "seq": 111, "wall_ts_ms": 1789098288620, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0111", "position": {"x": -314.40286948037965, "y": 938.2728681520762}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789098288620, "virtual_time_s": 2774.23207, "clear_result": "success"}}
{"event": "action", "seq": 112, "wall_ts_ms": 1789098288621, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0112", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789098288621, "virtual_time_s": 2959.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 113, "wall_ts_ms": 1789098288624, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0113", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789098288624, "virtual_time_s": 2965.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 114, "wall_ts_ms": 1789098288626, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0114", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789098288626, "virtual_time_s": 2971.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 115, "wall_ts_ms": 1789098288628, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0115", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789098288628, "virtual_time_s": 2977.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 116, "wall_ts_ms": 1789098288631, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0116", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789098288631, "virtual_time_s": 2983.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 117, "wall_ts_ms": 1789098288633, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0117", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789098288633, "virtual_time_s": 2989.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 118, "wall_ts_ms": 1789098288636, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0118", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789098288636, "virtual_time_s": 2995.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 119, "wall_ts_ms": 1789098288642, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0119", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789098288642, "virtual_time_s": 3001.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 120, "wall_ts_ms": 1789098288646, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0120", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789098288646, "virtual_time_s": 3007.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 121, "wall_ts_ms": 1789098288648, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0121", "position": {"x": 579.8500000000001, "y": 1004.3296607688135}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789098288648, "virtual_time_s": 3013.569929, "measure_result": "no_signal"}}
{"event": "action", "seq": 122, "wall_ts_ms": 1789098288653, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0122", "position": {"x": 567.7315195519344, "y": -30.08795183085696}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789098288653, "virtual_time_s": 3225.467648, "clear_result": "success"}}
{"event": "action", "seq": 123, "wall_ts_ms": 1789098288675, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0123", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288675, "virtual_time_s": 3453.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 124, "wall_ts_ms": 1789098288694, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0124", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288694, "virtual_time_s": 3458.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 125, "wall_ts_ms": 1789098288717, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0125", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288717, "virtual_time_s": 3463.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 126, "wall_ts_ms": 1789098288745, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0126", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288745, "virtual_time_s": 3468.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 127, "wall_ts_ms": 1789098288767, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0127", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288767, "virtual_time_s": 3473.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 128, "wall_ts_ms": 1789098288786, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0128", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288786, "virtual_time_s": 3478.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 129, "wall_ts_ms": 1789098288809, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0129", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288809, "virtual_time_s": 3483.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 130, "wall_ts_ms": 1789098288832, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0130", "position": {"x": -316.6685045965652, "y": -701.8080492945575}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789098288832, "virtual_time_s": 3488.582149, "measure_result": "no_signal"}}
{"event": "action", "seq": 131, "wall_ts_ms": 1789098288834, "method": "POST", "path": "/exit", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "40d2ecd3a4e3-0131"}, "response": {"accepted": true, "real_timestamp_ms": 1789098288834, "virtual_time_s": 3488.582149, "exit_reason": "user_exit"}}
{"event": "session_end", "reason": "user_exit", "virtual_time_s": 3488.582149, "real_elapsed_s": 6.480214, "request_count": 131, "cleared_count": 9}
@@ -0,0 +1,88 @@
{
"case_code": "BAU8-WBA6-KTVC-ZEXJ",
"module": "q4_practice",
"robot_id": "1",
"seed": 1724280692,
"truth": [
{
"channel": 11,
"x": -651.4491911816699,
"y": -861.9941841983957,
"r_eff_m": 1158.6608380331968,
"directional": true,
"heading_deg": 183.92591871574925
},
{
"channel": 12,
"x": 1585.5153767709246,
"y": -598.9783966903034,
"r_eff_m": 1422.1912155936766,
"directional": true,
"heading_deg": 181.61389868883072
},
{
"channel": 6,
"x": 31.50984974130298,
"y": -1431.359436573822,
"r_eff_m": 1485.36130365001,
"directional": true,
"heading_deg": 92.85184332916663
},
{
"channel": 1,
"x": -108.01732725078004,
"y": -1695.4363576323935,
"r_eff_m": 1493.4753791235612,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 13,
"x": 1201.552514046707,
"y": 190.10520305773161,
"r_eff_m": 1303.4011108874158,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 16,
"x": 979.2068152143753,
"y": 146.43846094844704,
"r_eff_m": 1232.2441710447958,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 8,
"x": 567.6868428443917,
"y": -32.68947299569081,
"r_eff_m": 1242.1787489349902,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 3,
"x": -307.0094050788321,
"y": 931.898187331384,
"r_eff_m": 1339.2730119404985,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 2,
"x": 1385.5262555901513,
"y": 595.9468914421283,
"r_eff_m": 1050.5024603796926,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 10,
"x": 1365.446283577057,
"y": -619.1808438513183,
"r_eff_m": 1495.4685578869562,
"directional": false,
"heading_deg": 0.0
}
]
}
@@ -0,0 +1,133 @@
{"event": "session_start", "case_code": "BBM9-HZG2-77N5-NKKC", "module": "q3_practice", "robot_id": "1", "seed": 214175614, "countdown_s": 5.0, "window_s": 1500.0, "max_real_duration_s": 1200.0, "truth": [{"channel": 13, "x": -667.5434273375823, "y": 1201.9279733147766, "r_eff_m": 1068.7667479727882, "directional": false, "heading_deg": 0.0}, {"channel": 18, "x": 936.4803225514449, "y": -449.0798658945765, "r_eff_m": 1100.2220789348723, "directional": false, "heading_deg": 0.0}, {"channel": 7, "x": 1168.5586737701378, "y": -665.9024303254582, "r_eff_m": 1380.180019258212, "directional": false, "heading_deg": 0.0}, {"channel": 16, "x": -704.338944452677, "y": -1500.6801256821625, "r_eff_m": 1260.765213581664, "directional": false, "heading_deg": 0.0}, {"channel": 9, "x": 301.3279949940345, "y": -1195.568730289507, "r_eff_m": 1268.9333402487596, "directional": false, "heading_deg": 0.0}, {"channel": 19, "x": -1016.5047516327342, "y": -1362.2054377699205, "r_eff_m": 1029.8927902123228, "directional": false, "heading_deg": 0.0}, {"channel": 17, "x": -1128.3611120627002, "y": -751.6668239293164, "r_eff_m": 1073.440585013539, "directional": false, "heading_deg": 0.0}, {"channel": 2, "x": 1267.339479448259, "y": 687.5619158006604, "r_eff_m": 1380.3211633911274, "directional": false, "heading_deg": 0.0}, {"channel": 14, "x": -431.7778870393432, "y": 921.0181764839424, "r_eff_m": 1418.973099517202, "directional": false, "heading_deg": 0.0}, {"channel": 11, "x": 437.0112473060851, "y": -112.52557536387796, "r_eff_m": 1181.7035745633132, "directional": false, "heading_deg": 0.0}]}
{"event": "action", "seq": 1, "wall_ts_ms": 1789097576646, "method": "POST", "path": "/enter", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0001"}, "response": {"accepted": true, "real_timestamp_ms": 1789097576646, "virtual_time_s": 0.0, "max_virtual_duration_s": 360000.0, "max_real_duration_s": 1200, "remaining_real_duration_s": 1200}}
{"event": "action", "seq": 2, "wall_ts_ms": 1789097576662, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0002", "position": {"x": 0.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097576662, "virtual_time_s": 5.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 3, "wall_ts_ms": 1789097576667, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0003", "position": {"x": 0.0, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097576667, "virtual_time_s": 11.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 4, "wall_ts_ms": 1789097576672, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0004", "position": {"x": 0.0, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097576672, "virtual_time_s": 17.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 5, "wall_ts_ms": 1789097576677, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0005", "position": {"x": 0.0, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097576677, "virtual_time_s": 23.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 6, "wall_ts_ms": 1789097576689, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0006", "position": {"x": 0.0, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097576688, "virtual_time_s": 29.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 7, "wall_ts_ms": 1789097576716, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0007", "position": {"x": 0.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097576716, "virtual_time_s": 35.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 8, "wall_ts_ms": 1789097576727, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0008", "position": {"x": 0.0, "y": 0.0}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097576727, "virtual_time_s": 41.0, "measure_result": "direction", "svd_deg": 329.53}}
{"event": "action", "seq": 9, "wall_ts_ms": 1789097576757, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0009", "position": {"x": 0.0, "y": 0.0}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097576757, "virtual_time_s": 47.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 10, "wall_ts_ms": 1789097576762, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0010", "position": {"x": 0.0, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097576762, "virtual_time_s": 53.0, "measure_result": "direction", "svd_deg": 284.61}}
{"event": "action", "seq": 11, "wall_ts_ms": 1789097576791, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0011", "position": {"x": 0.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097576791, "virtual_time_s": 59.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 12, "wall_ts_ms": 1789097576796, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0012", "position": {"x": 0.0, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097576796, "virtual_time_s": 65.0, "measure_result": "direction", "svd_deg": 345.95}}
{"event": "action", "seq": 13, "wall_ts_ms": 1789097576825, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0013", "position": {"x": 0.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097576825, "virtual_time_s": 71.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 14, "wall_ts_ms": 1789097576830, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0014", "position": {"x": 0.0, "y": 0.0}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097576830, "virtual_time_s": 77.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 15, "wall_ts_ms": 1789097576835, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0015", "position": {"x": 0.0, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097576835, "virtual_time_s": 83.0, "measure_result": "direction", "svd_deg": 115.07}}
{"event": "action", "seq": 16, "wall_ts_ms": 1789097576864, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0016", "position": {"x": 0.0, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097576864, "virtual_time_s": 89.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 17, "wall_ts_ms": 1789097576868, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0017", "position": {"x": 0.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097576868, "virtual_time_s": 95.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 18, "wall_ts_ms": 1789097576873, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0018", "position": {"x": 0.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097576873, "virtual_time_s": 101.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 19, "wall_ts_ms": 1789097576878, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0019", "position": {"x": 0.0, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097576878, "virtual_time_s": 107.0, "measure_result": "direction", "svd_deg": 334.09}}
{"event": "action", "seq": 20, "wall_ts_ms": 1789097576907, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0020", "position": {"x": 0.0, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097576907, "virtual_time_s": 113.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 21, "wall_ts_ms": 1789097576913, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0021", "position": {"x": 0.0, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097576913, "virtual_time_s": 119.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 22, "wall_ts_ms": 1789097577020, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0022", "position": {"x": -382.32549659893994, "y": 438.1825018611922}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097577020, "virtual_time_s": 241.305923, "measure_result": "direction", "svd_deg": 95.7}}
{"event": "action", "seq": 23, "wall_ts_ms": 1789097577105, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0023", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097577105, "virtual_time_s": 375.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 24, "wall_ts_ms": 1789097577108, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0024", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097577108, "virtual_time_s": 381.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 25, "wall_ts_ms": 1789097577111, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0025", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097577111, "virtual_time_s": 387.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 26, "wall_ts_ms": 1789097577114, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0026", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097577114, "virtual_time_s": 393.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 27, "wall_ts_ms": 1789097577117, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0027", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097577117, "virtual_time_s": 399.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 28, "wall_ts_ms": 1789097577121, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0028", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097577121, "virtual_time_s": 405.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 29, "wall_ts_ms": 1789097577124, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0029", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097577124, "virtual_time_s": 411.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 30, "wall_ts_ms": 1789097577128, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0030", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097577128, "virtual_time_s": 417.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 31, "wall_ts_ms": 1789097577132, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0031", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097577132, "virtual_time_s": 423.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 32, "wall_ts_ms": 1789097577137, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0032", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097577136, "virtual_time_s": 429.155971, "measure_result": "direction", "svd_deg": 112.67}}
{"event": "action", "seq": 33, "wall_ts_ms": 1789097577155, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0033", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097577155, "virtual_time_s": 435.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 34, "wall_ts_ms": 1789097577158, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0034", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097577158, "virtual_time_s": 441.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 35, "wall_ts_ms": 1789097577161, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0035", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097577161, "virtual_time_s": 447.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 36, "wall_ts_ms": 1789097577165, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0036", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097577165, "virtual_time_s": 453.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 37, "wall_ts_ms": 1789097577169, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0037", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097577169, "virtual_time_s": 459.155971, "measure_result": "no_signal"}}
{"event": "action", "seq": 38, "wall_ts_ms": 1789097577275, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0038", "position": {"x": -432.59886137022454, "y": 927.952956866304}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097577275, "virtual_time_s": 505.358374, "measure_result": "direction", "svd_deg": 276.22}}
{"event": "action", "seq": 39, "wall_ts_ms": 1789097577364, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0039", "position": {"x": -428.8404761449007, "y": 898.3063116196065}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097577364, "virtual_time_s": 516.335159, "measure_result": "direction", "svd_deg": 96.95}}
{"event": "action", "seq": 40, "wall_ts_ms": 1789097577365, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0040", "position": {"x": -430.7196687575625, "y": 913.129634242954}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097577365, "virtual_time_s": 524.323552, "clear_result": "success"}}
{"event": "action", "seq": 41, "wall_ts_ms": 1789097577455, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0041", "position": {"x": -441.9875302830439, "y": 1247.8826866081681}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097577455, "virtual_time_s": 597.31208, "measure_result": "direction", "svd_deg": 191.28}}
{"event": "action", "seq": 42, "wall_ts_ms": 1789097577456, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0042", "position": {"x": -668.4093907720109, "y": 1202.7926660772903}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097577456, "virtual_time_s": 648.485652, "clear_result": "success"}}
{"event": "action", "seq": 43, "wall_ts_ms": 1789097577536, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0043", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097577536, "virtual_time_s": 910.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 44, "wall_ts_ms": 1789097577539, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0044", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097577539, "virtual_time_s": 916.267979, "measure_result": "direction", "svd_deg": 332.39}}
{"event": "action", "seq": 45, "wall_ts_ms": 1789097577554, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0045", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097577554, "virtual_time_s": 922.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 46, "wall_ts_ms": 1789097577557, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0046", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097577557, "virtual_time_s": 928.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 47, "wall_ts_ms": 1789097577560, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0047", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097577560, "virtual_time_s": 934.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 48, "wall_ts_ms": 1789097577564, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0048", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097577564, "virtual_time_s": 940.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 49, "wall_ts_ms": 1789097577567, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0049", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097577567, "virtual_time_s": 946.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 50, "wall_ts_ms": 1789097577571, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0050", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097577571, "virtual_time_s": 952.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 51, "wall_ts_ms": 1789097577574, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0051", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097577574, "virtual_time_s": 958.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 52, "wall_ts_ms": 1789097577577, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0052", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097577577, "virtual_time_s": 964.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 53, "wall_ts_ms": 1789097577581, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0053", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097577581, "virtual_time_s": 970.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 54, "wall_ts_ms": 1789097577583, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0054", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097577583, "virtual_time_s": 976.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 55, "wall_ts_ms": 1789097577586, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0055", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097577586, "virtual_time_s": 982.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 56, "wall_ts_ms": 1789097577588, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0056", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097577588, "virtual_time_s": 988.267979, "measure_result": "no_signal"}}
{"event": "action", "seq": 57, "wall_ts_ms": 1789097577687, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0057", "position": {"x": 994.1110687766269, "y": 542.6492729278544}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097577687, "virtual_time_s": 1121.061738, "measure_result": "direction", "svd_deg": 28.25}}
{"event": "action", "seq": 58, "wall_ts_ms": 1789097577767, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0058", "position": {"x": 1268.7031752387938, "y": 689.8006776789011}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097577767, "virtual_time_s": 1188.368836, "measure_result": "near"}}
{"event": "action", "seq": 59, "wall_ts_ms": 1789097577773, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0059", "position": {"x": 1268.7031752387938, "y": 689.8006776789011}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097577773, "virtual_time_s": 1193.368836, "clear_result": "success"}}
{"event": "action", "seq": 60, "wall_ts_ms": 1789097577859, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0060", "position": {"x": 1200.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097577859, "virtual_time_s": 1338.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 61, "wall_ts_ms": 1789097577861, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0061", "position": {"x": 1200.0, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097577861, "virtual_time_s": 1344.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 62, "wall_ts_ms": 1789097577864, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0062", "position": {"x": 1200.0, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097577864, "virtual_time_s": 1350.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 63, "wall_ts_ms": 1789097577866, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0063", "position": {"x": 1200.0, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097577866, "virtual_time_s": 1356.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 64, "wall_ts_ms": 1789097577869, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0064", "position": {"x": 1200.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097577869, "virtual_time_s": 1362.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 65, "wall_ts_ms": 1789097577871, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0065", "position": {"x": 1200.0, "y": 0.0}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097577871, "virtual_time_s": 1368.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 66, "wall_ts_ms": 1789097577873, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0066", "position": {"x": 1200.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097577873, "virtual_time_s": 1374.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 67, "wall_ts_ms": 1789097577876, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0067", "position": {"x": 1200.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097577875, "virtual_time_s": 1380.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 68, "wall_ts_ms": 1789097577878, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0068", "position": {"x": 1200.0, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097577878, "virtual_time_s": 1386.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 69, "wall_ts_ms": 1789097577881, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0069", "position": {"x": 1200.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097577881, "virtual_time_s": 1392.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 70, "wall_ts_ms": 1789097577884, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0070", "position": {"x": 1200.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097577884, "virtual_time_s": 1398.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 71, "wall_ts_ms": 1789097577888, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0071", "position": {"x": 1200.0, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097577888, "virtual_time_s": 1404.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 72, "wall_ts_ms": 1789097577890, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0072", "position": {"x": 1200.0, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097577890, "virtual_time_s": 1410.011557, "measure_result": "no_signal"}}
{"event": "action", "seq": 73, "wall_ts_ms": 1789097577973, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0073", "position": {"x": 904.3723232997338, "y": -5.399878906793646}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097577973, "virtual_time_s": 1475.146955, "measure_result": "direction", "svd_deg": 193.85}}
{"event": "action", "seq": 74, "wall_ts_ms": 1789097578037, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0074", "position": {"x": 732.9363400589687, "y": 158.81239802766925}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097578037, "virtual_time_s": 1527.625779, "measure_result": "direction", "svd_deg": 223.37}}
{"event": "action", "seq": 75, "wall_ts_ms": 1789097578039, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0075", "position": {"x": 446.4480711916748, "y": -111.48435372746496}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097578039, "virtual_time_s": 1611.400359, "clear_result": "success"}}
{"event": "action", "seq": 76, "wall_ts_ms": 1789097578098, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0076", "position": {"x": 609.8586286156244, "y": -86.93118226598972}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097578098, "virtual_time_s": 1650.449334, "measure_result": "direction", "svd_deg": 312.82}}
{"event": "action", "seq": 77, "wall_ts_ms": 1789097578145, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0077", "position": {"x": 711.4189708756367, "y": -138.68820908196022}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097578145, "virtual_time_s": 1679.246959, "measure_result": "direction", "svd_deg": 311.79}}
{"event": "action", "seq": 78, "wall_ts_ms": 1789097578171, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0078", "position": {"x": 968.3799882543295, "y": -471.87178417317915}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097578171, "virtual_time_s": 1769.399264, "measure_result": "direction", "svd_deg": 145.41}}
{"event": "action", "seq": 79, "wall_ts_ms": 1789097578198, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0079", "position": {"x": 948.6903772101683, "y": -457.77800595341034}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097578198, "virtual_time_s": 1779.242054, "measure_result": "direction", "svd_deg": 144.5}}
{"event": "action", "seq": 80, "wall_ts_ms": 1789097578200, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0080", "position": {"x": 938.8455716880909, "y": -450.7311168435281}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097578200, "virtual_time_s": 1786.663449, "clear_result": "success"}}
{"event": "action", "seq": 81, "wall_ts_ms": 1789097578222, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0081", "position": {"x": 1216.8995655319154, "y": -717.7217593627017}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097578222, "virtual_time_s": 1869.760278, "measure_result": "direction", "svd_deg": 132.81}}
{"event": "action", "seq": 82, "wall_ts_ms": 1789097578247, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0082", "position": {"x": 1185.682710431516, "y": -684.9782355200915}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097578247, "virtual_time_s": 1883.808218, "measure_result": "direction", "svd_deg": 132.18}}
{"event": "action", "seq": 83, "wall_ts_ms": 1789097578269, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0083", "position": {"x": 1170.5902788598225, "y": -668.8979941203445}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097578269, "virtual_time_s": 1893.218913, "measure_result": "near"}}
{"event": "action", "seq": 84, "wall_ts_ms": 1789097578272, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0084", "position": {"x": 1170.6182266765854, "y": -668.8718181334558}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097578272, "virtual_time_s": 1898.226571, "clear_result": "success"}}
{"event": "action", "seq": 85, "wall_ts_ms": 1789097578293, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0085", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097578293, "virtual_time_s": 2040.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 86, "wall_ts_ms": 1789097578296, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0086", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097578296, "virtual_time_s": 2046.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 87, "wall_ts_ms": 1789097578299, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0087", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097578299, "virtual_time_s": 2052.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 88, "wall_ts_ms": 1789097578301, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0088", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097578301, "virtual_time_s": 2058.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 89, "wall_ts_ms": 1789097578304, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0089", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097578304, "virtual_time_s": 2064.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 90, "wall_ts_ms": 1789097578307, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0090", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097578307, "virtual_time_s": 2070.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 91, "wall_ts_ms": 1789097578311, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0091", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097578311, "virtual_time_s": 2076.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 92, "wall_ts_ms": 1789097578314, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0092", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097578314, "virtual_time_s": 2082.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 93, "wall_ts_ms": 1789097578318, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0093", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097578318, "virtual_time_s": 2088.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 94, "wall_ts_ms": 1789097578322, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0094", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097578322, "virtual_time_s": 2094.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 95, "wall_ts_ms": 1789097578325, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0095", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097578325, "virtual_time_s": 2100.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 96, "wall_ts_ms": 1789097578328, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0096", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097578328, "virtual_time_s": 2106.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 97, "wall_ts_ms": 1789097578332, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0097", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097578332, "virtual_time_s": 2112.281075, "measure_result": "no_signal"}}
{"event": "action", "seq": 98, "wall_ts_ms": 1789097578355, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0098", "position": {"x": 431.0177074456876, "y": -790.4383437162506}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097578355, "virtual_time_s": 2178.431734, "measure_result": "direction", "svd_deg": 252.8}}
{"event": "action", "seq": 99, "wall_ts_ms": 1789097578358, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0099", "position": {"x": 308.8495661381867, "y": -1188.2218722331802}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097578358, "virtual_time_s": 2266.655959, "measure_result": "direction", "svd_deg": 225.19}}
{"event": "action", "seq": 100, "wall_ts_ms": 1789097578359, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0100", "position": {"x": 302.26396092359636, "y": -1195.0880783213174}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097578359, "virtual_time_s": 2273.558746, "clear_result": "success"}}
{"event": "action", "seq": 101, "wall_ts_ms": 1789097578360, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0101", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097578360, "virtual_time_s": 2462.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 102, "wall_ts_ms": 1789097578363, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0102", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097578363, "virtual_time_s": 2468.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 103, "wall_ts_ms": 1789097578366, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0103", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097578366, "virtual_time_s": 2474.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 104, "wall_ts_ms": 1789097578371, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0104", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097578371, "virtual_time_s": 2480.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 105, "wall_ts_ms": 1789097578374, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0105", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097578374, "virtual_time_s": 2486.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 106, "wall_ts_ms": 1789097578377, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0106", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097578377, "virtual_time_s": 2492.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 107, "wall_ts_ms": 1789097578380, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0107", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097578380, "virtual_time_s": 2498.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 108, "wall_ts_ms": 1789097578384, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0108", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097578383, "virtual_time_s": 2504.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 109, "wall_ts_ms": 1789097578386, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0109", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097578386, "virtual_time_s": 2510.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 110, "wall_ts_ms": 1789097578389, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0110", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097578389, "virtual_time_s": 2516.684041, "measure_result": "direction", "svd_deg": 257.75}}
{"event": "action", "seq": 111, "wall_ts_ms": 1789097578399, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0111", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097578399, "virtual_time_s": 2522.684041, "measure_result": "direction", "svd_deg": 150.83}}
{"event": "action", "seq": 112, "wall_ts_ms": 1789097578409, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0112", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097578409, "virtual_time_s": 2528.684041, "measure_result": "direction", "svd_deg": 217.09}}
{"event": "action", "seq": 113, "wall_ts_ms": 1789097578419, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0113", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097578419, "virtual_time_s": 2534.684041, "measure_result": "no_signal"}}
{"event": "action", "seq": 114, "wall_ts_ms": 1789097578449, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0114", "position": {"x": -855.523050877763, "y": -1149.4070702441772}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097578449, "virtual_time_s": 2596.336861, "measure_result": "direction", "svd_deg": 293.06}}
{"event": "action", "seq": 115, "wall_ts_ms": 1789097578473, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0115", "position": {"x": -702.0198196486191, "y": -1511.0796905664733}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097578473, "virtual_time_s": 2679.91684, "measure_result": "direction", "svd_deg": 101.78}}
{"event": "action", "seq": 116, "wall_ts_ms": 1789097578475, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0116", "position": {"x": -704.0596428309664, "y": -1500.3611560598777}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097578475, "virtual_time_s": 2687.099021, "clear_result": "success"}}
{"event": "action", "seq": 117, "wall_ts_ms": 1789097578495, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0117", "position": {"x": -786.4741505952657, "y": -1490.051846445478}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097578495, "virtual_time_s": 2709.710382, "measure_result": "direction", "svd_deg": 151.04}}
{"event": "action", "seq": 118, "wall_ts_ms": 1789097578497, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0118", "position": {"x": -1023.4461023835017, "y": -1359.1588736906476}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097578497, "virtual_time_s": 2768.854145, "clear_result": "success"}}
{"event": "action", "seq": 119, "wall_ts_ms": 1789097578511, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0119", "position": {"x": -1266.2459250683066, "y": -1017.2747950835054}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097578511, "virtual_time_s": 2858.719866, "measure_result": "direction", "svd_deg": 62.8}}
{"event": "action", "seq": 120, "wall_ts_ms": 1789097578513, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0120", "position": {"x": -1126.6121592386512, "y": -745.1634840678316}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097578513, "virtual_time_s": 2924.88919, "clear_result": "success"}}
{"event": "action", "seq": 121, "wall_ts_ms": 1789097578515, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0121", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097578515, "virtual_time_s": 3080.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 122, "wall_ts_ms": 1789097578518, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0122", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097578518, "virtual_time_s": 3086.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 123, "wall_ts_ms": 1789097578520, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0123", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097578520, "virtual_time_s": 3092.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 124, "wall_ts_ms": 1789097578522, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0124", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097578522, "virtual_time_s": 3098.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 125, "wall_ts_ms": 1789097578524, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0125", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097578524, "virtual_time_s": 3104.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 126, "wall_ts_ms": 1789097578526, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0126", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097578526, "virtual_time_s": 3110.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 127, "wall_ts_ms": 1789097578527, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0127", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097578527, "virtual_time_s": 3116.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 128, "wall_ts_ms": 1789097578529, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0128", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097578529, "virtual_time_s": 3122.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 129, "wall_ts_ms": 1789097578531, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0129", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097578531, "virtual_time_s": 3128.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 130, "wall_ts_ms": 1789097578533, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0130", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097578533, "virtual_time_s": 3134.642907, "measure_result": "no_signal"}}
{"event": "action", "seq": 131, "wall_ts_ms": 1789097578535, "method": "POST", "path": "/exit", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "4721c649063d-0131"}, "response": {"accepted": true, "real_timestamp_ms": 1789097578535, "virtual_time_s": 3134.642907, "exit_reason": "user_exit"}}
{"event": "session_end", "reason": "user_exit", "virtual_time_s": 3134.642907, "real_elapsed_s": 3.209263, "request_count": 131, "cleared_count": 10}
@@ -0,0 +1,88 @@
{
"case_code": "BBM9-HZG2-77N5-NKKC",
"module": "q3_practice",
"robot_id": "1",
"seed": 214175614,
"truth": [
{
"channel": 13,
"x": -667.5434273375823,
"y": 1201.9279733147766,
"r_eff_m": 1068.7667479727882,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 18,
"x": 936.4803225514449,
"y": -449.0798658945765,
"r_eff_m": 1100.2220789348723,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 7,
"x": 1168.5586737701378,
"y": -665.9024303254582,
"r_eff_m": 1380.180019258212,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 16,
"x": -704.338944452677,
"y": -1500.6801256821625,
"r_eff_m": 1260.765213581664,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 9,
"x": 301.3279949940345,
"y": -1195.568730289507,
"r_eff_m": 1268.9333402487596,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 19,
"x": -1016.5047516327342,
"y": -1362.2054377699205,
"r_eff_m": 1029.8927902123228,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 17,
"x": -1128.3611120627002,
"y": -751.6668239293164,
"r_eff_m": 1073.440585013539,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 2,
"x": 1267.339479448259,
"y": 687.5619158006604,
"r_eff_m": 1380.3211633911274,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 14,
"x": -431.7778870393432,
"y": 921.0181764839424,
"r_eff_m": 1418.973099517202,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 11,
"x": 437.0112473060851,
"y": -112.52557536387796,
"r_eff_m": 1181.7035745633132,
"directional": false,
"heading_deg": 0.0
}
]
}
@@ -0,0 +1 @@
{"event": "session_start", "case_code": "GTS5-XVTM-V9YN-Y4BJ", "module": "q3_practice", "robot_id": "1", "seed": 2128480631, "countdown_s": 5.0, "window_s": 1500.0, "max_real_duration_s": 1200.0, "truth": [{"channel": 14, "x": 869.7117494788679, "y": 1325.898501771252, "r_eff_m": 1167.1710168530835, "directional": false, "heading_deg": 0.0}, {"channel": 7, "x": -1665.7822886877482, "y": 66.52241734048596, "r_eff_m": 1247.496847519186, "directional": false, "heading_deg": 0.0}, {"channel": 17, "x": -267.2501504987328, "y": -1556.6283220268592, "r_eff_m": 1491.0954004659015, "directional": false, "heading_deg": 0.0}, {"channel": 1, "x": -636.3395610110787, "y": -1598.1328560008155, "r_eff_m": 1208.9713764899795, "directional": false, "heading_deg": 0.0}, {"channel": 4, "x": 558.9076992395989, "y": 1032.2007939243106, "r_eff_m": 1211.461745342395, "directional": false, "heading_deg": 0.0}, {"channel": 16, "x": -1532.9905318641804, "y": -709.688503369543, "r_eff_m": 1067.0517959760218, "directional": false, "heading_deg": 0.0}, {"channel": 13, "x": -915.4908507030872, "y": -586.2791352960422, "r_eff_m": 1095.6771524182404, "directional": false, "heading_deg": 0.0}, {"channel": 11, "x": -1153.6749206930394, "y": 519.9519609239459, "r_eff_m": 1400.3919177962928, "directional": false, "heading_deg": 0.0}, {"channel": 18, "x": 1445.4267699899235, "y": 497.35501424117336, "r_eff_m": 1119.6707058479788, "directional": false, "heading_deg": 0.0}, {"channel": 15, "x": -329.7113112604381, "y": -157.01421172012004, "r_eff_m": 1432.5378503183756, "directional": false, "heading_deg": 0.0}, {"channel": 6, "x": 840.8717095338735, "y": -679.5717339286426, "r_eff_m": 1174.5610978768314, "directional": false, "heading_deg": 0.0}, {"channel": 5, "x": 1254.97217446553, "y": -347.277464286233, "r_eff_m": 1170.296779068818, "directional": false, "heading_deg": 0.0}, {"channel": 8, "x": -232.91757962061797, "y": 1588.9705512017863, "r_eff_m": 1102.2856329340332, "directional": false, "heading_deg": 0.0}, {"channel": 10, "x": 760.4387707310572, "y": -568.2401844640306, "r_eff_m": 1040.0816807146166, "directional": false, "heading_deg": 0.0}, {"channel": 12, "x": -685.4862181378795, "y": -1250.2632246388744, "r_eff_m": 1185.3345488548437, "directional": false, "heading_deg": 0.0}]}
@@ -0,0 +1,128 @@
{
"case_code": "GTS5-XVTM-V9YN-Y4BJ",
"module": "q3_practice",
"robot_id": "1",
"seed": 2128480631,
"truth": [
{
"channel": 14,
"x": 869.7117494788679,
"y": 1325.898501771252,
"r_eff_m": 1167.1710168530835,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 7,
"x": -1665.7822886877482,
"y": 66.52241734048596,
"r_eff_m": 1247.496847519186,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 17,
"x": -267.2501504987328,
"y": -1556.6283220268592,
"r_eff_m": 1491.0954004659015,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 1,
"x": -636.3395610110787,
"y": -1598.1328560008155,
"r_eff_m": 1208.9713764899795,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 4,
"x": 558.9076992395989,
"y": 1032.2007939243106,
"r_eff_m": 1211.461745342395,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 16,
"x": -1532.9905318641804,
"y": -709.688503369543,
"r_eff_m": 1067.0517959760218,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 13,
"x": -915.4908507030872,
"y": -586.2791352960422,
"r_eff_m": 1095.6771524182404,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 11,
"x": -1153.6749206930394,
"y": 519.9519609239459,
"r_eff_m": 1400.3919177962928,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 18,
"x": 1445.4267699899235,
"y": 497.35501424117336,
"r_eff_m": 1119.6707058479788,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 15,
"x": -329.7113112604381,
"y": -157.01421172012004,
"r_eff_m": 1432.5378503183756,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 6,
"x": 840.8717095338735,
"y": -679.5717339286426,
"r_eff_m": 1174.5610978768314,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 5,
"x": 1254.97217446553,
"y": -347.277464286233,
"r_eff_m": 1170.296779068818,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 8,
"x": -232.91757962061797,
"y": 1588.9705512017863,
"r_eff_m": 1102.2856329340332,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 10,
"x": 760.4387707310572,
"y": -568.2401844640306,
"r_eff_m": 1040.0816807146166,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 12,
"x": -685.4862181378795,
"y": -1250.2632246388744,
"r_eff_m": 1185.3345488548437,
"directional": false,
"heading_deg": 0.0
}
]
}
@@ -0,0 +1,121 @@
{"event": "session_start", "case_code": "RM7Y-JRYA-9S7E-6J2T", "module": "q3_practice", "robot_id": "1", "seed": 1539645273, "countdown_s": 5.0, "window_s": 1500.0, "max_real_duration_s": 1200.0, "truth": [{"channel": 18, "x": 1514.5988909830828, "y": 578.5437460895635, "r_eff_m": 1242.5532543305198, "directional": false, "heading_deg": 0.0}, {"channel": 15, "x": -813.7264918366334, "y": 184.45394380231278, "r_eff_m": 1281.7579743845968, "directional": false, "heading_deg": 0.0}, {"channel": 14, "x": -483.3588607307586, "y": 1609.042825940461, "r_eff_m": 1261.397442029016, "directional": false, "heading_deg": 0.0}, {"channel": 19, "x": 484.25883869219865, "y": 412.79231501032433, "r_eff_m": 1403.135275873889, "directional": false, "heading_deg": 0.0}, {"channel": 10, "x": -1185.3432835076858, "y": -882.5936176534458, "r_eff_m": 1051.898596297638, "directional": false, "heading_deg": 0.0}, {"channel": 7, "x": 27.489354230125446, "y": 597.1806051296936, "r_eff_m": 1016.5786767252073, "directional": false, "heading_deg": 0.0}, {"channel": 20, "x": -786.2186502489933, "y": -1030.2391402202422, "r_eff_m": 1337.9526501887033, "directional": false, "heading_deg": 0.0}, {"channel": 13, "x": -528.7812163217789, "y": 1415.4507846756549, "r_eff_m": 1342.4148601109948, "directional": false, "heading_deg": 0.0}, {"channel": 12, "x": 1618.6469617181342, "y": -780.4844715210944, "r_eff_m": 1183.5031703982477, "directional": false, "heading_deg": 0.0}, {"channel": 9, "x": -730.8436887494869, "y": 1629.1773460674606, "r_eff_m": 1268.3689368990042, "directional": false, "heading_deg": 0.0}, {"channel": 2, "x": -1498.0608735557626, "y": 84.22312468223669, "r_eff_m": 1169.058568141951, "directional": false, "heading_deg": 0.0}, {"channel": 3, "x": 1278.1226595751832, "y": 1262.0779642908842, "r_eff_m": 1096.052626308773, "directional": false, "heading_deg": 0.0}, {"channel": 8, "x": 16.436633792518094, "y": -864.8969376336956, "r_eff_m": 1051.1924624749086, "directional": false, "heading_deg": 0.0}, {"channel": 4, "x": 86.92957139289182, "y": 837.7240456106593, "r_eff_m": 1472.5243578771838, "directional": false, "heading_deg": 0.0}, {"channel": 5, "x": 264.7412123726052, "y": -576.0112311236278, "r_eff_m": 1472.6387608455834, "directional": false, "heading_deg": 0.0}, {"channel": 1, "x": -157.93200084817084, "y": -1476.5943058247763, "r_eff_m": 1381.0058509120777, "directional": false, "heading_deg": 0.0}]}
{"event": "action", "seq": 1, "wall_ts_ms": 1789097557703, "method": "POST", "path": "/enter", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0001"}, "response": {"accepted": true, "real_timestamp_ms": 1789097557703, "virtual_time_s": 0.0, "max_virtual_duration_s": 360000.0, "max_real_duration_s": 1200, "remaining_real_duration_s": 1200}}
{"event": "action", "seq": 2, "wall_ts_ms": 1789097557718, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0002", "position": {"x": 0.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097557718, "virtual_time_s": 5.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 3, "wall_ts_ms": 1789097557723, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0003", "position": {"x": 0.0, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097557723, "virtual_time_s": 11.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 4, "wall_ts_ms": 1789097557727, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0004", "position": {"x": 0.0, "y": 0.0}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097557727, "virtual_time_s": 17.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 5, "wall_ts_ms": 1789097557731, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0005", "position": {"x": 0.0, "y": 0.0}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097557731, "virtual_time_s": 23.0, "measure_result": "direction", "svd_deg": 83.92}}
{"event": "action", "seq": 6, "wall_ts_ms": 1789097557758, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0006", "position": {"x": 0.0, "y": 0.0}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097557758, "virtual_time_s": 29.0, "measure_result": "direction", "svd_deg": 294.12}}
{"event": "action", "seq": 7, "wall_ts_ms": 1789097557788, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0007", "position": {"x": 0.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097557788, "virtual_time_s": 35.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 8, "wall_ts_ms": 1789097557793, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0008", "position": {"x": 0.0, "y": 0.0}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097557793, "virtual_time_s": 41.0, "measure_result": "direction", "svd_deg": 87.89}}
{"event": "action", "seq": 9, "wall_ts_ms": 1789097557821, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0009", "position": {"x": 0.0, "y": 0.0}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097557821, "virtual_time_s": 47.0, "measure_result": "direction", "svd_deg": 270.40999999999997}}
{"event": "action", "seq": 10, "wall_ts_ms": 1789097557852, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0010", "position": {"x": 0.0, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097557852, "virtual_time_s": 53.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 11, "wall_ts_ms": 1789097557856, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0011", "position": {"x": 0.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097557856, "virtual_time_s": 59.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 12, "wall_ts_ms": 1789097557861, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0012", "position": {"x": 0.0, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097557861, "virtual_time_s": 65.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 13, "wall_ts_ms": 1789097557866, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0013", "position": {"x": 0.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097557866, "virtual_time_s": 71.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 14, "wall_ts_ms": 1789097557871, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0014", "position": {"x": 0.0, "y": 0.0}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097557871, "virtual_time_s": 77.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 15, "wall_ts_ms": 1789097557875, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0015", "position": {"x": 0.0, "y": 0.0}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097557875, "virtual_time_s": 83.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 16, "wall_ts_ms": 1789097557880, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0016", "position": {"x": 0.0, "y": 0.0}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097557880, "virtual_time_s": 89.0, "measure_result": "direction", "svd_deg": 166.24}}
{"event": "action", "seq": 17, "wall_ts_ms": 1789097557910, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0017", "position": {"x": 0.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097557910, "virtual_time_s": 95.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 18, "wall_ts_ms": 1789097557915, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0018", "position": {"x": 0.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097557915, "virtual_time_s": 101.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 19, "wall_ts_ms": 1789097557921, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0019", "position": {"x": 0.0, "y": 0.0}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097557921, "virtual_time_s": 107.0, "measure_result": "no_signal"}}
{"event": "action", "seq": 20, "wall_ts_ms": 1789097557928, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0020", "position": {"x": 0.0, "y": 0.0}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097557928, "virtual_time_s": 113.0, "measure_result": "direction", "svd_deg": 40.84}}
{"event": "action", "seq": 21, "wall_ts_ms": 1789097558022, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0021", "position": {"x": 0.0, "y": 0.0}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097558022, "virtual_time_s": 119.0, "measure_result": "direction", "svd_deg": 231.86}}
{"event": "action", "seq": 22, "wall_ts_ms": 1789097558210, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0022", "position": {"x": -149.65135118390128, "y": 573.0324376220874}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097558210, "virtual_time_s": 243.450277, "measure_result": "direction", "svd_deg": 8.69}}
{"event": "action", "seq": 23, "wall_ts_ms": 1789097558213, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0023", "position": {"x": 22.17702290799913, "y": 599.4956299989444}, "channel": 7}, "response": {"accepted": true, "real_timestamp_ms": 1789097558213, "virtual_time_s": 283.221122, "clear_result": "success"}}
{"event": "action", "seq": 24, "wall_ts_ms": 1789097558335, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0024", "position": {"x": -101.9760778275257, "y": 697.4671868713128}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097558335, "virtual_time_s": 320.851752, "measure_result": "direction", "svd_deg": 37.35}}
{"event": "action", "seq": 25, "wall_ts_ms": 1789097558442, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0025", "position": {"x": 90.33435176041925, "y": 844.7755213644774}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097558442, "virtual_time_s": 374.30092, "measure_result": "direction", "svd_deg": 245.20999999999998}}
{"event": "action", "seq": 26, "wall_ts_ms": 1789097558444, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0026", "position": {"x": 88.15565839928949, "y": 840.2676738025095}, "channel": 4}, "response": {"accepted": true, "real_timestamp_ms": 1789097558444, "virtual_time_s": 380.302267, "clear_result": "success"}}
{"event": "action", "seq": 27, "wall_ts_ms": 1789097558553, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0027", "position": {"x": 390.54100585774984, "y": 667.5806304250419}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097558553, "virtual_time_s": 455.946423, "measure_result": "direction", "svd_deg": 290.48}}
{"event": "action", "seq": 28, "wall_ts_ms": 1789097558555, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0028", "position": {"x": 483.4581452322053, "y": 418.111211730111}, "channel": 19}, "response": {"accepted": true, "real_timestamp_ms": 1789097558555, "virtual_time_s": 514.188732, "clear_result": "success"}}
{"event": "action", "seq": 29, "wall_ts_ms": 1789097558643, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0029", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097558643, "virtual_time_s": 646.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 30, "wall_ts_ms": 1789097558648, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0030", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097558648, "virtual_time_s": 652.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 31, "wall_ts_ms": 1789097558651, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0031", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097558651, "virtual_time_s": 658.58037, "measure_result": "direction", "svd_deg": 18.6}}
{"event": "action", "seq": 32, "wall_ts_ms": 1789097558671, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0032", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097558671, "virtual_time_s": 664.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 33, "wall_ts_ms": 1789097558675, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0033", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097558675, "virtual_time_s": 670.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 34, "wall_ts_ms": 1789097558678, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0034", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097558678, "virtual_time_s": 676.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 35, "wall_ts_ms": 1789097558681, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0035", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097558681, "virtual_time_s": 682.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 36, "wall_ts_ms": 1789097558685, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0036", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097558685, "virtual_time_s": 688.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 37, "wall_ts_ms": 1789097558689, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0037", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097558689, "virtual_time_s": 694.58037, "measure_result": "direction", "svd_deg": 161.62}}
{"event": "action", "seq": 38, "wall_ts_ms": 1789097558712, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0038", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097558712, "virtual_time_s": 700.58037, "measure_result": "direction", "svd_deg": 151.34}}
{"event": "action", "seq": 39, "wall_ts_ms": 1789097558731, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0039", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097558731, "virtual_time_s": 706.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 40, "wall_ts_ms": 1789097558734, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0040", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097558734, "virtual_time_s": 712.58037, "measure_result": "no_signal"}}
{"event": "action", "seq": 41, "wall_ts_ms": 1789097558739, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0041", "position": {"x": 600.0000000000001, "y": 1039.2304845413264}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097558739, "virtual_time_s": 718.58037, "measure_result": "direction", "svd_deg": 333.05}}
{"event": "action", "seq": 42, "wall_ts_ms": 1789097558912, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0042", "position": {"x": 763.3161794058348, "y": 1329.0912690006119}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097558912, "virtual_time_s": 791.121019, "measure_result": "direction", "svd_deg": 352.69}}
{"event": "action", "seq": 43, "wall_ts_ms": 1789097559125, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0043", "position": {"x": 1083.3861227014502, "y": 1072.8276376774256}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097559125, "virtual_time_s": 879.124877, "measure_result": "direction", "svd_deg": 310.85}}
{"event": "action", "seq": 44, "wall_ts_ms": 1789097559280, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0044", "position": {"x": 982.5080403720083, "y": 985.7374435518959}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097559280, "virtual_time_s": 911.779024, "measure_result": "direction", "svd_deg": 42.69}}
{"event": "action", "seq": 45, "wall_ts_ms": 1789097559281, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0045", "position": {"x": 1276.505194434143, "y": 1256.7197197867613}, "channel": 3}, "response": {"accepted": true, "real_timestamp_ms": 1789097559281, "virtual_time_s": 996.745447, "clear_result": "success"}}
{"event": "action", "seq": 46, "wall_ts_ms": 1789097559407, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0046", "position": {"x": 1519.930091635603, "y": 570.0314765599868}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097559407, "virtual_time_s": 1148.457001, "measure_result": "direction", "svd_deg": 122.2}}
{"event": "action", "seq": 47, "wall_ts_ms": 1789097559530, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0047", "position": {"x": 1509.5530416186468, "y": 585.8862512524679}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097559530, "virtual_time_s": 1157.246761, "measure_result": "direction", "svd_deg": 304.71}}
{"event": "action", "seq": 48, "wall_ts_ms": 1789097559532, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0048", "position": {"x": 1513.76371887733, "y": 579.5738004890592}, "channel": 18}, "response": {"accepted": true, "real_timestamp_ms": 1789097559532, "virtual_time_s": 1163.764349, "clear_result": "success"}}
{"event": "action", "seq": 49, "wall_ts_ms": 1789097559651, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0049", "position": {"x": 1200.0, "y": 0.0}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097559651, "virtual_time_s": 1301.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 50, "wall_ts_ms": 1789097559654, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0050", "position": {"x": 1200.0, "y": 0.0}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097559654, "virtual_time_s": 1307.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 51, "wall_ts_ms": 1789097559656, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0051", "position": {"x": 1200.0, "y": 0.0}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097559656, "virtual_time_s": 1313.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 52, "wall_ts_ms": 1789097559659, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0052", "position": {"x": 1200.0, "y": 0.0}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097559659, "virtual_time_s": 1319.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 53, "wall_ts_ms": 1789097559661, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0053", "position": {"x": 1200.0, "y": 0.0}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097559661, "virtual_time_s": 1325.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 54, "wall_ts_ms": 1789097559664, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0054", "position": {"x": 1200.0, "y": 0.0}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097559664, "virtual_time_s": 1331.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 55, "wall_ts_ms": 1789097559667, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0055", "position": {"x": 1200.0, "y": 0.0}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097559667, "virtual_time_s": 1337.575344, "measure_result": "direction", "svd_deg": 297.54}}
{"event": "action", "seq": 56, "wall_ts_ms": 1789097559682, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0056", "position": {"x": 1200.0, "y": 0.0}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097559682, "virtual_time_s": 1343.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 57, "wall_ts_ms": 1789097559687, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0057", "position": {"x": 1200.0, "y": 0.0}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097559687, "virtual_time_s": 1349.575344, "measure_result": "no_signal"}}
{"event": "action", "seq": 58, "wall_ts_ms": 1789097559827, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0058", "position": {"x": 1192.2027278108449, "y": -350.0560673308244}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097559827, "virtual_time_s": 1425.603923, "measure_result": "direction", "svd_deg": 315.51}}
{"event": "action", "seq": 59, "wall_ts_ms": 1789097559949, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0059", "position": {"x": 1579.4443151483792, "y": -732.0861531283488}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097559949, "virtual_time_s": 1539.397863, "measure_result": "direction", "svd_deg": 308.75}}
{"event": "action", "seq": 60, "wall_ts_ms": 1789097560079, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0060", "position": {"x": 1599.756957132486, "y": -758.3250236728769}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097560079, "virtual_time_s": 1551.034373, "measure_result": "direction", "svd_deg": 309.97}}
{"event": "action", "seq": 61, "wall_ts_ms": 1789097560080, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0061", "position": {"x": 1610.0853690933254, "y": -771.0954929815541}, "channel": 12}, "response": {"accepted": true, "real_timestamp_ms": 1789097560080, "virtual_time_s": 1559.319253, "clear_result": "success"}}
{"event": "action", "seq": 62, "wall_ts_ms": 1789097560208, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0062", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097560208, "virtual_time_s": 1774.333016, "measure_result": "direction", "svd_deg": 210.85}}
{"event": "action", "seq": 63, "wall_ts_ms": 1789097560222, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0063", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097560222, "virtual_time_s": 1780.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 64, "wall_ts_ms": 1789097560226, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0064", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097560226, "virtual_time_s": 1786.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 65, "wall_ts_ms": 1789097560230, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0065", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097560230, "virtual_time_s": 1792.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 66, "wall_ts_ms": 1789097560233, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0066", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097560233, "virtual_time_s": 1798.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 67, "wall_ts_ms": 1789097560236, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0067", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097560236, "virtual_time_s": 1804.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 68, "wall_ts_ms": 1789097560240, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0068", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097560240, "virtual_time_s": 1810.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 69, "wall_ts_ms": 1789097560242, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0069", "position": {"x": 600.0000000000001, "y": -1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097560242, "virtual_time_s": 1816.333016, "measure_result": "no_signal"}}
{"event": "action", "seq": 70, "wall_ts_ms": 1789097560389, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0070", "position": {"x": 548.4205541744728, "y": -749.0884755472262}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097560389, "virtual_time_s": 1881.271229, "measure_result": "direction", "svd_deg": 147.73}}
{"event": "action", "seq": 71, "wall_ts_ms": 1789097560511, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0071", "position": {"x": 626.7987000553718, "y": -661.6714058193344}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097560511, "virtual_time_s": 1909.753033, "measure_result": "direction", "svd_deg": 166.92}}
{"event": "action", "seq": 72, "wall_ts_ms": 1789097560513, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0072", "position": {"x": 260.33825092933466, "y": -574.1726350109003}, "channel": 5}, "response": {"accepted": true, "real_timestamp_ms": 1789097560513, "virtual_time_s": 1990.105351, "clear_result": "success"}}
{"event": "action", "seq": 73, "wall_ts_ms": 1789097560632, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0073", "position": {"x": 246.24176870568039, "y": -685.4655800184461}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097560632, "virtual_time_s": 2018.541777, "measure_result": "direction", "svd_deg": 217.69}}
{"event": "action", "seq": 74, "wall_ts_ms": 1789097560728, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0074", "position": {"x": 101.4809670295322, "y": -1057.528116723252}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097560728, "virtual_time_s": 2104.388185, "measure_result": "direction", "svd_deg": 237.95}}
{"event": "action", "seq": 75, "wall_ts_ms": 1789097560809, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0075", "position": {"x": -180.8231606416641, "y": -1506.673415466817}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097560809, "virtual_time_s": 2215.487595, "measure_result": "direction", "svd_deg": 53.15}}
{"event": "action", "seq": 76, "wall_ts_ms": 1789097560891, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0076", "position": {"x": -167.18396538240404, "y": -1489.1246807747386}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097560891, "virtual_time_s": 2224.932753, "measure_result": "direction", "svd_deg": 54.04}}
{"event": "action", "seq": 77, "wall_ts_ms": 1789097560893, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0077", "position": {"x": -160.74458223819045, "y": -1480.568461060665}, "channel": 1}, "response": {"accepted": true, "real_timestamp_ms": 1789097560893, "virtual_time_s": 2232.074477, "clear_result": "success"}}
{"event": "action", "seq": 78, "wall_ts_ms": 1789097560972, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0078", "position": {"x": 5.9157845288639805, "y": -871.6596394811392}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097560972, "virtual_time_s": 2364.335418, "measure_result": "direction", "svd_deg": 33.33}}
{"event": "action", "seq": 79, "wall_ts_ms": 1789097560974, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0079", "position": {"x": 13.593963995537074, "y": -866.4150648005227}, "channel": 8}, "response": {"accepted": true, "real_timestamp_ms": 1789097560974, "virtual_time_s": 2371.195095, "clear_result": "success"}}
{"event": "action", "seq": 80, "wall_ts_ms": 1789097561053, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0080", "position": {"x": -286.37408911397563, "y": -766.8255500189505}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097561053, "virtual_time_s": 2440.408671, "measure_result": "direction", "svd_deg": 207.25}}
{"event": "action", "seq": 81, "wall_ts_ms": 1789097561113, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0081", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097561113, "virtual_time_s": 2529.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 82, "wall_ts_ms": 1789097561117, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0082", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097561117, "virtual_time_s": 2535.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 83, "wall_ts_ms": 1789097561121, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0083", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561121, "virtual_time_s": 2541.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 84, "wall_ts_ms": 1789097561124, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0084", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097561124, "virtual_time_s": 2547.490717, "measure_result": "direction", "svd_deg": 165.82}}
{"event": "action", "seq": 85, "wall_ts_ms": 1789097561138, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0085", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097561138, "virtual_time_s": 2553.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 86, "wall_ts_ms": 1789097561141, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0086", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097561141, "virtual_time_s": 2559.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 87, "wall_ts_ms": 1789097561144, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0087", "position": {"x": -600.0000000000006, "y": -1039.230484541326}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097561144, "virtual_time_s": 2565.490717, "measure_result": "no_signal"}}
{"event": "action", "seq": 88, "wall_ts_ms": 1789097561223, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0088", "position": {"x": -821.4557486194155, "y": -1043.9702928641734}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097561223, "virtual_time_s": 2615.79201, "measure_result": "direction", "svd_deg": 21.12}}
{"event": "action", "seq": 89, "wall_ts_ms": 1789097561290, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0089", "position": {"x": -799.1301367753487, "y": -1034.893452384792}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097561290, "virtual_time_s": 2625.61206, "measure_result": "direction", "svd_deg": 20.37}}
{"event": "action", "seq": 90, "wall_ts_ms": 1789097561292, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0090", "position": {"x": -788.1496255408595, "y": -1030.5957631304852}, "channel": 20}, "response": {"accepted": true, "real_timestamp_ms": 1789097561292, "virtual_time_s": 2632.970379, "clear_result": "success"}}
{"event": "action", "seq": 91, "wall_ts_ms": 1789097561362, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0091", "position": {"x": -1067.9438619396667, "y": -719.4050934512866}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097561362, "virtual_time_s": 2722.666125, "measure_result": "direction", "svd_deg": 233.54000000000002}}
{"event": "action", "seq": 92, "wall_ts_ms": 1789097561363, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0092", "position": {"x": -1193.79864138515, "y": -889.3490379535914}, "channel": 10}, "response": {"accepted": true, "real_timestamp_ms": 1789097561363, "virtual_time_s": 2769.960508, "clear_result": "success"}}
{"event": "action", "seq": 93, "wall_ts_ms": 1789097561422, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0093", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097561422, "virtual_time_s": 2953.83464, "measure_result": "direction", "svd_deg": 163.42}}
{"event": "action", "seq": 94, "wall_ts_ms": 1789097561432, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0094", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097561432, "virtual_time_s": 2959.83464, "measure_result": "no_signal"}}
{"event": "action", "seq": 95, "wall_ts_ms": 1789097561439, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0095", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561439, "virtual_time_s": 2965.83464, "measure_result": "no_signal"}}
{"event": "action", "seq": 96, "wall_ts_ms": 1789097561442, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0096", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097561442, "virtual_time_s": 2971.83464, "measure_result": "no_signal"}}
{"event": "action", "seq": 97, "wall_ts_ms": 1789097561445, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0097", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097561445, "virtual_time_s": 2977.83464, "measure_result": "no_signal"}}
{"event": "action", "seq": 98, "wall_ts_ms": 1789097561449, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0098", "position": {"x": -1200.0, "y": 1.4695761589768238e-13}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097561449, "virtual_time_s": 2983.83464, "measure_result": "no_signal"}}
{"event": "action", "seq": 99, "wall_ts_ms": 1789097561517, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0099", "position": {"x": -1423.667553533217, "y": -173.2063353897658}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097561517, "virtual_time_s": 3046.412943, "measure_result": "direction", "svd_deg": 106.43}}
{"event": "action", "seq": 100, "wall_ts_ms": 1789097561519, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0100", "position": {"x": -1501.4366031905558, "y": 89.91826644321941}, "channel": 2}, "response": {"accepted": true, "real_timestamp_ms": 1789097561519, "virtual_time_s": 3106.288286, "clear_result": "success"}}
{"event": "action", "seq": 101, "wall_ts_ms": 1789097561576, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0101", "position": {"x": -905.3480310884979, "y": 1.476683864108395}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097561576, "virtual_time_s": 3232.811064, "measure_result": "direction", "svd_deg": 63.06}}
{"event": "action", "seq": 102, "wall_ts_ms": 1789097561578, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0102", "position": {"x": -805.596590259142, "y": 197.1442590697214}, "channel": 15}, "response": {"accepted": true, "real_timestamp_ms": 1789097561578, "virtual_time_s": 3281.736524, "clear_result": "success"}}
{"event": "action", "seq": 103, "wall_ts_ms": 1789097561616, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0103", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 6}, "response": {"accepted": true, "real_timestamp_ms": 1789097561616, "virtual_time_s": 3461.100784, "measure_result": "no_signal"}}
{"event": "action", "seq": 104, "wall_ts_ms": 1789097561619, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0104", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561619, "virtual_time_s": 3467.100784, "measure_result": "direction", "svd_deg": 102.88}}
{"event": "action", "seq": 105, "wall_ts_ms": 1789097561626, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0105", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 11}, "response": {"accepted": true, "real_timestamp_ms": 1789097561626, "virtual_time_s": 3473.100784, "measure_result": "no_signal"}}
{"event": "action", "seq": 106, "wall_ts_ms": 1789097561629, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0106", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 16}, "response": {"accepted": true, "real_timestamp_ms": 1789097561629, "virtual_time_s": 3479.100784, "measure_result": "no_signal"}}
{"event": "action", "seq": 107, "wall_ts_ms": 1789097561631, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0107", "position": {"x": -599.9999999999998, "y": 1039.2304845413264}, "channel": 17}, "response": {"accepted": true, "real_timestamp_ms": 1789097561631, "virtual_time_s": 3485.100784, "measure_result": "no_signal"}}
{"event": "action", "seq": 108, "wall_ts_ms": 1789097561691, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0108", "position": {"x": -468.74856219927324, "y": 1147.741683519248}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561691, "virtual_time_s": 3525.160508, "measure_result": "direction", "svd_deg": 119.34}}
{"event": "action", "seq": 109, "wall_ts_ms": 1789097561729, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0109", "position": {"x": -288.39506636259784, "y": 1099.5726385930388}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097561729, "virtual_time_s": 3568.495553, "measure_result": "direction", "svd_deg": 126.77}}
{"event": "action", "seq": 110, "wall_ts_ms": 1789097561753, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0110", "position": {"x": -231.41543619323764, "y": 1147.1056551785941}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097561753, "virtual_time_s": 3589.336127, "measure_result": "direction", "svd_deg": 118.26}}
{"event": "action", "seq": 111, "wall_ts_ms": 1789097561759, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0111", "position": {"x": -523.9735913338733, "y": 1413.4654346550624}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097561759, "virtual_time_s": 3674.465845, "measure_result": "direction", "svd_deg": 156.58}}
{"event": "action", "seq": 112, "wall_ts_ms": 1789097561761, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0112", "position": {"x": -529.9009483775656, "y": 1416.1573221581389}, "channel": 13}, "response": {"accepted": true, "real_timestamp_ms": 1789097561761, "virtual_time_s": 3680.767841, "clear_result": "success"}}
{"event": "action", "seq": 113, "wall_ts_ms": 1789097561765, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0113", "position": {"x": -497.5575661714986, "y": 1640.1638651043113}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097561765, "virtual_time_s": 3732.033734, "measure_result": "direction", "svd_deg": 294.96}}
{"event": "action", "seq": 114, "wall_ts_ms": 1789097561768, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0114", "position": {"x": -489.1226703393842, "y": 1622.842919408121}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097561768, "virtual_time_s": 3740.88685, "measure_result": "direction", "svd_deg": 293.48}}
{"event": "action", "seq": 115, "wall_ts_ms": 1789097561770, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0115", "position": {"x": -485.2642914202578, "y": 1614.3706024009493}, "channel": 14}, "response": {"accepted": true, "real_timestamp_ms": 1789097561770, "virtual_time_s": 3747.748755, "clear_result": "success"}}
{"event": "action", "seq": 116, "wall_ts_ms": 1789097561773, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0116", "position": {"x": -723.7252173218731, "y": 1600.2232732795474}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561773, "virtual_time_s": 3801.524799, "measure_result": "direction", "svd_deg": 102.92}}
{"event": "action", "seq": 117, "wall_ts_ms": 1789097561777, "method": "POST", "path": "/measure", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0117", "position": {"x": -728.399681602855, "y": 1619.0766264002268}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561777, "virtual_time_s": 3810.409639, "measure_result": "direction", "svd_deg": 102.9}}
{"event": "action", "seq": 118, "wall_ts_ms": 1789097561779, "method": "POST", "path": "/clear", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0118", "position": {"x": -730.7304567672215, "y": 1628.491328583946}, "channel": 9}, "response": {"accepted": true, "real_timestamp_ms": 1789097561779, "virtual_time_s": 3817.349424, "clear_result": "success"}}
{"event": "action", "seq": 119, "wall_ts_ms": 1789097561780, "method": "POST", "path": "/exit", "status": 200, "request": {"arena_id": "default", "robot_id": "1", "request_id": "b635af372db3-0119"}, "response": {"accepted": true, "real_timestamp_ms": 1789097561780, "virtual_time_s": 3817.349424, "exit_reason": "user_exit"}}
{"event": "session_end", "reason": "user_exit", "virtual_time_s": 3817.349424, "real_elapsed_s": 7.603792, "request_count": 119, "cleared_count": 16}
@@ -0,0 +1,136 @@
{
"case_code": "RM7Y-JRYA-9S7E-6J2T",
"module": "q3_practice",
"robot_id": "1",
"seed": 1539645273,
"truth": [
{
"channel": 18,
"x": 1514.5988909830828,
"y": 578.5437460895635,
"r_eff_m": 1242.5532543305198,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 15,
"x": -813.7264918366334,
"y": 184.45394380231278,
"r_eff_m": 1281.7579743845968,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 14,
"x": -483.3588607307586,
"y": 1609.042825940461,
"r_eff_m": 1261.397442029016,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 19,
"x": 484.25883869219865,
"y": 412.79231501032433,
"r_eff_m": 1403.135275873889,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 10,
"x": -1185.3432835076858,
"y": -882.5936176534458,
"r_eff_m": 1051.898596297638,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 7,
"x": 27.489354230125446,
"y": 597.1806051296936,
"r_eff_m": 1016.5786767252073,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 20,
"x": -786.2186502489933,
"y": -1030.2391402202422,
"r_eff_m": 1337.9526501887033,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 13,
"x": -528.7812163217789,
"y": 1415.4507846756549,
"r_eff_m": 1342.4148601109948,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 12,
"x": 1618.6469617181342,
"y": -780.4844715210944,
"r_eff_m": 1183.5031703982477,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 9,
"x": -730.8436887494869,
"y": 1629.1773460674606,
"r_eff_m": 1268.3689368990042,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 2,
"x": -1498.0608735557626,
"y": 84.22312468223669,
"r_eff_m": 1169.058568141951,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 3,
"x": 1278.1226595751832,
"y": 1262.0779642908842,
"r_eff_m": 1096.052626308773,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 8,
"x": 16.436633792518094,
"y": -864.8969376336956,
"r_eff_m": 1051.1924624749086,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 4,
"x": 86.92957139289182,
"y": 837.7240456106593,
"r_eff_m": 1472.5243578771838,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 5,
"x": 264.7412123726052,
"y": -576.0112311236278,
"r_eff_m": 1472.6387608455834,
"directional": false,
"heading_deg": 0.0
},
{
"channel": 1,
"x": -157.93200084817084,
"y": -1476.5943058247763,
"r_eff_m": 1381.0058509120777,
"directional": false,
"heading_deg": 0.0
}
]
}

Some files were not shown because too many files have changed in this diff Show More