docs: say that HrtRateFit::toSeconds returns producer-epoch, not wall, seconds

The fit keeps the slope and discards the intercept, so the result counts from
the producer's boot. Tasks 4 and 7 compose it with ClockOffset::map, which is
correct, but the bare name invites passing it straight to a plot axis.

Also unwrapped the stalled-clock assertion from behind `if (fit.ready())` —
that branch never runs, so the test confirmed nothing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino Ferrari
2026-08-27 19:55:24 +02:00
co-authored by Claude Opus 4.6
parent e4817dd284
commit c89decef8e
2 changed files with 15 additions and 4 deletions
+9
View File
@@ -63,6 +63,15 @@ public:
void add(uint64_t hrt, double wallSec); void add(uint64_t hrt, double wallSec);
bool ready() const { return n_ >= kMinSamples && rate_ > 0.0; } bool ready() const { return n_ >= kMinSamples && rate_ > 0.0; }
double ticksPerSecond() const { return rate_; } double ticksPerSecond() const { return rate_; }
/**
* @brief Converts a tick count to seconds on the PRODUCER's own epoch.
*
* The fit recovers the slope only and discards the intercept, so this is
* `hrt / ticksPerSecond()` — not a wall-clock time. A producer's hrt counts
* from its own boot, not from the Unix epoch. Pass the result to
* ClockOffset::map() to land it on the wall clock; latching that arbitrary
* epoch difference is precisely what ClockOffset is for.
*/
double toSeconds(uint64_t hrt) const; double toSeconds(uint64_t hrt) const;
void reset(); void reset();
+6 -4
View File
@@ -102,10 +102,12 @@ TEST(HrtRateFit, SurvivesAStalledClock) {
for (int i = 0; i < 64; i++) { for (int i = 0; i < 64; i++) {
fit.add(12345u, 1000.0 + i * 0.01); /* hrt never advances */ fit.add(12345u, 1000.0 + i * 0.01); /* hrt never advances */
} }
/* A degenerate fit must not produce a rate that would divide by zero. */ /* A degenerate fit must not produce a rate that would divide by zero, so it
if (fit.ready()) { * must decline to be ready at all. Guarding this behind `if (fit.ready())`
EXPECT_GT(fit.ticksPerSecond(), 0.0); * would make the test vacuous: the branch never runs and a fit that
} * declared itself ready with a rate of 0 or NaN would pass unnoticed. */
EXPECT_FALSE(fit.ready());
EXPECT_DOUBLE_EQ(fit.ticksPerSecond(), 0.0);
} }
TEST(TimeSignalScale, UsesNanosecondsForUint64AndMicrosecondsOtherwise) { TEST(TimeSignalScale, UsesNanosecondsForUint64AndMicrosecondsOtherwise) {