| /* |
| ** |
| ** Copyright 2014, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #ifndef CLOCK_ESTIMATOR_H_ |
| |
| #define CLOCK_ESTIMATOR_H_ |
| |
| #include "foundation/ABase.h" |
| #include <utils/RefBase.h> |
| #include <utils/Vector.h> |
| |
| namespace android { |
| // --------------------------------------------------------------------------- |
| |
| struct ClockEstimator : RefBase { |
| virtual double estimate(double x, double y) = 0; |
| virtual void reset() = 0; |
| }; |
| |
| struct WindowedLinearFitEstimator : ClockEstimator { |
| struct LinearFit { |
| /** |
| * Fit y = a * x + b, where each input has a weight |
| */ |
| double mX; // sum(w_i * x_i) |
| double mXX; // sum(w_i * x_i^2) |
| double mY; // sum(w_i * y_i) |
| double mYY; // sum(w_i * y_i^2) |
| double mXY; // sum(w_i * x_i * y_i) |
| double mW; // sum(w_i) |
| |
| LinearFit(); |
| void reset(); |
| void combine(const LinearFit &lf); |
| void add(double x, double y, double w); |
| void scale(double w); |
| double interpolate(double x); |
| double size() const; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(LinearFit); |
| }; |
| |
| /** |
| * Estimator for f(x) = y' where input y' is noisy, but |
| * theoretically linear: |
| * |
| * y' =~ y = a * x + b |
| * |
| * It uses linear fit regression over a tapering rolling window |
| * to get an estimate for y (from the current and past inputs |
| * (x, y')). |
| * |
| * ____________ |
| * /| |\ |
| * / | | \ |
| * / | | \ <--- new data (x, y') |
| * / | main | \ |
| * <--><----------><--> |
| * tail head |
| * |
| * weight is 1 under the main window, tapers exponentially by |
| * the factors given in the head and the tail. |
| * |
| * Assuming that x and y' are monotonic, that x is somewhat |
| * evenly sampled, and that a =~ 1, the estimated y is also |
| * going to be monotonic. |
| */ |
| WindowedLinearFitEstimator( |
| size_t headLength = 5, double headFactor = 0.5, |
| size_t mainLength = 0, double tailFactor = 0.99); |
| |
| virtual void reset(); |
| |
| // add a new sample (x -> y') and return an estimated value for the true y |
| virtual double estimate(double x, double y); |
| |
| private: |
| Vector<double> mXHistory; // circular buffer |
| Vector<double> mYHistory; // circular buffer |
| LinearFit mHead; |
| LinearFit mMain; |
| LinearFit mTail; |
| double mHeadFactorInv; |
| double mTailFactor; |
| double mFirstWeight; |
| size_t mHistoryLength; |
| size_t mHeadLength; |
| size_t mNumSamples; |
| size_t mSampleIx; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(WindowedLinearFitEstimator); |
| }; |
| |
| }; // namespace android |
| |
| #endif |