Tiefpassfilter für Kompasskurs

Gast #4569537
Moin!

Ich bekomme von einem externen Kompassmodul einen fertig berechneten 
Kompass-Wert (0.0 bis 359.9 Grad) über eine serielle Schnittstelle (als 
ASCII mit einer Dezimalstelle und einem Zeilenende als Abschluss).

Der Wert ist allerdings mit einem Rauschen von etwa 2 Grad Spitze-Spitze 
überlagert und taugt noch nicht zur direkten Anzeige - das wackelt zu 
viel.

Da die Messfrequenz ungefähr 30 Hertz beträgt und mein Messobjekt nicht 
besonders dynamisch ist, könnte ich über ungefähr 20 bis 40 Werte 
tiefpassfiltern. Das habe ich auch schon umgesetzt und es funktioniert 
auch ganz gut, die Anzeige schwankt nur um 0.1 Grad.

Allerdings gibt es an einer Stelle (logischerweise) ein Problem: Wenn 
der Wert bei Nordkurs zwischen 359 bis 1 Grad schwankt, erhalte ich als 
Ergebnis aus dem Tiefpaßfilter 180 Grad als Anzeige. Das ist nun ganz 
und gar ein unerwünschtes Verhalten!

Wie kann man diese Filterung eleganter lösen, so dass ein stabiler 
Kompasswert herauskommt, insbesondere wenn sich das Messobjekt langsam 
dreht? Sprich - wie filtert man einen Messwert, der eine Diskontinuität 
im Bereich hat?
Gast
Moinsen!

Rechne intern einfach die Umdrehunen mit. Anschließend kannst du den 
Winkel z.B. durch eine Modulo Operation wieder berechnen.

Etwas so:
1
if((letzterWert<90)&&(wert>180)) umdrehungen--;
2
else
3
if((letzterWert>270)&&(wert<180))umdrehungen++;
4

5
wert += umdrehungen * 360;
6
wert = tiefpass(wert);
7
wert = wert%360;
Gast
... der lieber mit diesen Parametern:
1
if((letzterWert<90)&&(wert>270)) umdrehungen--;
2
else
3
if((letzterWert>270)&&(wert<90))umdrehungen++;
4

5
wert += umdrehungen * 360;
6
wert = tiefpass(wert);
7
wert = wert%360;
Scheint mir auch die eleganteste Lösung zu sein. Falls du sin & cos 
einigermaßen brauchbar berechnen kannst.

Ansonsten könntest du deinen Wertebereich um 180° drehen, sobald es in 
die Nähe der 0° geht, damit die Diskontinuität dann woanders liegt.
Schwierig wird es, da den Grenzwert einzustellen, denn genau da tritt 
wieder ein Schalten auf. Vermutlich möchte man das glatte, gefilterte 
Signal als Entscheidungsgrundlage nehmen und etwas Hysterese einbauen. 
Das wird vermutlich schwieriger, als es klingt...
sollte aber auch machbar sein.
Gast
Joe F. schrieb:
> Ein Median-Filter wäre auch noch eine Möglichkeit.
> Da kommt immer ein sinnvoller Wert heraus.

Das ist doch Unfug.

Es kommt zwar kein um rund 180° falscher Wert raus, aber bei Anwendung 
auf Kompasskurse im Bereich 360/0° werden gerade die richtigen Werte 
(nahe 0/360°) durch die Medianberechung rausgeschmissen. Als Ergebnis 
aus dem Median kommt nämlich in dem Fall einer raus, der gerade von 
0/360° weit weg liegt :-(
Wolfgang schrieb:
> Als Ergebnis
> aus dem Median kommt nämlich in dem Fall einer raus, der gerade von
> 0/360° weit weg liegt :-(

Nein, denn man nimmt natürlich den Wert, der in der Mitte der Liste 
liegt.

Nachtrag:
Achso, du hast natürlich recht. Sorry.

Medianfilter ist Quatsch.

Was Sinn machen würde, ist den am häufigsten auftretenden Wert zu 
nehmen.
Andere Idee:

Du berechnest für jeden eingehenden Wert die Abweichung vom aktuell 
angezeigten Kurs (kann dann auch negativ sein).

Wenn die Abweichung des Messwertes >180° ist, nimmst du einen Überlauf 
über 0° an, und ziehst 360° ab.
Wenn die Abweichung <-180° ist, addierst du 360°.

Diese Abweichungen mittelst du, rechnest dieses Mittel zum aktuellen 
Kurs dazu, und bringst das Ergebnis wieder in den Wertebereich 0.0-359.9
(<0 -> +360.0 , >=360 -> -360.0)
Das ist dann der neue Kurs.
(Firma: HEGRO GmbH)
Das trifft sich gerade prima, mache nämlich just in diesem Moment etwas 
Ähnliches. N Kompass ist aber nicht dabei :>

Wolfgang schrieb:
> Rechne mit cos(KpK) und sin(KpK). Da tritt keine Diskontinuität auf.
Hättest du Lust und Zeit das zu erläutern?

EDIT: Nach etwas googlen habe ich das hier gefunden:

                   sum_i_from_1_to_N sin(a[i])
a = arctangent ---------------------------
                   sum_i_from_1_to_N cos(a[i])
Angehängte Dateien:
Hier die reine Integer-Lösung (mit 0.1° Auflösung)

1
#define COMPASS_VALUES 30
2
#define TEST_DIRECTION 3599  // 359.9°  
3

4
int compass[COMPASS_VALUES];  
5
int i;
6
int d;
7
int d_sum;
8
int course;
9

10
// create random input values
11
for (i=0; i<COMPASS_VALUES; i++)
12
{
13
  compass[i] = TEST_DIRECTION + rand()%5 - 2;  // main direction +/- 0.2°
14
  if (compass[i] >= 3600) compass[i] -= 3600;
15
  if (compass[i] <     0) compass[i] += 3600;
16
  printf("%2d: %3d.%1d\n", i, compass[i]/10, compass[i]%10);
17
}
18

19
// calculate average course derivation
20
course = compass[0];
21
d_sum = 0;
22
for (i=1; i<COMPASS_VALUES; i++)
23
{
24
  d = compass[i] - course;
25
  if (d >  1800) d -= 3600;
26
  if (d < -1800) d += 3600;
27
  d_sum += d;
28
}
29
d_sum  += COMPASS_VALUES / 2;  // round (add 0.5)
30
d_sum  /= (COMPASS_VALUES);
31
course += d_sum;
32

33
// normalize
34
if (course >= 3600) course -= 3600;
35
if (course <     0) course += 3600;
36

37
// output
38
printf("Course: %3d.%1d°\n", course/10, course%10);

Ergebnis:
1
 0: 359.7
2
 1:   0.1
3
 2:   0.0
4
 3: 359.9
5
 4:   0.0
6
 5: 359.9
7
 6: 359.8
8
 7:   0.0
9
 8: 359.7
10
 9: 359.8
11
10: 359.7
12
11: 359.8
13
12:   0.1
14
13: 359.7
15
14:   0.0
16
15: 359.9
17
16: 359.7
18
17:   0.1
19
18: 359.9
20
19: 359.9
21
20: 359.8
22
21:   0.1
23
22:   0.1
24
23: 359.9
25
24:   0.1
26
25:   0.1
27
26: 359.7
28
27: 359.8
29
28: 359.9
30
29:   0.1
31
Course: 359.9°
Gast
Reginald L. schrieb:
> Wolfgang schrieb:
>> Rechne mit cos(KpK) und sin(KpK). Da tritt keine Diskontinuität auf.
> Hättest du Lust und Zeit das zu erläutern?

Guck dir den Kurvenverlauf von sin(x) und cos(x) in der Nähe von 0°/360° 
an. Da ist alles wunderschön stetig. So ganz unproblematisch ist eine 
Mittelung bei den Umkehrpunkten aber auch nicht (z.B. cos(x) für x nahe 
0).

Die Idee von Joe F. ist aber viel praktischer, weil keiner wegen einer 
simplen Mittelung trigonometrische Funktionen hoch und runter rechnen 
möchte.

Joe F. schrieb:
> Andere Idee: ...
Gast
Reginald L. schrieb:
> Deshalb überlasse ich das meinem Rechner ;)

Mit dieser Einstellung wird es auch weiterhin gelingen, Fortschritte in 
der Rechnerleistung sinnlos durch Faulheit bei der Programmierung und 
Entwicklung von Algorithmen zu verpulvern.
(Firma: HEGRO GmbH)
Wolfgang schrieb:
> Mit dieser Einstellung wird es auch weiterhin gelingen, Fortschritte in
> der Rechnerleistung sinnlos durch Faulheit bei der Programmierung und
> Entwicklung von Algorithmen zu verpulvern.

Du kannst ruhig weiterhin stundenlang an der Entwicklung eines 
Algorithmus sitzen um deinen 4x3GHz Rechner dann mit dem kleinen 
EinMalEins zu malträtieren :)

Es dient letztendlich als Mittel zum Zweck. Möchte man sowas in einen 
kleinen langsamen 8-Bitter implementieren stellt sich die Frage 
inwieweit die "Faulheit" noch taugt.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.