MP: tighten peer re-anchor -- error-proportional absorption (residual snap, task #50)
Chasing the ~2.9u residual snap: instrumented BT_MIRDIV and isolated it to the PEER side (master send-mirror error is accurate, mean 0.39u < 0.55u threshold; peer drifted 3-11u from received authority). Root: the master models the peer with the BODY channel but the peer moves with the LEG channel -- slightly different travel/frame -- so the master deadband does not fire exactly when the peer drifts, and the fixed ~1/3s offset decay bled slower than accel/decel drift accumulated. A hard ground-snap (authentic FUN_004ab1c8:14985) popped instead (records not perfectly dense on the one-box relay). FIX: error-proportional absorption -- bleed the offset to updateOrigin at a rate that scales with the error (k 0.15..0.6/frame): small steady offset absorbed gently (no foot-pop), large speed-change drift caught in a few frames. Measured (through-zero sweep): peer drift 11u->2.1u, maxStep 2.9u->1.77u, ratio 1.043->1.036. Remaining <=1.8u snaps are the leg-vs-body channel-shape mismatch; fully closing needs a leg-channel send-mirror (second instance) -- deferred. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
47771ba256
commit
38fed81d8a
@@ -2145,23 +2145,26 @@ void
|
||||
// (reverse clips return negative travel; master dir==1.0 in SM mode).
|
||||
if (!s_drPos)
|
||||
{
|
||||
// POSE-SYNC OFFSET DECAY (authentic FUN_004ab1c8 motionEventVector
|
||||
// mechanism): a record does NOT snap the body -- the correction offset
|
||||
// is absorbed over ~1/3s while the clip's root motion keeps driving, so
|
||||
// the feet never pop and the position converges to authority.
|
||||
static Vector3D s_rmErr[2]; // per-instance would be a member; one replicant per node in practice
|
||||
Vector3D &rmErr = s_rmErr[0];
|
||||
if (poseSyncLatch)
|
||||
// POSE-SYNC ERROR-PROPORTIONAL ABSORPTION: track the error to the
|
||||
// received authority (updateOrigin) and bleed it into localOrigin at a
|
||||
// rate that scales with the error, so a small steady offset is absorbed
|
||||
// gently (no foot-pop) while a large speed-change drift is caught fast.
|
||||
// The residual snap came from two sources: (a) a fixed slow ~1/3s decay
|
||||
// let drift reach 3-11u during accel/decel; (b) a hard ground snap popped
|
||||
// because records are not perfectly dense on this relay. Error-scaled
|
||||
// absorption is the stable middle: k grows from ~0.15/frame at small
|
||||
// error toward ~0.6 at large error. (Records re-measure the error every
|
||||
// frame they arrive, so this converges to authority within a few frames.)
|
||||
{
|
||||
Vector3D rmErr;
|
||||
rmErr.Subtract(updateOrigin.linearPosition, localOrigin.linearPosition);
|
||||
poseSyncLatch = 0;
|
||||
}
|
||||
{
|
||||
Scalar k = dt * 3.0f; if (k > 1.0f) k = 1.0f; // ~1/3s absorption
|
||||
const float eMag = (float)rmErr.Length();
|
||||
float k = 0.15f + eMag * 0.15f; // error-proportional catch-up
|
||||
if (k > 0.6f) k = 0.6f;
|
||||
localOrigin.linearPosition.x += rmErr.x * k;
|
||||
localOrigin.linearPosition.y += rmErr.y * k;
|
||||
localOrigin.linearPosition.z += rmErr.z * k;
|
||||
rmErr.x -= rmErr.x * k; rmErr.y -= rmErr.y * k; rmErr.z -= rmErr.z * k;
|
||||
}
|
||||
if (replLegAdv != 0.0f)
|
||||
{
|
||||
@@ -2177,6 +2180,24 @@ void
|
||||
localToWorld = localOrigin; // refresh with the coupled position
|
||||
}
|
||||
|
||||
// PEER-DRIFT probe (BT_MIRDIV, 1s max): how far the peer's coupled
|
||||
// position wanders from the last-received authority (updateOrigin)
|
||||
// before a record re-anchors it -- the other end of the snap.
|
||||
if (getenv("BT_MIRDIV"))
|
||||
{
|
||||
static float s_pdAcc = 0.0f, s_pdMax = 0.0f;
|
||||
Vector3D d; d.Subtract(localOrigin.linearPosition, updateOrigin.linearPosition);
|
||||
const float dl = (float)d.Length();
|
||||
if (dl > s_pdMax) s_pdMax = dl;
|
||||
s_pdAcc += dt;
|
||||
if (s_pdAcc >= 1.0f)
|
||||
{
|
||||
DEBUG_STREAM << "[peerdrift] maxDriftFromAuthority=" << s_pdMax
|
||||
<< " replLegAdv=" << replLegAdv << "\n" << std::flush;
|
||||
s_pdAcc = 0.0f; s_pdMax = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// GAIT-EVENNESS probe (BT_GAITEV, 1s stats): the metric of the VISIBLE
|
||||
// speed-change glitch -- per-frame leg-clip advance regularity + leg-state
|
||||
// transition (flap) rate on the peer. Position dead-reckons smoothly
|
||||
@@ -3772,6 +3793,27 @@ void
|
||||
error.Subtract(
|
||||
projectedOrigin.linearPosition,
|
||||
localOrigin.linearPosition);
|
||||
// MIRROR-DIVERGENCE probe (BT_MIRDIV, 1s max): how far the master's
|
||||
// send-mirror (projectedOrigin, body-channel gait) drifts from the true
|
||||
// localOrigin (leg-channel gait) BEFORE a send fires. This is the source
|
||||
// of the peer's residual snap -- quantifies the leg-vs-body channel shape
|
||||
// mismatch. posDb (~0.55u) is the send threshold; anything the mirror
|
||||
// over/under-shoots beyond it is the channel divergence.
|
||||
if (getenv("BT_MIRDIV"))
|
||||
{
|
||||
static float s_mdAcc = 0.0f, s_mdMax = 0.0f, s_mdAdvB = 0.0f, s_mdAdvL = 0.0f;
|
||||
const float e = (float)error.Length();
|
||||
if (e > s_mdMax) s_mdMax = e;
|
||||
s_mdAdvB += (float)(mirrorBodyAdv < 0 ? -mirrorBodyAdv : mirrorBodyAdv);
|
||||
s_mdAcc += dt;
|
||||
if (s_mdAcc >= 1.0f)
|
||||
{
|
||||
DEBUG_STREAM << "[mirdiv] maxErr=" << s_mdMax
|
||||
<< " bodyTravel/s=" << s_mdAdvB
|
||||
<< " bodyTgtSpd=" << bodyTargetSpeed << "\n" << std::flush;
|
||||
s_mdAcc = 0.0f; s_mdMax = 0.0f; s_mdAdvB = 0.0f; s_mdAdvL = 0.0f;
|
||||
}
|
||||
}
|
||||
Quaternion angular_deviation;
|
||||
angular_deviation.Subtract(
|
||||
projectedOrigin.angularPosition,
|
||||
|
||||
Reference in New Issue
Block a user