A running mean cannot keep up with a pod that is closing
The period trace came back with no period - intervals scattered from 0 to 2.5s - so the twenty-step renormalisation is not the culprit and neither is any other fixed cadence. That is a real answer, and it also exposed a fault in the instrument that produced it. The angular step varies six hundredfold across the samples, 0.12 mrad with the pod at 119m against 77 mrad at 5.4m. Judging each frame against a long running mean therefore reports the mean own lag as a lurch whenever the pod is closing, which is exactly what the window matching the reported symptom was doing: 26 lurches at 5.4m range, almost all of them measurement artifact. Compare each frame against the frame before it instead. Consecutive frames of a smooth pass are nearly equal however fast the sweep, so the ratio is immune to range, and a tick is specifically one frame that barely moves followed by one that catches up - so time the stalls, not the lurches. Also read renderStepFraction directly, per drawn frame, which should have been the first measurement taken. It is the number the interpolation actually uses. Sweeping smoothly from 0 to 1 means interpolation is working; pinned at 1 means the simulation is behind and every frame is drawing the same latest step, which is stepping at the physics rate no matter how clean the packets were. The camera station rasters the map and the gauges as well as the world, so falling behind is entirely plausible and would show here and nowhere else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+63
-6
@@ -1153,11 +1153,34 @@ void
|
||||
static int interval_count = 0;
|
||||
static int frames = 0;
|
||||
static int lurches = 0;
|
||||
static int stalls = 0;
|
||||
static Scalar last_angle = 0.0f;
|
||||
static Logical have_angle = False;
|
||||
static Scalar fraction_sum = 0.0f;
|
||||
static int pinned_high = 0;
|
||||
static int pinned_low = 0;
|
||||
|
||||
Vector3D dir;
|
||||
dir.Divide(to_pod, range);
|
||||
++frames;
|
||||
|
||||
//
|
||||
// How far through the physics step this frame is being
|
||||
// drawn. This is the number the interpolation actually
|
||||
// uses, so it is worth reading directly rather than
|
||||
// inferring from the picture. It should sweep smoothly
|
||||
// from 0 to 1 and wrap. Pinned at 1 means the
|
||||
// simulation is behind and interpolation has degenerated
|
||||
// to drawing the latest step over and over - which IS
|
||||
// stepping, at the physics rate, however smooth the
|
||||
// packets were.
|
||||
//
|
||||
Scalar fraction = myEntity->renderStepFraction;
|
||||
|
||||
fraction_sum += fraction;
|
||||
if (fraction > 0.99f) { ++pinned_high; }
|
||||
if (fraction < 0.01f) { ++pinned_low; }
|
||||
|
||||
if (have_last)
|
||||
{
|
||||
Scalar dot =
|
||||
@@ -1169,15 +1192,31 @@ void
|
||||
Scalar angle = (Scalar) acos((double) dot);
|
||||
|
||||
//
|
||||
// Only judge while the pod is actually crossing the
|
||||
// view. A pod held near the centre subtends almost
|
||||
// no angle and every ratio against it is noise.
|
||||
// Compare each frame against the frame BEFORE it,
|
||||
// not against a running mean. The angular step
|
||||
// varies six hundredfold between a pod at 119m and
|
||||
// the same pod at 5m, so a long mean cannot keep up
|
||||
// during a pass and reports its own lag as a lurch -
|
||||
// which is precisely what the previous version of
|
||||
// this trace did, in the one window that mattered.
|
||||
//
|
||||
if (mean_angle > 0.0002f)
|
||||
// Consecutive frames of a smooth pass are nearly
|
||||
// equal however fast the sweep, so their ratio is
|
||||
// immune to range. A tick is one frame that barely
|
||||
// moves followed by one that catches up, so the
|
||||
// stall is the event worth timing.
|
||||
//
|
||||
if (have_angle && last_angle > 0.00002f)
|
||||
{
|
||||
if (angle > mean_angle * 2.5f)
|
||||
Scalar ratio = angle / last_angle;
|
||||
|
||||
if (ratio > 2.5f)
|
||||
{
|
||||
++lurches;
|
||||
}
|
||||
else if (ratio < 0.4f)
|
||||
{
|
||||
++stalls;
|
||||
|
||||
Scalar now = (Scalar) Now();
|
||||
|
||||
@@ -1193,6 +1232,9 @@ void
|
||||
last_event = now;
|
||||
}
|
||||
}
|
||||
last_angle = angle;
|
||||
have_angle = True;
|
||||
|
||||
mean_angle = (mean_angle > 0.0f)
|
||||
? (mean_angle * 0.95f + angle * 0.05f)
|
||||
: angle;
|
||||
@@ -1205,21 +1247,36 @@ void
|
||||
if (next_say > 0.0f)
|
||||
{
|
||||
DEBUG_STREAM << "CamLog: on-screen motion - " << frames
|
||||
<< " frames, " << lurches << " lurch(es), period "
|
||||
<< " frames, " << stalls << " stall(s), "
|
||||
<< lurches << " lurch(es), period "
|
||||
<< ((interval_count > 0)
|
||||
? (interval_sum / interval_count)
|
||||
: 0.0f)
|
||||
<< "s (" << interval_min << ".." << interval_max
|
||||
<< "), mean step " << (mean_angle * 1000.0f)
|
||||
<< " mrad, range " << range << "m\n" << std::flush;
|
||||
|
||||
DEBUG_STREAM << "CamLog: render fraction - mean "
|
||||
<< ((frames > 0) ? (fraction_sum / frames) : 0.0f)
|
||||
<< ", " << pinned_high << " pinned at 1, "
|
||||
<< pinned_low << " at 0, of " << frames
|
||||
<< " frames ("
|
||||
<< ((pinned_high * 4 > frames)
|
||||
? "simulation is behind, interpolation degenerate"
|
||||
: "sweeping normally")
|
||||
<< ")\n" << std::flush;
|
||||
}
|
||||
next_say = ((Scalar) Now()) + 5.0f;
|
||||
frames = 0;
|
||||
lurches = 0;
|
||||
stalls = 0;
|
||||
interval_sum = 0.0f;
|
||||
interval_min = 1000.0f;
|
||||
interval_max = 0.0f;
|
||||
interval_count = 0;
|
||||
fraction_sum = 0.0f;
|
||||
pinned_high = 0;
|
||||
pinned_low = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user