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
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?
^^ Bin beim obigen Post aus einem mir jetzt nicht mehr einleuchtenden Grund davon ausgegangen, daß du eine "gerade" Strecke zurücklegst...
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
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
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
Fein :) Kannst du uns dann auch an den Ergebnissen teilhaben lassen? Habe auch noch vor mit dem GPS Kram rumzuspielen. Gruß Philipp
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
IAR hat einen extra Schalter für 64 bit Double. Hab aber damit noch nicht gearbeitet. MW
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.
"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.
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
@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
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.
> 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.
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.
> auch 64bit FP wird von GCC unterstützt. Auf einem AVR? Das wär ja ganz was Neues. (Wenn FP Floating Point heissen soll)
Wie sieht hier die Unterstützung aus? Datentypen + Operationen Das wäre äusserst nützlich, wenn man da keine externen Libraries brauchen würde.
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.
@Francesco Na: wo finde ich diese Module? Wenn das implementiert wäre, wäre das sehr hilfreich. Danke für die Infos. mfg Andreas
> 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.
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.
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.
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 ?
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.