exp: 轮次33(上)——实际执行速度做成一等指标并自证;默认路径逐位复现第30轮,256题全部超VMAX
- rollout 逐题记录 max|Δq|/STEP(1.0=VMAX)与每步速度变化比;eval_cl 汇总 p50/p95/max、over_vmax_rate - 自证:用 round30_after trace 独立重算得 1.660004×VMAX、超速度占比 1.0,与新指标逐位一致 - 默认参数下 base 复现第30轮 after 的每个旧指标(0.57421875/0.390625/19.25/2.444952726/0.209975064 等) - 新开关 inc_cap(反馈叠加后再按每轴 VMAX·DT 限幅)、gap_margin(余量门限+自动抬宽相位 cap, 否则现 cap=0.5 会让 >0.5 的余量恒假);col 仍按 gap<=0 判真实碰撞,不与余量混用 - 只读核查:ik-policy.js:355 同样在 ±1·STEP 之后叠加反馈;JS 的 5 mm 余量是投影式护栏,非同机制 - 口径提醒:round30 plans['gaps'] 在 cap=0.5 截顶,不能据此算"≥1mm 占比";中位最小间隙 0.046 mm 可用 - 测试 26→30 项(限幅灵敏度、余量拒/受、cap 抬升生效)
This commit is contained in:
@@ -27,6 +27,7 @@ class EvalMetricsTest(unittest.TestCase):
|
||||
'travel': [6.0, 0.0, 8.0], 'brakes': [2.0, 4.0, 6.0],
|
||||
'start_fail': [False, True, False], 'goal_ratio_2s': [0.3, 0.9, 0.1],
|
||||
'err': [0.2, 200.0, 0.8], 'dls_it': [4, -1, 20],
|
||||
'speed_ratio': [1.66, 0.9, 1.2], 'accel_ratio': [0.3, 0.2, 0.5],
|
||||
}.items()}
|
||||
|
||||
def evaluate(self, tasks, bs=2, **kw):
|
||||
@@ -53,6 +54,12 @@ class EvalMetricsTest(unittest.TestCase):
|
||||
self.assertAlmostEqual(result['goal_ratio_2s'], 0.3, places=6)
|
||||
self.assertEqual(result['err_fail_med'], 200.0)
|
||||
self.assertEqual(result['brakes_mean'], 4.0)
|
||||
# 极值/分位按逐题值跨批汇总,不能进按 n 加权求均值的批聚合
|
||||
self.assertAlmostEqual(result['speed_ratio_p50'], 1.2, places=6)
|
||||
self.assertAlmostEqual(result['speed_ratio_p95'], 1.614, places=6)
|
||||
self.assertAlmostEqual(result['speed_ratio_max'], 1.66, places=5)
|
||||
self.assertAlmostEqual(result['over_vmax_rate'], 2 / 3, places=6) # 1.66 与 1.2 都算超 VMAX,0.9 不算
|
||||
self.assertAlmostEqual(result['accel_ratio_max'], 0.5, places=6)
|
||||
|
||||
def test_empty_conditional_metrics_and_explicit_limit(self):
|
||||
task = {**self.tasks[0], 'exec_s': None, 'travel': None}
|
||||
@@ -550,5 +557,59 @@ class SegmentCertificateTest(unittest.TestCase):
|
||||
(p.detach() - point).norm(dim=-1), atol=1e-8, rtol=0)
|
||||
|
||||
|
||||
class SpeedAndMarginTest(unittest.TestCase):
|
||||
"""轮次33:反馈叠加后的每轴速度限幅,以及安全层的正余量门限(含 cap 截顶坑)。"""
|
||||
STEP = [1.2, 1.2, 1.8, 1.8, 2.4, 3.6]
|
||||
|
||||
def rollout_one(self, teacher_step, gap_value, fb=None, **kwargs):
|
||||
class FlatKin:
|
||||
def clamp_box(self, q):
|
||||
return q
|
||||
|
||||
def gaps(self, q, cap):
|
||||
return {'gm': torch.full((q.shape[0], 49), float(gap_value))}
|
||||
|
||||
commit_n = 2
|
||||
traj = torch.zeros(1, commit_n + 1, 6)
|
||||
traj[0, 1:] = torch.tensor(teacher_step)[None].repeat(commit_n, 1).cumsum(0) # teacher_step = 每步各轴的度数增量
|
||||
patches = {
|
||||
'features': lambda *args: torch.zeros(1, 83),
|
||||
'goal_err': lambda kin, q, T, R: (torch.full((q.shape[0],), 10.0), torch.zeros(q.shape[0])),
|
||||
}
|
||||
with patch.multiple('ml.sim.closed_loop', **patches):
|
||||
with patch('ml.sim.closed_loop.dls_steps', return_value=torch.tensor([[[1.0, 0, 0, 0, 0, 0]]])):
|
||||
_, per = rollout(None, FlatKin(), [{'q0': [0] * 6, 'T': [10, 0, 0]}], 'cpu', K=1, safety=True,
|
||||
max_sec=0.02 * commit_n, return_traj=True, use_sub=False, select='first',
|
||||
oracle=TeacherOracle(traj), replan='empty', commit_n=commit_n,
|
||||
**kwargs)
|
||||
return per
|
||||
|
||||
def test_feedback_over_speed_is_measured_not_assumed(self):
|
||||
# 策略给满 STEP(J1 +1.2°)+ 2.2×1.0° 反馈 = 3.4° > VMAX·DT
|
||||
per = self.rollout_one([1.2, 0, 0, 0, 0, 0], 5.0, fb_gain=2.2)
|
||||
self.assertAlmostEqual(per['traj'][0, 1, 0].item(), 3.4, places=5)
|
||||
self.assertAlmostEqual(per['speed_ratio'][0].item(), 3.4 / 1.2, places=5)
|
||||
|
||||
def test_inc_cap_limits_actual_step_to_vmax(self):
|
||||
per = self.rollout_one([1.2, 0, 0, 0, 0, 0], 5.0, fb_gain=2.2, inc_cap=1)
|
||||
self.assertAlmostEqual(per['traj'][0, 1, 0].item(), 1.2, places=5)
|
||||
self.assertLessEqual(per['speed_ratio'][0].item(), 1.0 + 1e-6)
|
||||
|
||||
def test_margin_rejects_near_obstacle_step_that_passes_at_zero(self):
|
||||
moved = self.rollout_one([0.5, 0, 0, 0, 0, 0], 0.3, safety_partial=1)
|
||||
self.assertAlmostEqual(moved['traj'][0, -1, 0].item(), 1.0, places=5)
|
||||
self.assertEqual(moved['brakes'].item(), 0.0)
|
||||
braked = self.rollout_one([0.5, 0, 0, 0, 0, 0], 0.3, gap_margin=0.5, safety_partial=1)
|
||||
self.assertEqual(braked['brakes'].item(), 1.0)
|
||||
torch.testing.assert_close(braked['traj'], torch.zeros(1, 3, 6), rtol=0, atol=0)
|
||||
|
||||
def test_margin_below_cap_still_accepts_clear_step(self):
|
||||
# 余量 0.5 必须仍能通过 5 mm 间隙:若宽相位 cap 没抬到 margin+0.5,截顶值 0.5 会让门限恒假
|
||||
per = self.rollout_one([0.5, 0, 0, 0, 0, 0], 5.0, gap_margin=0.5, safety_partial=1)
|
||||
self.assertEqual(per['brakes'].item(), 0.0)
|
||||
self.assertAlmostEqual(per['traj'][0, -1, 0].item(), 1.0, places=5)
|
||||
self.assertTrue((per['plans']['gaps'] > 0.5).all().item())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user