Forum: Compiler & IDEs "echter" double mit AVR-GCC


von Andreas (Gast)


Lesenswert?

Hallo,

ich habe ein Funktion zur Berechnung der Wegstrecke zwischen 2 
GPS-Koordinaten geschrieben. Diese verwendet double-Datentypen. Da GCC 
aber anscheinend keinen echten double verwendet, habe ich Probleme mit 
der Genauigkeit von "nur" 6 Stellen.
Wenn die Koordinaten eng beisammen sind, ergibt sich bereits ein relativ 
großer Fehler. Beim Aufaddieren der Abstände zwischen den einzelnen 
Koordinaten ergibt sich folglich ein erheblicher Fehler (Bsp. 300 
Koordinaten, Länge am PC errechnet: 750m, Länge am AVR berechnet: 
312m!!!).

Gibt es eine Möglichkeit, die Genauigkeit im GCC zu erhöhen oder hat 
jemand eine optimierte Formel zur Berechnung der Differenz?
Ich verwende folgende Formel:

d = 2 * asin(sqrt((sin((lat1 - lat2) / 2)) ^ 2 + cos(lat1) * cos(lat2) * 
(sin((lon1 - lon2) / 2)) ^ 2))

Das Ergebnis ist die Länge in nautischen Meilen.

Danke für eure Hilfe.

mfg
Andreas

von Oliver (Gast)


Lesenswert?

Diese Formel ist bezüglich der Rundungsfehler schon optimiert. Da hängt 
es eher an der internen Implementation der trigonometrischen Funktionen 
im AVR-GCC.

Was spricht dagegen, die Gesamtstrecke nicht als Summe der einzelnen 
Teilstrecken, sondern als Entfernung Startpunkt-Zielpunkt zu berechnen?

von Oliver (Gast)


Lesenswert?

^^ Bin beim obigen Post aus einem mir jetzt nicht mehr einleuchtenden 
Grund davon ausgegangen, daß du eine "gerade" Strecke zurücklegst...

von Andreas (Gast)


Lesenswert?

Hallo Oliver,

genau das ist das Problem. Bei einer geraden Strecke würde der Fehler 
erträglich sein, aber durch das Aufaddieren entsteht ein relativ großer 
Fehler. Bin gerade auf der Suche nach Fixed-Point-Berechnungen für 
sin/cos/asin.

mfg
Andreas

von Philipp (Gast)


Lesenswert?

Ist jetzt nur eine Idee ohne zu wissen ob es hier was bringt, aber 
vielleicht sollte man sich die Taylor Reihen der einzelnen Funktionen 
mal ansehen und gucken ob man die Formel dann noch etwas vereinfachen 
kann.

Gruß Philipp

von Andreas (Gast)


Lesenswert?

Hallo Philipp,

danke für den Tipp. Bin gerade dabei, dass ich sin/cos für Fixed-Point 
implementiere. +, -, *, / und abs() habe ich schon.

mfg
Andreas

von Philipp C. (ba4_philipp)


Lesenswert?

Fein :) Kannst du uns dann auch an den Ergebnissen teilhaben lassen? 
Habe auch noch vor mit dem GPS Kram rumzuspielen.

Gruß Philipp

von Andreas (Gast)


Lesenswert?

Hallo,

hab jetzt ziemlich viel Zeit investiert, um eine höhere Genauigkeit zu 
erreichen. Leider ohne Erfolg. Ich habe in FixedPoint (8.24) 
sin/cos/sqrt implementiert, aber trotzdem reicht die Genauigkeit nicht 
für die Berechnung kleiner Wegstrecken aus. Bei einer Distanz von 
mehreren km ist es kein Problem. Ist der Abstand aber kleiner 10m, so 
kommt bei den Berechnungen immer 0 raus.
Wenn man zu Fuß unterwegs ist, wird man pro Sekunde (GPS-Daten kommen 
1x/s) nicht viel Meter zurücklegen. Somit habe ich als Summe der 
Wegstrecke immer 0.

Jetzt ist die Frage, ob ein anderer Compiler double precision 
unterstützt. Vielleich IAR oder so?

Hat da jemand Erfahrung damit?

mfg
Andreas

von Michael Wilhelm (Gast)


Lesenswert?

IAR hat einen extra Schalter für 64 bit Double. Hab aber damit noch 
nicht gearbeitet.

MW

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Den GCC selbst auf 64-bit-double zu bringen, ist sicher auch gar kein
großer Akt.  Allerdings müsste sich eben jemand hinsetzen und eine
libm.a für 64 bit FP bauen.

von Reiner (Gast)


Lesenswert?

"Bei einer Distanz von mehreren km ist es kein Problem. Ist der Abstand 
aber kleiner 10m, so kommt bei den Berechnungen immer 0 raus."

Was benutzt Du denn für ein GPS.  Normalerweise liegt der 
Positionsfehler bei GPS im günstigsten Fall bei 15m, kann aber leicht 
auch mal bis >50m hochgehen.  Differential-GPS geht runter bis 1-3m 
erfordert aber einen zusätzlichen terrestrischen Empfangskanal.

Wo liegt also das Problem mit Abständen von 10m?

R.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

15-50 m? Da hast du aber einen sehr schlechten Empfänger. Beim SIRF III 
sieht der Fehler unter guten Empfangsbedingungen ungefähr so aus:
http://www.pocketnavigation.de/pictures/article/3483_1.jpeg

von Andreas (Gast)


Lesenswert?

@Reiner: das merkt man auch, wenn der Empfänger am selben Ort liegt, 
aber lt. Koordinaten die Position sehr stark abweicht (hatte schon ca. 
50m bei schlechterem Empfang!).

Laut Rückrechnung ergibt sich bei einer Differenz von 1m eine Änderung 
der Longitude von 0,00000952". Da ich aber nur 0,0001" Auflösung habe, 
habe ich sowieso ein Problem...

mfg
Andreas

von Francesco N. (franceso-)


Lesenswert?

8.24 kannst du nur nutzen, wenn du die 360 Grad in 256 umrechnest, inkl.
den Nachkommastellen. Dies kann unter umstaenden die Berechnungen sehr
beschleunigen. Ich habe das mit fixed-point mal gemacht, mit einer 
multiplication sowie ein paar shifts/additionen, fuer die Rundungen.
Grundsaetzlich habe ich damals 16.16 Float genommen, auch weil ich
sin usw. im bereich von 0-1 hatte (16bit table lookup+interpolation).
Habe aber auch ein Scaling gemacht, aber das war Applikationsspezifisch.

von Michael (Gast)


Lesenswert?

> Jetzt ist die Frage, ob ein anderer Compiler double precision
> unterstützt. Vielleich IAR oder so?

Der macht das problemlos und rechnet sehr schnell.

> Allerdings müsste sich eben jemand hinsetzen und eine
> libm.a für 64 bit FP bauen.

Das macht bekanntlich niemand, da 'float' in 'Fachkreisen' immer wieder 
schlechtgeredet wird und 'double' sowieso niemand braucht.
GPS ist nun mal ne Anwendung, wo man sich nicht mehr um 'double' 
herummogeln kann.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Michael wrote:

>> Allerdings müsste sich eben jemand hinsetzen und eine
>> libm.a für 64 bit FP bauen.

> Das macht bekanntlich niemand, da 'float' in 'Fachkreisen' immer wieder
> schlechtgeredet wird und 'double' sowieso niemand braucht.

Quark.  Es gibt hinreichend viele Requests dafür, nur keinen, der sich
bislang der Aufgabe hätte annehmen wollen.

von Francesco N. (franceso-)


Lesenswert?

Wiso nimmst du nicht FP, auch 64bit FP wird von GCC unterstützt.

von Karl heinz B. (kbucheg)


Lesenswert?

> auch 64bit FP wird von GCC unterstützt.

Auf einem AVR?
Das wär ja ganz was Neues.

(Wenn FP Floating Point heissen soll)

von Francesco N. (franceso-)


Lesenswert?

Sorry, fixed point,

von Karl heinz B. (kbucheg)


Lesenswert?

Wie sieht hier die Unterstützung aus?
Datentypen + Operationen
Das wäre äusserst nützlich, wenn man da keine
externen Libraries brauchen würde.

von Rolf Magnus (Gast)


Lesenswert?

Hab ich auch noch nie davon gehört. Irgendwo auf meiner Platte rotiert 
aber noch ein angefangenes Fixedpoint-Klassentemplate für avr-g++ mit 
per Template-Argument wählbarer Anzahl an Vor- und Nachkommabits. Gips 
aber keine trigonometrischen Funktionen für, und die Klasse ist auch 
weder fertig, noch getestet. Muss ich mal bei Gelegenheit dran 
weiterbasteln.

von Andreas (Gast)


Lesenswert?

@Francesco Na: wo finde ich diese Module? Wenn das implementiert wäre, 
wäre das sehr hilfreich.

Danke für die Infos.

mfg
Andreas

von Michael (Gast)


Lesenswert?

> Quark.  Es gibt hinreichend viele Requests dafür, nur keinen, der sich
> bislang der Aufgabe hätte annehmen wollen.

Das ist ja auch kein Wunder. Wenn hier (Forum) ein Problem auftritt, das 
sich einfachst mit 'float' lösen ließe, wird gleich geschrieen, daß man 
das nicht machen darf, weil es viel zu langsam sei, .....
Man nehme gefälligst 'int' und schlimmstenfalls 'long' und skaliere bis 
zum Abwinken.
Das ist keine Motivation für irgendeinen , die Grundrechenarten als 
'double' zu implementieren. Für sin(), cos(), usw. gib es ja die 
entsprechenden Routinen in C, mit recht effizienten Reihen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Michael wrote:

> Das ist keine Motivation für irgendeinen , die Grundrechenarten als
> 'double' zu implementieren. Für sin(), cos(), usw. gib es ja die
> entsprechenden Routinen in C, mit recht effizienten Reihen.

Eben um die Implementierung dieser Routinen ging es mir aber.  Die
gibt es nicht ,,in C'', sondern die müsste jemand für avr-libc's
Mathematikbibliothek in 64 bit implementieren.  Andernfalls wäre das
mögliche GCC-Feature ziemlich sinnfrei.  Die Implementierung des
GCC-Features trau ich mir beinahe zu (ist letztlich ein Mischmasch
zwischen 64-bit int und 32-bit float), aber eine effiziente Reihe für
den AVR zu entwickeln ist jenseits dessen, was ich aus dem Handgelenk
schüttele.  (Die GCC-Implementierung bietet natürlich auch noch
genügend Brot in den Details, man will schließlich wohl am Ende einen
Schalter -mdouble32 haben analog zu -mint8.)

Diejenigen, die potenziell in der Lage sind, obiges zu erledigen,
werden sich kaum vom gelegentlichen Gequake ,,double nimmt man einfach
nicht'' abhalten lassen.  Eher von der fehlenden Zeit, das anzugehen.

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

@Jörg

Ist es dies, was Du bräuchtest ?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Naja, letztlich sollte es schon für den AVR optimiert sein.  Wenn
ich mir das so angucke fürchte ich, dass das ein ziemlicher Klopper
wird.  Ich häng dir mal zum Vergleich die jetzige Implementierung
von atan2() der libm aus der avr-libc an.

von Michael (Gast)


Lesenswert?

Klopper hin, Klopper her. Die uralte Routine habe ich auf die Schnelle 
gefunden. Bei anderen GNU-Quellen hatte ich auch mehr C-Quellen für 
trigon.+andere Funktionen gefunden, allerdings nicht mehr aktuell auf 
der Platte verfügbar. Das wird sich alles wiederfinden lassen.

Um sich nicht gleich Knüppel zwischen die Beine zu werfen, würde ich 
vorschlagen, je nach Compiler-Schalter entweder nur 32bit oder nur 64bit 
rechnen zu lassen: gleiche Größe für 'float' und 'double'.
Ferner wird man einen Prozessor mit wohl 32k Flash benötigen. Wenn ich 
meine Mega128-Programme ansehe, da ist Platz im Flash noch und nöcher. 
Und wenn ein sin() vielleicht 2-3ms dauert, wer es braucht, kann damit 
leben. Kopfrechnen dauert länger.


Dazu bräuchte man
1. die Grundrechenarten einschließlich Rundung und Vergleichsoperationen
2. eine Compilerversion, die alle float/double mit 64bit verarbeitet.
3. eine libm64.a, die die notwendigen Funktionen zur Verfügung stellt.

Punkt 1 müßte in Assembler erledigt werden, da hiervon die 
Verarbeitungsgeschwindigkeit maßgeblich abhängt. Die Routinen sollten 
rekursiv und reentrant verwendbar sein.
Punkt 2 müßte in der Compilerquelle angepaßt werden.
Punkt 3 müßte die C-Quellen für alle Funktionen durchnudeln und eine lib 
erzeugen.

Gretchenfrage: wer macht Punkt 1 ?

von Andreas (Gast)


Lesenswert?

Danke für eure interessanten Ideen. Ich habe versucht, die Berechnung 
mit FixedPoint (64 Bit) zu lösen. Doch das scheitert an mehreren 
Punkten:

1. ich bräuchte für *, / einen 128 Bit Datentyp, oder aufwändige 
Schiebeoperationen
2. die Implementierung in C ist extrem (!!) speicherintensiv. Ein 
ATmega32 reicht hier bei weitem nicht aus. Implementierung in Assembler 
ist mir zu mühsam.
3. Kosten für anderen Compiler sind zu hoch

Deshalb werde ich einfach einen anderen Controller einsetzen, dessen 
Compiler einen echten double unterstützt (Renesas M16C). Den haben wir 
im Haus und kostet somit nichts.

mfg
Andreas

von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Wegen Numerikproblemen den Mikrocontroller wechseln? Bißchen 
zweifelhaft, die Strategie.

Du machst in Deiner Formel asin(sqrt(sin . Ich nehme an, daß das 
numerisch ungünstig ist. In
Beitrag "Re: GPS - MOUSE - MINI- NAVIGATOR (Assembler) ATmega8" habe ich mal nen 
Excelsheet gepostet, dessen Berechnungsmethode vielleicht numerisch 
günstiger ist.

Michaels atan2.c und Jörgs atan2.s sind nicht fair vergleichbar, weil in 
atan2.c der atan selbst mitberechnet wird, atan.c selbst ist ne 
Vorverarbeitung, welche den atan selbst als Funktion nur aufruft.

Für die Freunde des atan2: angehängt ne C-Routine, die aus 2 short 
Real/imag einen short mit Cordic nen Winkel macht. Genau wie sau und hat 
für meine Zwecke immer gelangt.

Cheers
Detlef

von Andreas (Gast)


Lesenswert?

Hallo Detlef,

danke für die Infos. Der Wechsel des Controllers ist kein Problem, da 
ich noch in der Evaluierungsphase bin und Librarys (RS232, etc.) für 
beide Controller habe. Mal schauen, ob nach der Machbarkeitsstudie ein 
Go für das Projekt rauskommt...

mfg
Andreas

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.