Forum: Mikrocontroller und Digitale Elektronik Tiefpassfilter für Kompasskurs


von Gerhard (Gast)


Lesenswert?

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?

von Hochstapler und Tiefpasser (Gast)


Lesenswert?

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;

von Hochstapler und Tiefpasser (Gast)


Lesenswert?

... 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;

von Wolfgang (Gast)


Lesenswert?

Gerhard schrieb:
> Sprich - wie filtert man einen Messwert, der eine Diskontinuität
> im Bereich hat?

Rechne mit cos(KpK) und sin(KpK). Da tritt keine Diskontinuität auf.

von A. S. (rava)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

Ein Median-Filter wäre auch noch eine Möglichkeit.
Da kommt immer ein sinnvoller Wert heraus.

https://de.wikipedia.org/wiki/Rangordnungsfilter

von Wolfgang (Gast)


Lesenswert?

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 :-(

von Joe F. (easylife)


Lesenswert?

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.

von Joe F. (easylife)


Lesenswert?

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.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Angehängte Dateien:

Lesenswert?

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])

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Mann muss übrigens Atan2 benutzen, sonst weiß man nicht in welchem 
Quadranten sich der Mittelwert befindet (für alle Non-Mathematiker wie 
mich :>)

von Joe F. (easylife)


Lesenswert?

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°

von Wolfgang (Gast)


Lesenswert?

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: ...

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Wolfgang schrieb:
> Die Idee von Joe F. ist aber viel praktischer, weil keiner wegen einer
> simplen Mittelung trigonometrische Funktionen hoch und runter rechnen
> möchte.
Deshalb überlasse ich das meinem Rechner ;)

von Wolfgang (Gast)


Lesenswert?

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.

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.