59 lines
2.3 KiB
C++
59 lines
2.3 KiB
C++
#pragma once
|
|
#include <plot/core/types.hpp>
|
|
#include <plot/data/series.hpp>
|
|
|
|
namespace plot {
|
|
|
|
/// Interval statistics over the half-open sample range [begin, end).
|
|
///
|
|
/// `dx` is the x distance between the first and the last sample of the interval
|
|
/// (0 for a single-sample interval), `dy` the corresponding y difference,
|
|
/// `slope` = `dy / dx`, `mean` and `rms` over the `end - begin` samples, `ymin`
|
|
/// / `ymax` the exact extremes, and `integral` the area under the samples.
|
|
///
|
|
/// `integral` is deliberately a LEFT-RIEMANN sum, `sum(begin, end) * dx`: the
|
|
/// series' samples are taken as the value at the left edge of each step. A
|
|
/// trapezoid rule would be equally defensible and compute a different number for
|
|
/// every reported interval, so this choice is part of the result's contract, not
|
|
/// an implementation detail. Do not "fix" it without changing every documented
|
|
/// value and every test that pins one.
|
|
///
|
|
/// `valid` is false (and every field zero) for an interval that is empty,
|
|
/// inverted or out of range; such a call never reads the series.
|
|
struct Measurement {
|
|
f64 dx = 0.0;
|
|
f64 dy = 0.0;
|
|
f64 slope = 0.0;
|
|
f64 rms = 0.0;
|
|
f64 mean = 0.0;
|
|
f64 ymin = 0.0;
|
|
f64 ymax = 0.0;
|
|
f64 integral = 0.0;
|
|
bool valid = false;
|
|
};
|
|
|
|
/// The cursor pair a measure spans, as the plot stored it. `valid` is false for
|
|
/// an id that names no measure and for a measure whose cursors are not both
|
|
/// registered, so a caller can tell "no band to shade" from "a band between
|
|
/// cursors 0 and 0". The renderer uses it to place the band a measurement's
|
|
/// readout belongs to.
|
|
struct MeasureSpan {
|
|
u32 cursor_a = 0;
|
|
u32 cursor_b = 0;
|
|
bool valid = false;
|
|
};
|
|
|
|
/// Stateless interval measurement over a data::Series.
|
|
struct Measure {
|
|
/// Evaluates [begin, end). Every quantity comes from `Series::reduce`/`sum`/
|
|
/// `sumsq` -- never from the pyramid's `*_buckets` forms, which exclude partial
|
|
/// edge buckets and would silently return wrong extrema and sums for a range
|
|
/// that is not bucket-aligned. Each of those queries is O(kBucket) worst case
|
|
/// (bucket-aligned interior from the pyramid, at most two partial edge buckets
|
|
/// read raw), so a measurement never scans the series and its cost does not
|
|
/// grow with series length.
|
|
static Measurement evaluate(const data::Series& s, u64 begin, u64 end);
|
|
};
|
|
|
|
} // namespace plot
|