Ich hatte ein ähnliches Problem mit einem künstlichen Horizont auf meinem Gerät. Der Tiefpassfilter (LPF) löste dieses Problem.
Sie müssen jedoch berücksichtigen, wenn Sie den Ausrichtungswinkel in Grad verwenden und das LPF blind darauf anwenden. Das Ergebnis ist fehlerhaft, wenn sich das Gerät im Hochformat befindet und von links nach rechts oder umgekehrt gedreht wird. Der Grund dafür ist die Verschiebung zwischen 359 und 0 Grad. Daher empfehle ich, den Grad in Radianten umzuwandeln und den LPF auf die sin und cos Werte des Orientierungswinkels anzuwenden.
Weiter empfehle ich eine dynamische Alpha oder Update-Rate für das LPF zu verwenden. Ein statischer Wert für das Alpha ist möglicherweise auf Ihrem Gerät perfekt, auf keinem anderen jedoch.
Die folgenden Klasse-Filter auf Basis von Radianten und verwendet eine dynamische alpha, wie oben beschrieben:
import static java.lang.Math.*;
Filter {
private static final float TIME_CONSTANT = .297f;
private static final float NANOS = 1000000000.0f;
private static final int MAX = 360;
private double alpha;
private float timestamp;
private float timestampOld;
private int count;
private int values[];
Filter() {
timestamp = System.nanoTime();
timestampOld = System.nanoTime();
values = new int[0];
}
int filter(int input) {
//there is no need to filter if we have only one
if(values.length == 0) {
values = new int[] {0, input};
return input;
}
//filter based on last element from array and input
int filtered = filter(values[1], input);
//new array based on previous result and filter
values = new int[] {values[1], filtered};
return filtered;
}
private int filter(int previous, int current) {
calculateAlpha();
//convert to radians
double radPrev = toRadians(previous);
double radCurrent = toRadians(current);
//filter based on sin & cos
double sumSin = filter(sin(radPrev), sin(radCurrent));
double sumCos = filter(cos(radPrev), cos(radCurrent));
//calculate result angle
double radRes = atan2(sumSin, sumCos);
//convert radians to degree, round it and normalize (modulo of 360)
long round = round(toDegrees(radRes));
return (int) ((MAX + round) % MAX);
}
//dynamic alpha
private void calculateAlpha() {
timestamp = System.nanoTime();
float diff = timestamp - timestampOld;
double dt = 1/(count/(diff/NANOS));
count++;
alpha = dt/(TIME_CONSTANT + dt);
}
private double filter(double previous, double current) {
return (previous + alpha * (current - previous));
}
}
Für weitere Ablesungen sehen diese discussion.