2016-03-20 13 views
3

Ich versuche, einen Tiefpassfilter für Kompasspeilung Eingang zu implementieren, und ich habe eine Grundfunktion zusammen, die wie folgt aussieht:Tiefpass Kompass Glättung Seltsamkeit

var smoothing = 0.15; 

function lowPass(degree) { 
    var oldVal = $scope.compassBearing || 0; 
    var smoothedValue = oldVal + smoothing * (degree - oldVal); 
    return smoothedValue; 
} 

Funktioniert prima, außer denn wenn der Kompasspeilung Norden verläuft (dh. ändert sich schlagartig 0-359 oder umgekehrt.

Hat laufen jemand in ein ähnliches Problem, und wenn ja, wie wurde es gelöst?

+0

Was ist das Problem? 'smoothValue' wird z. 361, -2, usw.? – dannyjolie

+0

Es ist, dass die Glättung versucht, das Lesen um die andere Seite zu "glätten" - also anstatt zu glätten Übergang von zum Beispiel 356 -> 358 -> 0 -> 2, versucht es, die beiden Werte so schnell den Kompass zu mitteln dreht sich in die entgegengesetzte Richtung, um die neuen Werte zu treffen. – opticon

+0

Ja, das habe ich mir gedacht. Habe dein Skript selbst ausprobiert und dein wirkliches Problem gesehen. Übergang von z.B. 359 bis 10 geht "rückwärts", nicht über 0. Es war nicht klar aus der Frage. – dannyjolie

Antwort

4

Angenommen, Sie immer möchte, dass es auf dem kürzesten Weg geglättet wird, also wenn die Änderung von 270 Grad zu 5 ist Grad, es geht über Norden, dann müssen Sie die Werte überprüfen und sehen, ob der Unterschied zwischen ihnen mehr als 180 ist. Wenn ja, dann ändern Sie die Funktion ein wenig.

Wenn die Differenz kleiner als -180 ist, drehen Sie einige Operatoren und fügen 360 hinzu. Das Gleiche gilt, wenn der Unterschied mehr als 180 beträgt. Überprüfen Sie abschließend, ob das Ergebnis mehr als 360 oder weniger als 0 beträgt, und korrigieren Sie das Ergebnis.

function lowPass(degree) { 
    var oldVal = $scope.compassBearing || 0; 
    var smoothedValue; 

    if(oldVal - degree < -180){ 
     // Invert the logic 
     smoothedValue = oldVal - smoothing * (oldVal + 360 - degree); 
     if (smoothedValue < 0){ 
     smoothedValue = smoothedValue + 360; 
     } 
    } else if (oldVal - degree > 180){ 
     smoothedValue = oldVal + (360 + degree - oldVal) * smoothing; 
     if (smoothedValue > 360){ 
     smoothedValue = smoothedValue - 360; 
     } 
    } 
    else { 
     smoothedValue = oldVal + smoothing * (degree - oldVal); 
    } 
    return smoothedValue; 
} 

Es sieht ein Durcheinander aus, aber ich habe einfach damit herumgespielt. Hoffe es ist was du brauchst.

+0

Awesome. Das hat es getan. Ich habe das nur geärgert, aber du hast mich dazu geschlagen. Ein sonntäglicher Kater macht etwas logisches Denkvermögen :) – opticon

1

Es gibt eine elegantere Möglichkeit, dies zu tun, wenn Sie komplexe mathematische Berechnungen durchführen. Grundsätzlich können Sie mit einer komplexen Zahl einen Punkt auf dem Kompass darstellen.

enter image description here

Wenn Sie auf „durchschnittlich“ wollen oder zwei Kompassanzeige „glätten“, können Sie das tun im komplexen Bereich und dann in die Winkeldomäne zurück zu konvertieren.

Damit können wir die Mathematik js Bibliothek verwenden und Ihre Funktion im Grunde in der gleichen Form verlassen, dass Sie hatte:

var smoothing = .9; 


function lowPass(degree, oldVal) { 
    // var oldVal = $scope.compassBearing || 0; 
    var complexOldVal = math.complex({r:1, phi:oldVal * (math.pi/180)}); 
    var complexNewVal = math.complex({r:1, phi:degree * (math.pi/180)});  
    var complexSmoothedValue = math.chain(complexNewVal) 
            .subtract(complexOldVal) 
            .multiply(smoothing) 
            .add(complexOldVal) 
            .done(); 
    var smoothedValue = math.arg(complexSmoothedValue) * (180/math.pi); 
    if (smoothedValue < 0) { return 360 + smoothedValue; } 
    return smoothedValue; 
} 

document.write(lowPass(20, 30)+'<br>'); 
// 20.99634415156203 
document.write(lowPass(10, 350)+'<br>'); 
// 8.029256754215519 

können Sie sich hier mit ihm Geige: http://jsbin.com/zelokaqoju/edit?html,output

+0

Ich muss zugeben, dass ich diese Lösung über meine wirklich gut verstehen kann. Aber für diese eine einfache Anwendung, die ich denke, eine externe Bibliothek einzubringen und den Code für diejenigen, die mit Radianten nicht vertraut sind, zu entfremden, könnte ein bisschen übertrieben sein. Trotzdem liebe es aber :) – dannyjolie

+0

Ich höre dich und stimme generell zu ... Ein Vorteil dieses Ansatzes ist es leicht skaliert, wenn Sie zärtlich Glättung machen wollen. Etwas anderes als Mittelung in der Winkeldomäne führt wahrscheinlich zu unerwünschten Ergebnissen. –

+0

Einigen Sie sich in allen Punkten: P Picked Danny's und implementiert es rein für die Lesbarkeit. Diese Lösung erscheint elegant, aber es ist im Wesentlichen eine Black Box für mich! – opticon