Ask whether the pod stalled or the pan did

Two things are now ruled out with evidence rather than argument.

Render interpolation is healthy. behind is computed by Time::operator-,
which subtracts ticks and only then converts to float, so it carries the
clock full millisecond precision. With a 20ms step that gives the
fraction twenty possible values, and the measured 17 frames of 293 sitting
at zero is 5.8% against the 5% a sawtooth crossing zero would produce by
itself. Mean 0.474, never once pinned at 1: it is sweeping correctly.

And the trace period was never a period. Every interval it reported -
0.03125, 0.125, 0.375, 1.90625 - is a multiple of 1/32s, which is the
spacing of a float32 near 474196. That is this machine uptime in seconds,
because GetRTC returns QueryPerformanceCounter scaled to milliseconds
since boot, so (Scalar) Now() is a number near half a million and its
resolution has decayed to 31ms - coarser than the physics step it is being
used to time. The stall COUNT is unaffected and real, at three to five a
second; the interval between them was measurement noise. Logged separately
as its own defect.

What is left is that the angle is measured BETWEEN the pod and the eye,
so a hitch in the pan reads exactly like a hitch in the pod - and the
symptom is a pod moving PAST, which is when the pan rate peaks. Measure
each one on its own, by the same consecutive-frame ratio, and let the
trace say which.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-11 09:24:09 -05:00
co-authored by Claude Opus 5
parent 9c886efd8d
commit 5cd9783d38
+71
View File
@@ -1159,11 +1159,68 @@ void
static Scalar fraction_sum = 0.0f;
static int pinned_high = 0;
static int pinned_low = 0;
static Point3D last_pod(0.0f, 0.0f, 0.0f);
static Point3D last_eye(0.0f, 0.0f, 0.0f);
static Logical have_pod = False;
static Scalar last_pod_step = 0.0f;
static Scalar last_eye_step = 0.0f;
static Scalar eye_travel = 0.0f;
static int pod_stalls = 0;
static int eye_stalls = 0;
Vector3D dir;
dir.Divide(to_pod, range);
++frames;
//
// Split the pod's motion from the camera's.
//
// The angle above is measured BETWEEN the two, so a
// hitch in the pan and a hitch in the pod are the same
// reading - and the symptom is specifically a pod moving
// past, which is when the pan rate peaks. Measuring each
// on its own says which one to go and fix.
//
// Same ratio test as the angle, and for the same reason:
// consecutive frames of smooth motion are near equal
// whatever the speed.
//
Point3D pod_now;
pod_now.x = renderToWorld(3,0);
pod_now.y = renderToWorld(3,1);
pod_now.z = renderToWorld(3,2);
if (have_pod)
{
Vector3D pod_moved;
pod_moved.Subtract(pod_now, last_pod);
Vector3D eye_moved;
eye_moved.x = gEyeWorld.x - last_eye.x;
eye_moved.y = gEyeWorld.y - last_eye.y;
eye_moved.z = gEyeWorld.z - last_eye.z;
Scalar pod_step = pod_moved.Length();
Scalar eye_step = eye_moved.Length();
if (last_pod_step > 0.0001f && pod_step < last_pod_step * 0.4f)
{
++pod_stalls;
}
if (last_eye_step > 0.0001f && eye_step < last_eye_step * 0.4f)
{
++eye_stalls;
}
last_pod_step = pod_step;
last_eye_step = eye_step;
eye_travel += eye_step;
}
last_pod = pod_now;
last_eye.x = gEyeWorld.x;
last_eye.y = gEyeWorld.y;
last_eye.z = gEyeWorld.z;
have_pod = True;
//
// How far through the physics step this frame is being
// drawn. This is the number the interpolation actually
@@ -1265,6 +1322,17 @@ void
? "simulation is behind, interpolation degenerate"
: "sweeping normally")
<< ")\n" << std::flush;
DEBUG_STREAM << "CamLog: motion split - pod "
<< pod_stalls << " stall(s), eye "
<< eye_stalls << " stall(s), eye travelled "
<< eye_travel << "m, verdict "
<< ((pod_stalls > eye_stalls * 2)
? "the pod"
: ((eye_stalls > pod_stalls * 2)
? "the camera"
: "both, or neither"))
<< "\n" << std::flush;
}
next_say = ((Scalar) Now()) + 5.0f;
frames = 0;
@@ -1277,6 +1345,9 @@ void
fraction_sum = 0.0f;
pinned_high = 0;
pinned_low = 0;
pod_stalls = 0;
eye_stalls = 0;
eye_travel = 0.0f;
}
}
}