PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme mit Single-Variablen



digitali
05.02.2006, 21:16
Hallo,

Ich habe da ein kleines Problem mit einigen Single-Variablen. Wenn ich folgende Variablen auf einem ATMega16 mit diesen Werten deklariere:

A1 = 50.16666667
A2 = 7.2
A3 = 53.16666667
A4 = 7.226016667

und diese Werte wieder auf dem LCD ausgebe, wird folgendes angezeigt:

A1 = 50.16666667936
A2 = 7.199999806
A3 = 53.16666667936
A4 = 7.226016518

Sinn und Zweck des Ganzen ist eine Distanz- und Winkelberechnung in Kilometern zwischen zwei angegebenen Koordinaten. Mit der ACOS-Funktion habe ich auch noch so meine Probleme. Auch hier erhalte ich voellig unterschiedliche Ergebnisse. Diese unterscheiden sich vom ATMega16 und einem PC oder Taschenrechner gravierend.

B10 = 0.999999958
B11 = Acos(B10)

Hier erhalte ich auf dem angeschlossenen LCD als Ergebnis: 0.000345228
Berechne ich das im Excel mit der Funktion: ARCCOS(B10), dann erhalte ich als Ergebnis: 0.0002908617

Irgendwas stimmt da doch nicht? Was mache ich denn da falsch?
Ich benutze das aktuelle Bascom 1.11.8.2 (auch die letzten Updates habe ich mir gezogen)

Mit freundlichen Gruessen
Digitali

digitali
05.02.2006, 23:14
Problem geloest!
Habe alle Variablen als Double deklariert. Nach einer Vergleichsrechnung zwischen einer Excelfunktion und dem ATMega habe ich zwischen zwei Koordinaten 4m Differenz auf einem knappen Kilometer. Naja, damit kann ich leben.

Ich wollte damit eine GPS-Mouse auslesen. Zu der aktuellen Position laesst sich dann eine zweite Koordinate eintippen und ein GOTO starten. Auf dem GLCD wird dann eine Kompassrose gezeichnet und ein Pfeil zeigt mir die Richtung an in der man fahren muss. Und die noch verbleibene Wegstrecke in Kilometern. Eine Art Navigation nur nach Pfeil. Das ganze soll vielleicht mal als Festeinbau ins Auto. Fuer mich als aktiver Geocacher und Atmelbastler genau das Richtige. ;)

oe9vfj
06.02.2006, 12:32
Bei Verwendung von Gleitkommazahlen (SINGLE und DOUBLE) ist zu beachten, dass viele Dezimalzahlen nicht genau repräsentiert werden können. SINGLE hat eine Auflösung von 24 Bit und DOUBLE eine solche von 53Bit. Dies entspricht bei SINGLE etwa 8 Dezimalziffern und bei DOUBLE etwa 16 Dezimalziffern. (ich verwende hier Dezimalziffern anstatt Dezimalstellen, da auch die Ziffern vor dem Komma miteingerechnet werden müssen)
Zu Deinem Beispiel mit 50.16666667 ist das 50.166666. Der nächste entsprechende Binärwert im SINGLE Format ist 50.16666793823242 und entspricht ziemlich genau der Ausgabe von BASCOM-AVR.

Die Problematik trifft auch auf Dein ACOS Beispiel zu. Der exakte Wert für 0.999999958 im SINGLE-Format ist 0.9999999403953552. Berechnet man für diesen Wert den ACOS Wert bekommt man 0.000345266985 was dem Ausgabewert von BASCOM-AVR wiederum recht genau entspricht.

Die begrenzte Genauigkeit von SINGLE muss daher bei den Berechnungen berücksichtigt werden.

DOUBLE hat natürlich eine wesentlich bessere Genauigkeit. Auch EXCEL verwendet das DOUBLE-Format. In BASCOM-AVR wurden die trigonometrischen Funktionen so programmiert, dass sie in der Genauigkeit in etwa denen von EXCEL entsprechen sollten.
Daher hätte mich Deine Beispielsrechnung interessiert, welche bei Dir die Differenz von 4m ergibt.

digitali
06.02.2006, 19:01
Hallo,

die Abweichung von den besagten 4m hat sich geklaert. Da hatte ich nen simplen Zahlendreher in der Rechnung (irgendwann sieht man vor lauter Zahlen nichts mehr... :) ). Nun passen die Ergebnisse vom Atmel exakt mit denen von Excel ueberein. Ich habe mittlerweile auch einen ATMega128 genommen. Beim 16er war der Flash schon stellenweise zu 30% voll. Und das Programm ist ja noch laengst nicht fertig. Als naechstes die Winkelberechnung, dann grafische Aufbereitung der Daten, Auslesen einer GPS-Mouse und Abfrage einen Drehimpulsgebers (zur Eingabe von einer Koordinate). Ein Drehimpulsgeber spart Platz und sieht huebscher aus, als so ein klobiges Tastenfeld. :)

In dem nachfolgenden Beispiel wird zunaechst nur die Distanz zweier fest vorgegebenen Koordinaten berechnet. Sicherlich laesst sich hier und da noch einiges optimieren. Das ist mal so auf die Schnelle entstanden. Hauptsache es funktioniert erstmal.


Dim A1 As Double , A2 As Double
Dim A3 As Double , A4 As Double
Dim B1 As Double , B2 As Double
Dim B3 As Double , B4 As Double
Dim B5 As Double , B6 As Double
Dim B7 As Double , B8 As Double
Dim B9 As Double , B10 As Double
Dim Distanz As Double , B11 As Double
Dim C1 As Double , C2 As Double
Dim C3 As Double , C4 As Double
Dim C5 As Double , Pi As Double
Dim Z As String * 20 , Y As Single
Dim X As String * 10
Pi = 3.141592654

Initlcd
Cursor Off
Cls

'Koordinate 1
A1 = 50,16666667
A2 = 7,2

'Koordinate 2
A3 = 50,16666667
A4 = 7,226016667

'Grundformel zur Distanzberechung zwischen zwei Koordinaten:
'6371,229*ARCCOS(SIN(A1*PI/180)*SIN(A3*PI/180)+COS(A1*PI/180)*COS(A3*PI/180)’*COS((A2-A7)*PI/180))

'Zerlegung der Formel
'SIN(A1*PI/180)

B1 = A1 * Pi
B1 = B1 / 180
C1 = Sin(b1)

'SIN(A3*PI/180)

B2 = A3 * Pi
B2 = B2 / 180
C2 = Sin(b2)

'COS(A1*PI/180)

B3 = A1 * Pi
B3 = B3 / 180
C3 = Cos(b3)

'COS(A3*PI/180)

B4 = A3 * Pi
B4 = B4 / 180
C4 = Cos(b4)

'COS((A2-A4)*PI/180)

B5 = A2 - A4
B5 = B5 * Pi
B5 = B5 / 180
C5 = Cos(b5)

'B9= (C1 * C2) + (C3 * C4 * C5)

B6 = C1 * C2
B7 = C3 * C4
B8 = B7 * C5
B9 = B6 + B8

'6371,229*ARCCOS(B9)

B10 = Acos(b9)
Distanz = 6371.229 * B10

Z = Str(distanz)
Y = Val(z)
X = Fusing(y , "#.####")

Locate 1 , 1
Lcd "Distanz: " ; X ; " Km"

oe9vfj
07.02.2006, 09:39
Eines Sache ist mir beim schnellen Durchschauen aufgefallen:

Für die Umrechung von Grad in Radiant gibt es die Funktion Deg2Rad()

'SIN(A1*PI/180)


B1 = A1 * Pi
B1 = B1 / 180
C1 = Sin(b1)

kann daher auch so gerechnet werden.


B1 = Deg2Rad(A1)
C1 = Sin(B1)

Das braucht weniger Code und geht schneller.

Mit Rad2Deg() gibt es auch den umgekehrten Weg.

oe9vfj
07.02.2006, 09:42
Eine Sache ist mir beim schnellen Durchschauen aufgefallen:

Für die Umrechung von Grad in Radiant gibt es die Funktion Deg2Rad()

'SIN(A1*PI/180)


B1 = A1 * Pi
B1 = B1 / 180
C1 = Sin(b1)

kann daher auch so gerechnet werden.


B1 = Deg2Rad(A1)
C1 = Sin(B1)

Das braucht weniger Code und geht schneller.

Mit Rad2Deg() gibt es auch den umgekehrten Weg.

digitali
07.02.2006, 21:16
Oh, war mir noch gar nicht aufgefallen. Und funktioniert! Danke fuer den Tipp!

Mit freundlichen Gruessen
Digitali

gpsklaus
24.02.2006, 10:45
Hallo,
vielleicht ist auch meine hinzugefügte ( und sicher noch verbesserungsfähige ) Winkelberechnung noch von Interesse.

Klaus

'--------------------------------------------------------------------
'Distanz und Winkel zwischen zwei geogr. Punkten


$lib "double.lbx"
$regfile = "m64def.dat"
$hwstack = 32
$swstack = 32
$framesize = 96

Dim A1 As Double , A2 As Double
Dim A3 As Double , A4 As Double ,
Dim B1 As Double , B2 As Double
Dim B3 As Double , B4 As Double
Dim B5 As Double , B6 As Double
Dim B7 As Double , B8 As Double
Dim B9 As Double , B10 As Double
Dim Dist As Double , B11 As Double
Dim C1 As Double , C2 As Double
Dim C3 As Double , C4 As Double
Dim C5 As Double , Pi As Double
Dim Radian As Double , Ga As Double
Dim Be As Double , Le As Double
Dim Bf As Double , Lf As Double ,
Dim Zw As Double , Zw1 As Double
Dim Zw2 As Double , Zw3 As Double
Dim Bear As Double , Bear1 As Double
Dim Bear2 As Double , Bear3 As Double
Dim Z As String * 20 , Y As Single
Dim X As String * 10
Dim W As String * 20 , V As Single
Dim U As String * 10

Pi = 3.141592654
Radian = 0.017453292 'Pi/180

Initlcd
Cursor Off
Cls

'Koordinate 1
A1 = 49.96 'Breite Eigen (BE)
A2 = 8.2 'Laenge Eigen (LE)

'Koordinate 2
A3 = 48.96 'Breite Fremd ( BF )
A4 = 8.2 'Laenge Fremd ( LF)

'Grundformel zur Distanzberechung:
'6371.229 * Arccos(sin(a1 * Pi / 180) * Sin(a3 * Pi / 180) +
'Cos(a1 * Pi / 180) * Cos(a3 * Pi / 180)’ * Cos((a2 -a7) * Pi / 180))

'Zerlegung der Formel
'Sin(a1 * Pi / 180)

B1 = Deg2rad(a1)
C1 = Sin(b1)

'Sin(a3 * Pi / 180)

B2 = Deg2rad(a3)
C2 = Sin(b2)

'Cos(a1 * Pi / 180)

B3 = Deg2rad(a1)
C3 = Cos(b3)

'Cos(a3 * Pi / 180)

B4 = Deg2rad(a3)
C4 = Cos(b4)

'Cos((a2 -a4) * Pi / 180)

B5 = A2 - A4
B5 = Deg2rad(b5)
C5 = Cos(b5)

'B9 =(c1 * C2) +(c3 * C4 * C5)

B6 = C1 * C2
B7 = C3 * C4
B8 = B7 * C5
B9 = B6 + B8

'6371 , 229 * Arccos(b9)

B10 = Acos(b9)
Dist = B10 * 6371.229

'Winkelberechnung ( Bearing ):
'-----------------------------

Be = A1 * Radian
Le = A2 * Radian
Bf = A3 * Radian
Lf = A4 * Radian

Ga = Le - Lf

'Grundformeln zur Winkelberechung:
'Zw = Cos(be) * Cos(ga) * Cos(bf) + Sin(be) * Sin(bf)
'Zw = Atn(zw / Sqr(1 -zw * Zw))
'Zw = Pi / 2 - Zw

'Bear =((sin(bf) - Sin(be) * Cos(zw)) /(cos(be) * Sin(zw)))
'Bear = Atn(bear / Sqr(1 -bear * Bear))
'Bear =(pi / 2 -bear) / Radian
'Zerlegung der Formeln:

Zw1 = Cos(be)
Zw2 = Cos(ga)
Zw3 = Cos(bf)
Zw2 = Zw1 * Zw2
Zw3 = Zw2 * Zw3
Zw1 = Sin(be)
Zw2 = Sin(bf)
Zw2 = Zw1 * Zw2
Zw = Zw2 + Zw3

Zw1 = Zw * Zw
Zw1 = 1 - Zw1
Zw1 = Sqr(zw1)
Zw = Zw / Zw1
Zw = Atn(zw)

Zw1 = Pi / 2
Zw = Zw1 - Zw

Bear1 = Sin(bf)
Bear2 = Sin(be)
Bear3 = Cos(zw)
Bear3 = Bear3 * Bear2
Bear1 = Bear1 - Bear3
Bear2 = Cos(be)
Bear3 = Sin(zw)
Bear2 = Bear2 * Bear3
Bear = Bear1 / Bear2

Bear1 = Bear * Bear
Bear1 = 1 - Bear1
Bear1 = Sqr(bear1)
Bear = Bear / Bear1
Bear = Atn(bear)

Bear1 = Pi / 2
Bear = Bear1 - Bear
Bear = Bear / Radian

Ga = Sin(ga)
If Ga >= 0 Then Bear = 360 - Bear

Z = Str(dist)
Y = Val(z)
X = Fusing(y , "#.#")

W = Str(bear)
V = Val(w)
U = Fusing(v , "#.#")

Locate 1 , 1
Lcd "DST: " ; X ; " Km"
Locate 2 , 1
Lcd "BRG: " ; U ; " Grad"

End

digitali
24.02.2006, 13:44
Hallo gpsklaus,

ist nicht wirklich interessant fuer mich, da offensichtlich das Ursprungslisting von mir stammt:

http://www.speckmann.de/atmel/koordinatenberechnung.htm

Aber macht nichts, ich hab da kein Problem mit. :)
Uebrigens habe ich auf einem GLCD schonmal rudimentaer versucht den Winkel grafisch darzustellen:

http://www.speckmann.de/atmel/gps_test.htm

Der Winkel wird zunaechst noch von einer for-next Schleife erzeugt. Spaeterhin wird die erste Koordinate aus einer Mouse ausgelesen und die Eingabe der zweiten Koordinate erfolgt mittels Drehimpulsgeber. Alles andere wird laufend vom Atmel berechnet und ausgegeben.

Mit freundlichen Gruessen
Digitali

gpsklaus
24.02.2006, 14:26
Hallo Digitali

> ist nicht wirklich interessant fuer mich, da offensichtlich das Ursprungslisting von mir stammt:

http://www.speckmann.de/atmel/koordinatenberechnung.htm

> Aber macht nichts, ich hab da kein Problem mit. :)

Sorry, aber diese Seite war mir nicht bekannt. Ich hatte eine für VisualBasic geschriebene Winkelroutine und sie dann für Bascom-AVR modifiziert. Letztendlich müssen sich die Ergebnisse aber immer irgendwie ähneln.

> Uebrigens habe ich auf einem GLCD schonmal rudimentaer versucht den Winkel grafisch darzustellen:

http://www.speckmann.de/atmel/gps_test.htm

> Der Winkel wird zunaechst noch von einer for-next Schleife erzeugt. Spaeterhin wird die erste Koordinate aus einer Mouse ausgelesen und die Eingabe der zweiten Koordinate erfolgt mittels Drehimpulsgeber. Alles andere wird laufend vom Atmel berechnet und ausgegeben.

Das sieht interessant aus

Klaus