blob: 156a331d092478d1feafb3957c74ac1058bc5edc [file] [log] [blame]
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <gtest/gtest.h> // for FRIEND_TEST
#include "include/filter_interpreter.h"
#include "include/finger_metrics.h"
#include "include/gestures.h"
#include "include/prop_registry.h"
#include "include/tracer.h"
#ifndef GESTURES_IIR_FILTER_INTERPRETER_H_
#define GESTURES_IIR_FILTER_INTERPRETER_H_
namespace gestures {
// This filter interpreter applies a low-pass infinite impulse response (iir)
// filter to each incoming finger. The default filter is a low-pass 2nd order
// Butterworth IIR filter with a normalized cutoff frequency of 0.2. It can be
// configured via properties to use other formulae or
// different coefficients for the Butterworth filter.
class IirFilterInterpreter : public FilterInterpreter, public PropertyDelegate {
FRIEND_TEST(IirFilterInterpreterTest, DisableIIRTest);
public:
// We'll maintain one IOHistory record per active finger
class IoHistory {
public:
IoHistory() : in_head(0), out_head(0) {}
explicit IoHistory(const FingerState& fs) : in_head(0), out_head(0) {
for (size_t i = 0; i < kInSize; i++)
in[i] = fs;
for (size_t i = 0; i < kOutSize; i++)
out[i] = fs;
}
// Note: NextOut() and the oldest PrevOut() point to the same object.
FingerState* NextOut() { return &out[NextOutHead()]; }
FingerState* PrevOut(size_t idx) {
return &out[(out_head + idx) % kOutSize];
}
// Note: NextIn() and the oldest PrevIn() point to the same object.
FingerState* NextIn() { return &in[NextInHead()]; }
FingerState* PrevIn(size_t idx) { return &in[(in_head + idx) % kInSize]; }
void Increment();
bool operator==(const IoHistory& that) const;
bool operator!=(const IoHistory& that) const { return !(*this == that); }
void WarpBy(float dx, float dy);
private:
size_t NextOutHead() const {
return (out_head + kOutSize - 1) % kOutSize;
}
size_t NextInHead() const {
return (in_head + kInSize - 1) % kInSize;
}
static const size_t kInSize = 3;
static const size_t kOutSize = 2;
FingerState in[kInSize]; // previous input values
size_t in_head;
FingerState out[kOutSize]; // previous output values
size_t out_head;
};
// Takes ownership of |next|:
IirFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
Tracer* tracer);
virtual ~IirFilterInterpreter() {}
protected:
virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout);
public:
virtual void DoubleWasWritten(DoubleProperty* prop);
private:
// Whether IIR filter should be used. Put as a member varible for
// unittest purpose.
bool using_iir_;
std::map<short, IoHistory> histories_;
// y[0] = b[0]*x[0] + b[1]*x[1] + b[2]*x[2] + b[3]*x[3]
// - (a[1]*y[1] + a[2]*y[2])
DoubleProperty b0_, b1_, b2_, b3_, a1_, a2_;
// If position change between 2 frames is less than iir_dist_thresh_,
// IIR filter is applied, otherwise rolling average is applied.
DoubleProperty iir_dist_thresh_;
// Whether to adjust the IIR history when finger WARP is detected.
BoolProperty adjust_iir_on_warp_;
};
} // namespace gestures
#endif // GESTURES_IIR_FILTER_INTERPRETER_H_