22 static constexpr size_t value = 1;
25template <glm::length_t L,
typename U, glm::qualifier Q>
27 static constexpr size_t value =
static_cast<size_t>(L);
42 if constexpr (GlmType<T>) {
43 using Comp = glm_component_type<T>;
45 for (
size_t i = 0; i < estimate_component_count_v<T>; ++i)
46 result[
static_cast<glm::length_t
>(i)] =
static_cast<Comp
>(components[i]);
49 return static_cast<T
>(components[0]);
57[[nodiscard]]
inline std::array<double, estimate_component_count_v<T>>
read_components(
const T&
value)
noexcept
59 std::array<double, estimate_component_count_v<T>> out {};
60 if constexpr (GlmType<T>) {
61 for (
size_t i = 0; i < estimate_component_count_v<T>; ++i)
62 out[i] =
static_cast<double>(
value[
static_cast<glm::length_t
>(i)]);
64 out[0] =
static_cast<double>(
value);
128 double adapt_rate = 0.05,
129 size_t history_capacity = 8)
133 m_estimates.emplace_back(model, adapt_rate, window);
143 void update(
const T& raw_sample,
double dt)
148 std::array<double, component_count> clean_components {};
153 const T clean = assemble_from_components<T>(clean_components);
156 if constexpr (std::is_same_v<T, glm::vec2>) {
160 if constexpr (std::is_same_v<T, glm::vec3>) {
189 return cached->second.value;
195 result = it->second->accept(raw);
213 void filter_order(
size_t order,
size_t window = 8,
double threshold_mad = 3.5,
214 size_t max_consecutive_rejections = 3)
216 m_filters[order] = std::make_unique<HampelFilter<T>>(window, threshold_mad, max_consecutive_rejections);
240 return it ==
m_filters.end() ? nullptr : it->second.get();
259 requires std::is_same_v<T, glm::vec2>
261 m_trajectory_2d = std::make_unique<SymbolicTrajectory<Lattice2D, glm::uvec2>>(lattice, window);
272 requires std::is_same_v<T, glm::vec3>
274 m_trajectory_3d = std::make_unique<SymbolicTrajectory<Lattice3D, glm::uvec3>>(lattice, window);
281 requires std::is_same_v<T, glm::vec2>
290 requires std::is_same_v<T, glm::vec3>
307 std::map<size_t, std::unique_ptr<HampelFilter<T>>>
m_filters;
334 const glm::vec2 vel = channel.
derivative<1>();
335 const glm::vec2 accel = channel.
derivative<2>();
337 const glm::vec2 floor_vec {
341 const auto dt =
static_cast<float>(channel.
last_dt());
342 const float min_speed = (dt > 0.0F) ? (glm::length(floor_vec) / dt) : 0.0F;
#define N(method_name, full_type_name)
Holds the last accepted value when a new sample looks like an isolated outlier relative to its recent...
void update(const T &raw_sample, double dt)
Feed one raw sample, denoise it, and push the cleaned value.
Memory::HistoryBuffer< T > m_history
MotionChannel(Stochastic::EstimateModel model, size_t window, double adapt_rate=0.05, size_t history_capacity=8)
Construct a channel.
void enable_trajectory_3d(Lattice3D lattice, size_t window=16)
Enable symbolic trajectory tracking over a 3D lattice.
std::vector< Stochastic::Estimate > m_estimates
SymbolicTrajectory< Lattice2D, glm::uvec2 > * trajectory_2d()
Direct access to the 2D trajectory, or nullptr if not enabled.
void enable_trajectory_2d(Lattice2D lattice, size_t window=16)
Enable symbolic trajectory tracking over a 2D lattice.
std::unique_ptr< SymbolicTrajectory< Lattice3D, glm::uvec3 > > m_trajectory_3d
double last_dt() const
dt passed to the most recent update() call
std::unique_ptr< SymbolicTrajectory< Lattice2D, glm::uvec2 > > m_trajectory_2d
std::map< size_t, std::unique_ptr< HampelFilter< T > > > m_filters
Memory::HistoryBuffer< T > & history()
Direct access to the underlying HistoryBuffer.
SymbolicTrajectory< Lattice3D, glm::uvec3 > * trajectory_3d()
Direct access to the 3D trajectory, or nullptr if not enabled.
void filter_order(size_t order, size_t window=8, double threshold_mad=3.5, size_t max_consecutive_rejections=3)
Configure Hampel screening for one derivative order.
static constexpr size_t component_count
HampelFilter< T > * filter_for_order(size_t order)
Direct access to a configured filter, or nullptr if that order has no filter configured.
T derivative()
Compute the N-th derivative, routed through a configured HampelFilter for that order if one exists.
Stochastic::Estimate & estimate_for_component(size_t component)
Direct access to one component's Estimate instance.
std::map< size_t, DerivativeCacheEntry > m_derivative_cache
Wires Estimate, Differential, and HampelFilter for one stream without hiding any of them.
double floor() const
Current learned floor.
Stateful statistical characterization of an evolving scalar stream.
Tracks a moving point's sequence of cells through a lattice partition over time.
History buffer for difference equations and recursive relations.
EstimateModel
Strategies for characterizing an evolving stream's statistical behavior.
constexpr size_t estimate_component_count_v
float channel_curvature(MotionChannel< glm::vec2 > &channel)
Curvature helper for MotionChannel<glm::vec2>, self-calibrating its min_speed guard from the channel'...
float curvature(const glm::vec2 &vel, const glm::vec2 &accel, float min_speed=1e-3F) noexcept
Signed curvature from velocity and acceleration.
std::array< double, estimate_component_count_v< T > > read_components(const T &value) noexcept
Read T's components into an array of doubles.
T assemble_from_components(const std::array< double, estimate_component_count_v< T > > &components) noexcept
Assemble a scalar or vector T from N doubles.
A regular subdivision of an AABB2D into a cell count per axis.
A regular subdivision of an AABB3D into a cell count per axis.
One memoized derivative<N>() result, tagged by the update() generation it was computed for.
static constexpr size_t value
Number of scalar components Estimate must independently track for T.