summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/input/VelocityTracker.h7
-rw-r--r--libs/input/VelocityTracker.cpp57
2 files changed, 34 insertions, 30 deletions
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index f218c512e8..b58feac444 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -221,6 +221,13 @@ private:
static const nsecs_t HORIZON = 100 * 1000000; // 100 ms
float chooseWeight(int32_t pointerId, uint32_t index) const;
+ /**
+ * An optimized least-squares solver for degree 2 and no weight (i.e. `Weighting.NONE`).
+ * The provided container of movements shall NOT be empty, and shall have the movements in
+ * chronological order.
+ */
+ std::optional<float> solveUnweightedLeastSquaresDeg2(
+ const RingBuffer<Movement>& movements) const;
const uint32_t mDegree;
const Weighting mWeighting;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 150b68b9d2..38730dc966 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -413,7 +413,7 @@ void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t
LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree,
Weighting weighting)
: AccumulatingVelocityTrackerStrategy(HORIZON /*horizonNanos*/,
- false /*maintainHorizonDuringAdd*/),
+ true /*maintainHorizonDuringAdd*/),
mDegree(degree),
mWeighting(weighting) {}
@@ -589,16 +589,21 @@ static std::optional<float> solveLeastSquares(const std::vector<float>& x,
* Optimized unweighted second-order least squares fit. About 2x speed improvement compared to
* the default implementation
*/
-static std::optional<float> solveUnweightedLeastSquaresDeg2(const std::vector<float>& x,
- const std::vector<float>& y) {
- const size_t count = x.size();
- LOG_ALWAYS_FATAL_IF(count != y.size(), "Mismatching array sizes");
- // Solving y = a*x^2 + b*x + c
+std::optional<float> LeastSquaresVelocityTrackerStrategy::solveUnweightedLeastSquaresDeg2(
+ const RingBuffer<Movement>& movements) const {
+ // Solving y = a*x^2 + b*x + c, where
+ // - "x" is age (i.e. duration since latest movement) of the movemnets
+ // - "y" is positions of the movements.
float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+ const size_t count = movements.size();
+ const Movement& newestMovement = movements[count - 1];
for (size_t i = 0; i < count; i++) {
- float xi = x[i];
- float yi = y[i];
+ const Movement& movement = movements[i];
+ nsecs_t age = newestMovement.eventTime - movement.eventTime;
+ float xi = -age * SECONDS_PER_NANO;
+ float yi = movement.position;
+
float xi2 = xi*xi;
float xi3 = xi2*xi;
float xi4 = xi3*xi;
@@ -641,6 +646,20 @@ std::optional<float> LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po
return std::nullopt; // no data
}
+ uint32_t degree = mDegree;
+ if (degree > size - 1) {
+ degree = size - 1;
+ }
+
+ if (degree <= 0) {
+ return std::nullopt;
+ }
+
+ if (degree == 2 && mWeighting == Weighting::NONE) {
+ // Optimize unweighted, quadratic polynomial fit
+ return solveUnweightedLeastSquaresDeg2(movements);
+ }
+
// Iterate over movement samples in reverse time order and collect samples.
std::vector<float> positions;
std::vector<float> w;
@@ -649,34 +668,12 @@ std::optional<float> LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po
const Movement& newestMovement = movements[size - 1];
for (ssize_t i = size - 1; i >= 0; i--) {
const Movement& movement = movements[i];
-
nsecs_t age = newestMovement.eventTime - movement.eventTime;
- if (age > HORIZON) {
- break;
- }
positions.push_back(movement.position);
w.push_back(chooseWeight(pointerId, i));
time.push_back(-age * 0.000000001f);
}
- const size_t m = positions.size();
- if (m == 0) {
- return std::nullopt; // no data
- }
-
- // Calculate a least squares polynomial fit.
- uint32_t degree = mDegree;
- if (degree > m - 1) {
- degree = m - 1;
- }
-
- if (degree <= 0) {
- return std::nullopt;
- }
- if (degree == 2 && mWeighting == Weighting::NONE) {
- // Optimize unweighted, quadratic polynomial fit
- return solveUnweightedLeastSquaresDeg2(time, positions);
- }
// General case for an Nth degree polynomial fit
return solveLeastSquares(time, positions, w, degree + 1);
}