exp: 端点进度选择——commit2 到达 52.1%/time_ok 35.2%(n=512),ratio2s 0.343→0.285;附带 50Hz 饥饿实测
- select='endpoint'(候选块末态离目标最近)优于 consist:n=512 到达 +1.3pp、time_ok +6.3pp、ratio −0.058 - 负结论:safety_try 1/2(41.4/44.9%)、K=4(47.3%)、DLS 兜底(52.3%/碰撞+1.1pp)、增益调度(47.3%) - JS Runner:endpoint 选择落地、冷启动跳前瞻;starveTicks 指标;commit2 平均空转 0.8–1.3 tick,commit3 可覆盖 - route40 endpoint:12/20 ok、13/20 到达、刹车 40.4%
This commit is contained in:
+26
-17
@@ -191,14 +191,14 @@ class Runner {
|
||||
this.o = Object.assign({ K: 8, commit: 3, margin: 5, /* 2026-10-18:运行时投影余量保持 5 mm(真机护栏,不迁就数据分布);数据侧另行过滤认证间隙 < 3 mm 的老师轨迹,APG 训练余量 3 mm */
|
||||
projMax: 0.5, refineMm: 5, arriveMm: 1, arriveDeg: 0.5,
|
||||
stuckPlans: 5, lockSec: 1.0, subReachDeg: 5, subTimeout: 1.5, subRule: 'cross', subLeadSec: 0.02, seed: 12345, lookahead: true,
|
||||
actScale: 1, certBudget: 40, safetyMs: 30, firstMs: 45, fbGain: 0, segCert: true }, opts || {});
|
||||
actScale: 1, certBudget: 40, safetyMs: 30, firstMs: 45, fbGain: 0, segCert: true, select: 'consist' }, opts || {});
|
||||
/* 2026-10-19:actScale = 模型 meta.act_scale(动作标签按 act_scale·STEP 归一化,旧模型 1);增量 = clamp(act, ±1)·actScale·STEP,
|
||||
与 ml/sim/closed_loop.py 同口径。subRule:'cross'(默认,越过顶点即切,与训练标签同口径;见 _subAdvance)/ 'timeout'(旧:< subReachDeg 或 subTimeout 超时)。 */ // 每条候选最多 40 次距离查询;安全层总预算 30 ms,第 1 条候选可用到 45 ms(超出按刹停处理)
|
||||
this.cert = makeCert(S, { leverTable: this.o.leverTable, cap: 20 });
|
||||
this.rng = makeRng(this.o.seed);
|
||||
/* 2026-10-18 第六轮(审查 B-1/B-2):耗时拆开记——inferMs 主推理、lookaheadMs 前瞻(第二次推理 + 8 份特征)、safetyMs 只含认证、
|
||||
planMs 整次规划(R9 口径:必须 < 60 ms 周期);certQ 每次规划新增的距离查询数,certHit 记忆命中数,certWhy 认证失败原因计数 */
|
||||
this.stats = { plans: 0, inferMs: [], lookaheadMs: [], safetyMs: [], planMs: [], planWarmMs: [], planColdMs: [], certQ: [], certHit: 0, certWhy: {}, brakes: 0, refine: 0, lookahead: 0, locks: 0, projected: 0, partial: 0 };
|
||||
this.stats = { plans: 0, inferMs: [], lookaheadMs: [], safetyMs: [], planMs: [], planWarmMs: [], planColdMs: [], certQ: [], certHit: 0, certWhy: {}, brakes: 0, refine: 0, lookahead: 0, locks: 0, projected: 0, partial: 0, starveTicks: 0 };
|
||||
this.reset(null);
|
||||
}
|
||||
reset(q0) {
|
||||
@@ -302,11 +302,14 @@ class Runner {
|
||||
async plan() {
|
||||
if (!this.needPlan()) return;
|
||||
this.planning = true;
|
||||
const qlen0 = this.queue.length; // 规划开始时队列里可执行步数
|
||||
const t = now(), c0 = this.cert.counters(), wasCold = this.cold; // 第八轮:冷启动(含前瞻)与稳态分开记,R9 判稳态
|
||||
try { await this._plan(); } finally {
|
||||
this.planning = false; this._until = undefined;
|
||||
const c1 = this.cert.counters();
|
||||
const dt = now() - t; this.stats.planMs.push(dt); (wasCold ? this.stats.planColdMs : this.stats.planWarmMs).push(dt); this.stats.certQ.push(c1.queries - c0.queries); this.stats.certHit += c1.hits - c0.hits;
|
||||
/* 50 Hz 饥饿估计:规划耗时 dt 期间每 20 ms 消耗一步;超过 qlen0 的步数即队列空转 tick */
|
||||
this.stats.starveTicks += Math.max(0, Math.ceil(dt / (DT * 1000)) - qlen0);
|
||||
}
|
||||
}
|
||||
async _plan() {
|
||||
@@ -344,27 +347,21 @@ class Runner {
|
||||
if (sb[12] > 0.5) { this.subs = [0, 1].map(v => this.q.map((x, j) => x + sb[v * 6 + j] * 180)); this.subPrev = this.q.slice(); }
|
||||
}
|
||||
/* 候选:去掉前缀后的提交步,投影,打分 */
|
||||
const cands = [], near = S.criticalPairs(qe, o.margin + 10).slice(0, 64);
|
||||
const cands = [], near = o.projMax > 0 ? S.criticalPairs(qe, o.margin + 10).slice(0, 64) : [];
|
||||
// 2026-10-20:全程目标反馈(与 ml/sim/closed_loop.py 的 fb_gain 一致)——一次 DLS,加到所有候选所有步
|
||||
const fbStep = (o.fbGain > 0 && this.goal) ? refineStep(S, qe, this.goal.T, this.goal.R, 0.3).dq : null;
|
||||
for (let k = 0; k < K; k++) {
|
||||
const inc = this._cand(out.act, k, r);
|
||||
if (fbStep) for (let s = 0; s < H; s++) for (let j = 0; j < 6; j++) inc[s][j] += o.fbGain * fbStep[j];
|
||||
let steps = inc.slice(r, r + o.commit), q = qe.slice();
|
||||
const adj = [];
|
||||
for (const d of steps) {
|
||||
let qn = q.map((v, j) => v + d[j]);
|
||||
let qp = project(S, qn, o.margin, o.projMax, near);
|
||||
/* 限位轴先夹到 LIM(与执行 clamp_box 同口径),否则候选会被认证的 inBox 整段拒绝 → 永远刹停 */
|
||||
qp = qp.map((v, j) => { const L = S.LIM[S.ORDER[j]]; return L.cont ? v : Math.max(L.lo, Math.min(L.hi, v)); });
|
||||
if (qp !== qn) this.stats.projected++;
|
||||
adj.push(qp.map((v, j) => v - q[j])); q = qp;
|
||||
}
|
||||
steps = adj;
|
||||
const steps = inc.slice(r, r + o.commit); // 先不投影;只对进入认证的候选投影(2026-10-20:投影 8 份候选占安全层 ~13 ms)
|
||||
const fut = []; let qq = qe.slice(); for (let s = r; s < H; s++) { qq = qq.map((v, j) => v + inc[s][j]); fut.push(qq); }
|
||||
let j1 = 0; for (let s = 0; s < H; s++) j1 += inc[s][0];
|
||||
let score = -2.0 * out.value[k];
|
||||
if (this.lastPlan) { // 与上一条已选计划的未来重叠步对齐:lastPlan[i] = 旧 qe 走 i 步,新 qe = lastPlan[commit],fut[s] 对应 lastPlan[s+commit+1]
|
||||
if (o.select === 'endpoint') {
|
||||
/* 2026-10-20:端点进度选择(与 ml/sim/closed_loop.py select='endpoint' 同口径)——n=512 时间效率 29→35%、ratio2s 0.343→0.285 */
|
||||
const qa = fut[fut.length - 1], pe = S.fk(qa, 0);
|
||||
score = -Math.hypot(pe[0] - this.goal.T[0], pe[1] - this.goal.T[1], pe[2] - this.goal.T[2]);
|
||||
} else if (this.lastPlan) { // 与上一条已选计划的未来重叠步对齐:lastPlan[i] = 旧 qe 走 i 步,新 qe = lastPlan[commit],fut[s] 对应 lastPlan[s+commit+1]
|
||||
// 2026-10-19 修错位(原对齐 lastPlan[s+commit],奖励比上一计划慢一步的候选;Python closed_loop.py 同步修正)
|
||||
let c = 0, w = 1;
|
||||
for (let s = 0; s < fut.length && s + o.commit + 1 < this.lastPlan.length; s++, w *= 0.85) {
|
||||
@@ -387,7 +384,7 @@ class Runner {
|
||||
/* 短前瞻:冷启动(新目标 / 目标跳变)时,各候选块末态再推一块,用其价值打分。
|
||||
2026-10-18 第六轮:去掉"卡死时也前瞻"——与仿真 ml/sim/closed_loop.py(只在首块前瞻)对齐;
|
||||
前瞻要算 8 份特征(8 次 gapMatrix cap40,沙箱 Node 实测 P99 126 ms),卡死时再做会让整次规划连续超周期。卡死由换向锁处理。 */
|
||||
if (o.lookahead && this.cold) {
|
||||
if (o.lookahead && this.cold && o.select !== 'endpoint') {
|
||||
this.stats.lookahead++;
|
||||
const feat2 = new Float32Array(pool.length * F_DIM), z2 = new Float32Array(pool.length * H * 6);
|
||||
pool.forEach((c, i) => {
|
||||
@@ -410,7 +407,19 @@ class Runner {
|
||||
for (const c of pool) {
|
||||
if (c !== pool[0] && now() - t1 > o.safetyMs) break;
|
||||
this._until = t1 + (c === pool[0] ? Math.max(o.firstMs, o.safetyMs) : o.safetyMs);
|
||||
const v = this._certCommit(qe, c.steps, true);
|
||||
let steps = c.steps;
|
||||
if (o.projMax > 0) { // 投影只做给要认证的候选(按需),不再对全部 K 条预算
|
||||
const adj = []; let q = qe.slice();
|
||||
for (const d of c.steps) {
|
||||
const qn = q.map((v, j) => v + d[j]);
|
||||
let qp = project(S, qn, o.margin, o.projMax, near);
|
||||
qp = qp.map((v, j) => { const L = S.LIM[S.ORDER[j]]; return L.cont ? v : Math.max(L.lo, Math.min(L.hi, v)); });
|
||||
if (qp !== qn) this.stats.projected++;
|
||||
adj.push(qp.map((v, j) => v - q[j])); q = qp;
|
||||
}
|
||||
steps = adj;
|
||||
}
|
||||
const v = this._certCommit(qe, steps, true);
|
||||
if (v.ok) { picked = c; pickedSteps = v.steps; this.brakeTail = v.tail; break; }
|
||||
}
|
||||
this._until = undefined;
|
||||
|
||||
Reference in New Issue
Block a user