diff options
author | Siarhei Vishniakou <svv@google.com> | 2018-09-07 16:38:18 -0700 |
---|---|---|
committer | Siarhei Vishniakou <svv@google.com> | 2018-10-01 15:35:09 -0500 |
commit | f7e2d3e6bd6b832fe949eb368f71756631fe808c (patch) | |
tree | d79e7ee685d4922234285fda52e49bcff6b5e15e | |
parent | 1f4bf704979ec355ec65a3115dc6b7529bbb3fcd (diff) | |
download | native-f7e2d3e6bd6b832fe949eb368f71756631fe808c.tar.gz |
Native tests for VelocityTracker::getEstimate
Earlier commit broke VelocityTracker::getEstimate, which also broke
pointer location. In additional VelocityTracker::getEstimate is an @hide
api that could be potentially accessed by app.
Add native tests for getEstimate (and specifically, for the currently
used LeastSquares lsq2 strategy) to prevent future regressions.
Bug: 114017699
Test: atest libinput_tests
Change-Id: I69d0c40283b9589b8559e698b66d758a6c838f19
-rw-r--r-- | libs/input/tests/VelocityTracker_test.cpp | 165 |
1 files changed, 147 insertions, 18 deletions
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 43b6012e0d..9da2e2a315 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "VelocityTracker_test" +#include <array> #include <math.h> #include <android-base/stringprintf.h> @@ -32,29 +33,35 @@ constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually define // here EV = expected value, tol = VELOCITY_TOLERANCE constexpr float VELOCITY_TOLERANCE = 0.2; +// estimate coefficients must be within 0.001% of the target value +constexpr float COEFFICIENT_TOLERANCE = 0.00001; + // --- VelocityTrackerTest --- class VelocityTrackerTest : public testing::Test { }; -static void checkVelocity(float Vactual, float Vtarget) { - // Compare directions - if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) { - FAIL() << StringPrintf("Velocity %f does not have the same direction" - " as the target velocity %f", Vactual, Vtarget); +/* + * Similar to EXPECT_NEAR, but ensures that the difference between the two float values + * is at most a certain fraction of the target value. + * If fraction is zero, require exact match. + */ +static void EXPECT_NEAR_BY_FRACTION(float actual, float target, float fraction) { + float tolerance = fabsf(target * fraction); + + if (target == 0 && fraction != 0) { + // If target is zero, this would force actual == target, which is too harsh. + // Relax this requirement a little. The value is determined empirically from the + // coefficients computed by the quadratic least squares algorithms. + tolerance = 1E-6; } + EXPECT_NEAR(actual, target, tolerance); +} - // Compare magnitudes - const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE)); - const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE)); - if (fabsf(Vactual) < Vlower) { - FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f", - Vactual, VELOCITY_TOLERANCE * 100, Vtarget); - } - if (fabsf(Vactual) > Vupper) { - FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f", - Vactual, VELOCITY_TOLERANCE * 100, Vtarget); - } - SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)", - Vactual, VELOCITY_TOLERANCE * 100, Vtarget); +static void checkVelocity(float Vactual, float Vtarget) { + EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE); +} + +static void checkCoefficient(float actual, float target) { + EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE); } void failWithMessage(std::string message) { @@ -123,6 +130,19 @@ static void computeAndCheckVelocity(const Position* positions, size_t numSamples delete event; } +static void computeAndCheckQuadraticEstimate(const Position* positions, size_t numSamples, + const std::array<float, 3>& coefficients) { + VelocityTracker vt("lsq2"); + MotionEvent* event = createSimpleMotionEvent(positions, numSamples); + vt.addMovement(event); + VelocityTracker::Estimator estimator; + EXPECT_TRUE(vt.getEstimator(0, &estimator)); + for (size_t i = 0; i< coefficients.size(); i++) { + checkCoefficient(estimator.xCoeff[i], coefficients[i]); + checkCoefficient(estimator.yCoeff[i], coefficients[i]); + } +} + /* * ================== VelocityTracker tests generated manually ===================================== */ @@ -660,5 +680,114 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2 } +/* + * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy + * getEstimator function. In particular: + * - inside the function, time gets converted from nanoseconds to seconds + * before being used in the fit. + * - any values that are older than 100 ms are being discarded. + * - the newest time gets subtracted from all of the other times before being used in the fit. + * So these tests have to be designed with those limitations in mind. + * + * General approach for the tests below: + * We only used timestamps in milliseconds, 0 ms, 1 ms, and 2 ms, to be sure that + * we are well within the HORIZON range. + * When specifying the expected values of the coefficients, we treat the x values as if + * they were in ms. Then, to adjust for the time units, the coefficients get progressively + * multiplied by powers of 1E3. + * For example: + * data: t(ms), x + * 1 ms, 1 + * 2 ms, 4 + * 3 ms, 9 + * The coefficients are (0, 0, 1). + * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2). + */ +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) { + Position values[] = { + { 0000000, 1, 1 }, // 0 s + { 1000000, 1, 1 }, // 0.001 s + { 2000000, 1, 1 }, // 0.002 s + }; + // The data used for the fit will be as follows: + // time(s), position + // -0.002, 1 + // -0.001, 1 + // -0.000, 1 + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({1, 0, 0})); +} + +/* + * Straight line y = x :: the constant and quadratic coefficients are zero. + */ +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) { + Position values[] = { + { 0000000, -2, -2 }, + { 1000000, -1, -1 }, + { 2000000, -0, -0 }, + }; + // The data used for the fit will be as follows: + // time(s), position + // -0.002, -2 + // -0.001, -1 + // -0.000, 0 + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 1E3, 0})); +} + +/* + * Parabola + */ +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) { + Position values[] = { + { 0000000, 1, 1 }, + { 1000000, 4, 4 }, + { 2000000, 8, 8 }, + }; + // The data used for the fit will be as follows: + // time(s), position + // -0.002, 1 + // -0.001, 4 + // -0.000, 8 + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({8, 4.5E3, 0.5E6})); +} + +/* + * Parabola + */ +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) { + Position values[] = { + { 0000000, 1, 1 }, + { 1000000, 4, 4 }, + { 2000000, 9, 9 }, + }; + // The data used for the fit will be as follows: + // time(s), position + // -0.002, 1 + // -0.001, 4 + // -0.000, 9 + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({9, 6E3, 1E6})); +} + +/* + * Parabola :: y = x^2 :: the constant and linear coefficients are zero. + */ +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) { + Position values[] = { + { 0000000, 4, 4 }, + { 1000000, 1, 1 }, + { 2000000, 0, 0 }, + }; + // The data used for the fit will be as follows: + // time(s), position + // -0.002, 4 + // -0.001, 1 + // -0.000, 0 + size_t count = sizeof(values) / sizeof(Position); + computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 0E3, 1E6})); +} } // namespace android |