Loading include/input/CoordinateFilter.h +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public: * the previous call. * @param coords Coordinates to be overwritten by the corresponding filtered coordinates. */ void filter(std::chrono::duration<float> timestamp, PointerCoords& coords); void filter(std::chrono::nanoseconds timestamp, PointerCoords& coords); private: OneEuroFilter mXFilter; Loading include/input/OneEuroFilter.h +5 −5 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ public: * provided in the previous call. * @param rawPosition Position to be filtered. */ float filter(std::chrono::duration<float> timestamp, float rawPosition); float filter(std::chrono::nanoseconds timestamp, float rawPosition); private: /** Loading @@ -67,7 +67,7 @@ private: /** * Slope of the cutoff frequency criterion. This is the term scaling the absolute value of the * filtered signal's speed. The data member is dimensionless, that is, it does not have units. * filtered signal's speed. Units are 1 / position. */ const float mBeta; Loading @@ -78,9 +78,9 @@ private: const float mSpeedCutoffFreq; /** * The timestamp from the previous call. Units are seconds. * The timestamp from the previous call. */ std::optional<std::chrono::duration<float>> mPrevTimestamp; std::optional<std::chrono::nanoseconds> mPrevTimestamp; /** * The raw position from the previous call. Loading @@ -88,7 +88,7 @@ private: std::optional<float> mPrevRawPosition; /** * The filtered velocity from the previous call. Units are position per second. * The filtered velocity from the previous call. Units are position per nanosecond. */ std::optional<float> mPrevFilteredVelocity; Loading libs/input/CoordinateFilter.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ namespace android { CoordinateFilter::CoordinateFilter(float minCutoffFreq, float beta) : mXFilter{minCutoffFreq, beta}, mYFilter{minCutoffFreq, beta} {} void CoordinateFilter::filter(std::chrono::duration<float> timestamp, PointerCoords& coords) { void CoordinateFilter::filter(std::chrono::nanoseconds timestamp, PointerCoords& coords) { coords.setAxisValue(AMOTION_EVENT_AXIS_X, mXFilter.filter(timestamp, coords.getX())); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, mYFilter.filter(timestamp, coords.getY())); } Loading libs/input/OneEuroFilter.cpp +21 −13 Original line number Diff line number Diff line Loading @@ -25,16 +25,24 @@ namespace android { namespace { using namespace std::literals::chrono_literals; const float kHertzPerGigahertz = 1E9f; const float kGigahertzPerHertz = 1E-9f; // filteredSpeed's units are position per nanosecond. beta's units are 1 / position. inline float cutoffFreq(float minCutoffFreq, float beta, float filteredSpeed) { return minCutoffFreq + beta * std::abs(filteredSpeed); return kHertzPerGigahertz * ((minCutoffFreq * kGigahertzPerHertz) + beta * std::abs(filteredSpeed)); } inline float smoothingFactor(std::chrono::duration<float> samplingPeriod, float cutoffFreq) { return samplingPeriod.count() / (samplingPeriod.count() + (1.0 / (2.0 * M_PI * cutoffFreq))); inline float smoothingFactor(std::chrono::nanoseconds samplingPeriod, float cutoffFreq) { const float constant = 2.0f * M_PI * samplingPeriod.count() * (cutoffFreq * kGigahertzPerHertz); return constant / (constant + 1); } inline float lowPassFilter(float rawPosition, float prevFilteredPosition, float smoothingFactor) { return smoothingFactor * rawPosition + (1 - smoothingFactor) * prevFilteredPosition; inline float lowPassFilter(float rawValue, float prevFilteredValue, float smoothingFactor) { return smoothingFactor * rawValue + (1 - smoothingFactor) * prevFilteredValue; } } // namespace Loading @@ -42,17 +50,17 @@ inline float lowPassFilter(float rawPosition, float prevFilteredPosition, float OneEuroFilter::OneEuroFilter(float minCutoffFreq, float beta, float speedCutoffFreq) : mMinCutoffFreq{minCutoffFreq}, mBeta{beta}, mSpeedCutoffFreq{speedCutoffFreq} {} float OneEuroFilter::filter(std::chrono::duration<float> timestamp, float rawPosition) { LOG_IF(FATAL, mPrevFilteredPosition.has_value() && (timestamp <= *mPrevTimestamp)) << "Timestamp must be greater than mPrevTimestamp"; float OneEuroFilter::filter(std::chrono::nanoseconds timestamp, float rawPosition) { LOG_IF(FATAL, mPrevTimestamp.has_value() && (*mPrevTimestamp >= timestamp)) << "Timestamp must be greater than mPrevTimestamp. Timestamp: " << timestamp.count() << "ns. mPrevTimestamp: " << mPrevTimestamp->count() << "ns"; const std::chrono::duration<float> samplingPeriod = (mPrevTimestamp.has_value()) ? (timestamp - *mPrevTimestamp) : std::chrono::duration<float>{1.0}; const std::chrono::nanoseconds samplingPeriod = (mPrevTimestamp.has_value()) ? (timestamp - *mPrevTimestamp) : 1s; const float rawVelocity = (mPrevFilteredPosition.has_value()) ? ((rawPosition - *mPrevFilteredPosition) / samplingPeriod.count()) : 0.0; ? ((rawPosition - *mPrevFilteredPosition) / (samplingPeriod.count())) : 0.0f; const float speedSmoothingFactor = smoothingFactor(samplingPeriod, mSpeedCutoffFreq); Loading libs/input/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ cc_test { "IdGenerator_test.cpp", "InputChannel_test.cpp", "InputConsumer_test.cpp", "InputConsumerFilteredResampling_test.cpp", "InputConsumerResampling_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", Loading Loading
include/input/CoordinateFilter.h +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public: * the previous call. * @param coords Coordinates to be overwritten by the corresponding filtered coordinates. */ void filter(std::chrono::duration<float> timestamp, PointerCoords& coords); void filter(std::chrono::nanoseconds timestamp, PointerCoords& coords); private: OneEuroFilter mXFilter; Loading
include/input/OneEuroFilter.h +5 −5 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ public: * provided in the previous call. * @param rawPosition Position to be filtered. */ float filter(std::chrono::duration<float> timestamp, float rawPosition); float filter(std::chrono::nanoseconds timestamp, float rawPosition); private: /** Loading @@ -67,7 +67,7 @@ private: /** * Slope of the cutoff frequency criterion. This is the term scaling the absolute value of the * filtered signal's speed. The data member is dimensionless, that is, it does not have units. * filtered signal's speed. Units are 1 / position. */ const float mBeta; Loading @@ -78,9 +78,9 @@ private: const float mSpeedCutoffFreq; /** * The timestamp from the previous call. Units are seconds. * The timestamp from the previous call. */ std::optional<std::chrono::duration<float>> mPrevTimestamp; std::optional<std::chrono::nanoseconds> mPrevTimestamp; /** * The raw position from the previous call. Loading @@ -88,7 +88,7 @@ private: std::optional<float> mPrevRawPosition; /** * The filtered velocity from the previous call. Units are position per second. * The filtered velocity from the previous call. Units are position per nanosecond. */ std::optional<float> mPrevFilteredVelocity; Loading
libs/input/CoordinateFilter.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ namespace android { CoordinateFilter::CoordinateFilter(float minCutoffFreq, float beta) : mXFilter{minCutoffFreq, beta}, mYFilter{minCutoffFreq, beta} {} void CoordinateFilter::filter(std::chrono::duration<float> timestamp, PointerCoords& coords) { void CoordinateFilter::filter(std::chrono::nanoseconds timestamp, PointerCoords& coords) { coords.setAxisValue(AMOTION_EVENT_AXIS_X, mXFilter.filter(timestamp, coords.getX())); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, mYFilter.filter(timestamp, coords.getY())); } Loading
libs/input/OneEuroFilter.cpp +21 −13 Original line number Diff line number Diff line Loading @@ -25,16 +25,24 @@ namespace android { namespace { using namespace std::literals::chrono_literals; const float kHertzPerGigahertz = 1E9f; const float kGigahertzPerHertz = 1E-9f; // filteredSpeed's units are position per nanosecond. beta's units are 1 / position. inline float cutoffFreq(float minCutoffFreq, float beta, float filteredSpeed) { return minCutoffFreq + beta * std::abs(filteredSpeed); return kHertzPerGigahertz * ((minCutoffFreq * kGigahertzPerHertz) + beta * std::abs(filteredSpeed)); } inline float smoothingFactor(std::chrono::duration<float> samplingPeriod, float cutoffFreq) { return samplingPeriod.count() / (samplingPeriod.count() + (1.0 / (2.0 * M_PI * cutoffFreq))); inline float smoothingFactor(std::chrono::nanoseconds samplingPeriod, float cutoffFreq) { const float constant = 2.0f * M_PI * samplingPeriod.count() * (cutoffFreq * kGigahertzPerHertz); return constant / (constant + 1); } inline float lowPassFilter(float rawPosition, float prevFilteredPosition, float smoothingFactor) { return smoothingFactor * rawPosition + (1 - smoothingFactor) * prevFilteredPosition; inline float lowPassFilter(float rawValue, float prevFilteredValue, float smoothingFactor) { return smoothingFactor * rawValue + (1 - smoothingFactor) * prevFilteredValue; } } // namespace Loading @@ -42,17 +50,17 @@ inline float lowPassFilter(float rawPosition, float prevFilteredPosition, float OneEuroFilter::OneEuroFilter(float minCutoffFreq, float beta, float speedCutoffFreq) : mMinCutoffFreq{minCutoffFreq}, mBeta{beta}, mSpeedCutoffFreq{speedCutoffFreq} {} float OneEuroFilter::filter(std::chrono::duration<float> timestamp, float rawPosition) { LOG_IF(FATAL, mPrevFilteredPosition.has_value() && (timestamp <= *mPrevTimestamp)) << "Timestamp must be greater than mPrevTimestamp"; float OneEuroFilter::filter(std::chrono::nanoseconds timestamp, float rawPosition) { LOG_IF(FATAL, mPrevTimestamp.has_value() && (*mPrevTimestamp >= timestamp)) << "Timestamp must be greater than mPrevTimestamp. Timestamp: " << timestamp.count() << "ns. mPrevTimestamp: " << mPrevTimestamp->count() << "ns"; const std::chrono::duration<float> samplingPeriod = (mPrevTimestamp.has_value()) ? (timestamp - *mPrevTimestamp) : std::chrono::duration<float>{1.0}; const std::chrono::nanoseconds samplingPeriod = (mPrevTimestamp.has_value()) ? (timestamp - *mPrevTimestamp) : 1s; const float rawVelocity = (mPrevFilteredPosition.has_value()) ? ((rawPosition - *mPrevFilteredPosition) / samplingPeriod.count()) : 0.0; ? ((rawPosition - *mPrevFilteredPosition) / (samplingPeriod.count())) : 0.0f; const float speedSmoothingFactor = smoothingFactor(samplingPeriod, mSpeedCutoffFreq); Loading
libs/input/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ cc_test { "IdGenerator_test.cpp", "InputChannel_test.cpp", "InputConsumer_test.cpp", "InputConsumerFilteredResampling_test.cpp", "InputConsumerResampling_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", Loading