A running mean is blind to alternation
The split is unanimous and one detail settles it: in two windows the eye travelled 0.0001m - a trackside camera standing perfectly still - and the pod stalled 15 and 29 times anyway. CameraShip::FollowGoal is exonerated, and so is the pan. It is the pod motion itself. That contradicts this trace only in appearance. It has been comparing each step against a RUNNING MEAN, and a running mean cannot see an alternating pattern: high, low, high, low averages to the mean and nothing ever looks anomalous. The renderer compares each frame against the PREVIOUS one, which catches exactly that, and counted 15 to 46 stalls in the same motion this trace called clean. So the mean test never ruled out uneven motion. It only ever ruled out drift. Apply the same consecutive test one level down, and keep twelve consecutive step lengths verbatim so the shape can be read rather than inferred from counters. Twelve steps is a quarter second at 50Hz - long enough to show a beat, short enough to fit on one line. The clock fix confirmed itself in passing: the reported intervals are now multiples of 17ms, the frame time, which is the honest resolution for a per-frame detector. The 1/32s artifact is gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -726,6 +726,11 @@ void
|
||||
static Scalar min_percent = 1.0f;
|
||||
static Scalar max_percent = 0.0f;
|
||||
static Scalar worst_error = 0.0f;
|
||||
static Scalar last_distance = 0.0f;
|
||||
static Scalar samples[12];
|
||||
static int sample_count = 0;
|
||||
static int seq_stalls = 0;
|
||||
static int seq_spikes = 0;
|
||||
|
||||
++steps;
|
||||
if (have_last)
|
||||
@@ -734,6 +739,43 @@ void
|
||||
moved.Subtract(localOrigin.linearPosition, last_pos);
|
||||
Scalar distance = moved.Length();
|
||||
|
||||
//
|
||||
// The same test the renderer applies to drawn frames:
|
||||
// this step against the one before it, not against a
|
||||
// running mean.
|
||||
//
|
||||
// A running mean is blind to an alternating pattern -
|
||||
// high, low, high, low averages to the mean and nothing
|
||||
// ever looks anomalous - which is why this trace has
|
||||
// been reporting zero spikes and zero stalls while the
|
||||
// renderer, comparing consecutive frames, counted
|
||||
// fifteen to forty-six stalls in the same motion. The
|
||||
// mean test only ever ruled out DRIFT.
|
||||
//
|
||||
if (distance < 50.0f)
|
||||
{
|
||||
if (last_distance > 0.001f)
|
||||
{
|
||||
Scalar sequential = distance / last_distance;
|
||||
|
||||
if (sequential < 0.4f) { ++seq_stalls; }
|
||||
else if (sequential > 2.5f) { ++seq_spikes; }
|
||||
}
|
||||
last_distance = distance;
|
||||
|
||||
//
|
||||
// And keep a few consecutive steps verbatim, so the
|
||||
// shape can be READ rather than inferred from
|
||||
// counters. Twelve steps is a quarter second at
|
||||
// 50Hz - long enough to show a beat, short enough
|
||||
// to fit one line.
|
||||
//
|
||||
if (sample_count < 12)
|
||||
{
|
||||
samples[sample_count++] = distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (distance > 50.0f)
|
||||
{
|
||||
mean_step = 0.0f; // respawn, not motion
|
||||
@@ -766,6 +808,15 @@ void
|
||||
<< "s worst miss " << worst_error << "s\n"
|
||||
<< std::flush;
|
||||
|
||||
DEBUG_STREAM << "CamLog: replicant sequence - "
|
||||
<< seq_stalls << " stall(s), " << seq_spikes
|
||||
<< " spike(s) against the PREVIOUS step; steps:";
|
||||
for (int s = 0; s < sample_count; s++)
|
||||
{
|
||||
DEBUG_STREAM << " " << samples[s];
|
||||
}
|
||||
DEBUG_STREAM << "\n" << std::flush;
|
||||
|
||||
DEBUG_STREAM << "CamLog: replicant arrivals - widest gap "
|
||||
<< widestGap << "s, " << longGapCount
|
||||
<< " long, " << queuedGapCount
|
||||
@@ -788,6 +839,9 @@ void
|
||||
min_percent = 1.0f;
|
||||
max_percent = 0.0f;
|
||||
worst_error = 0.0f;
|
||||
sample_count = 0;
|
||||
seq_stalls = 0;
|
||||
seq_spikes = 0;
|
||||
}
|
||||
{
|
||||
Scalar missed =
|
||||
|
||||
Reference in New Issue
Block a user