Moin zusammen,
ich hab hier ein STM32 F103 den ich mit der Arduino-IDE programmiere.
Für astronomische Berechnungen brauche ich folgende Formel:
double eps;
eps=279.6966778+36000.76892*ta+0.0003025*(ta*ta); //ta=1.20658453
Der STM liefert als Ergebnis: 43717.668 006 321 1;
Wolfram Alpha: 43717.667 965 170 291 580.... (Taschenrechner auch)
(Ich nehme mal an, dass WA genauer ist...)
Ich war bis dahin der Meinung, dass die Verwendung eines STM zur
32-Bitrechnerei ausreichend sei. Vermutlich hab ich mich dann doch
getäuscht. Wo liegt mein Fehler.
Thomas
> Ich war bis dahin der Meinung, dass die Verwendung eines STM zur> 32-Bitrechnerei ausreichend sei.
Ist er auch, aber für die von Dir gewünschte Genauigkeit wirst Du echte
double (mit 64 bit) brauchen. Auch dafür reicht jener stm32 locker.
Deine Zahlenbeispiele legen allerdings nahe, dass Du nur mit 32-bit
floats rechnest.
HTH
Das sollten schon double sein. Beim Compiler gibt es eine Option die
Konstanten als float zu betrachten, das müsste dann in den Compiler
Aufrufen zu sehen sein. Ist aber eine Holzhammermethode und eher
unschön. Aber in vielem AVR Arduino code wird einfach immer double
genommen und das produziert beim ARM unnötig viel/langsamen Code.
Vielleicht ist deshalb so eine Option gesetzt?
Thomas G. schrieb:> Ich war bis dahin der Meinung, dass die Verwendung eines STM zur> 32-Bitrechnerei ausreichend sei. Vermutlich hab ich mich dann doch> getäuscht. Wo liegt mein Fehler.
Bei 32-Bit hast du im IEEE 754 binary32 Format (Single Precision) nur 24
Bit oder 7.22 Digits. Wenn du dann Additionen mit so verschieden großen
Zahlen machst, gehen dir die Nachkommastellen flöten.
> eps=279.6966778+36000.76892*ta+0.0003025*(ta*ta); //ta=1.20658453
wird zu
Johannes S. schrieb:> Nur eps ist schon als double deklariert und die Konstanten sind es auch,> wenn eben nicht per Compiler Option umgebogen.
Damit die "double" wirklich double sind, darf der Compiler dann aber
keine 32-Bitrechnerei machen (wie es z.B. auf einem AVR passiert),
sondern muss wirklich 64 Bit für die Zahlen verwenden.
Wolfgang schrieb:> sondern muss wirklich 64 Bit für die Zahlen verwenden.
Ja, und das macht die newlib die beim gcc für die Cortex-M verwendet
wird.
Thomas G. schrieb:> Der STM liefert als Ergebnis:
Und wie wird das ausgegeben? Evtl beschneidet das Arduino Print das
Ergebnis.
Johannes S. schrieb:> Und wie wird das ausgegeben? Evtl beschneidet das Arduino Print das> Ergebnis.
Die ersten beiden Nachkommastellen passen, die dritte evtl als gerundet.
Danach passt nichts mehr.
Thomas G. schrieb:> Die ersten beiden Nachkommastellen passen, die dritte evtl als gerundet.> Danach passt nichts mehr.
Wie weiter oben geschrieben: Bei 32-Bit-Fließkommazahlen hast du 24 Bit
(= ca. 7 Dezimalstellen) für die Ziffern selber, die restlichen Bits
definieren "wo das Komma hinkommt".
Du hast 5 Stellen vor dem Komma und zwei danach genau. Passt also exakt
auf die 32-Bit-Float Theorie.
Das war mir vorher auch so in etwa klar, ich war jedoch aus mangelnder
Erfahrung der Meinung, dass 'double' in Verbindung mit dem STM dieses
Problem umgeht.
Thomas G. schrieb:> dass 'double' in Verbindung mit dem STM dieses> Problem umgeht.
dann zeig mal den Code, wo du das "double" hingeschrieben hast.
das "double eps;" hat z.B. keine Wirkung auf die Berechnung, wenn "ta"
als float (mit 32 Bit) definiert ist.
Thomas G. schrieb:> dass 'double' in Verbindung mit dem STM dieses> Problem umgeht.
das ist auch richtig. Also macht das Print etwas falsch oder es wird mit
Compileroptionen AVR kastriert. Was eigentlich Quatsch ist.
Kennt der Arduino Core (welchen benutzt du?) ein
Mit dem Befehl kann der Compiler nichts anfangen "
no matching function for call to 'print(const char [8], double&)'"
printf ist auch unbekannt
Arduino: 1.8.12 (Windows 10), Board: "Arduino Uno WiFi Rev2, ATMEGA328"
<- natürlich Quatsch, stm ist eingestellt
Core dürfte 1.8.3 sein.
ta und eps sind beide im Header als double deklariert.
Thomas G. schrieb:> Das war mir vorher auch so in etwa klar, ich war jedoch aus mangelnder> Erfahrung der Meinung, dass 'double' in Verbindung mit dem STM dieses> Problem umgeht.
Dann prüfe es nach.
Wie klein darf eps werden, ohne dass 1 + eps == 1 ist?
Also, um die Katze aus dem Sack zu lassen, dass Ganze ist nur ein
kleiner Zwischenschritt um den Sonnenauf-/untergang zu berechnen. eps
wird sich ziemlich genau um diesen Wert bewegen. Dabei sind die
Nachkommastellen das kriegsentscheidende. Wem es weiterhilft, ich habe
mal den Code angefügt. Interessant wird es ab //47.
PI aus math.h wird übrigens mit gewünschter Genauigkeit angezeigt. Für
mich heute aber nicht mehr. Ich danke euch bis hierhin.
Johannes S. schrieb:> oder per sprintf() in einen buffer schreiben und dann ausgeben.
Das ist doch alles ein Nebenschauplatz. Für irgendwelche Berechnungen
sollte es doch völlig wurscht sein, mit wieviel gültigen Stelle
sprintf(), Serial.printf() oder sonst eine Ausgabe daher kommt.
Hauptsache ist, dass die Berechnung mit der erwarteten Stellenzahl
läuft.
Thomas G. schrieb:> Für> mich heute aber nicht mehr.
für mich auch, ich hätte einen µC mit in den Urlaub nehmen sollen :)
Aber auch ein CM0 rechnet doubles mit 64 Bit. Das ist ja die Crux wenn
man eine Arduino Lib portiert und irgendeine Konstante ohne 'f' suffix
drin hat, dann sprengt es gleich den Flash.
ein virtuelles Target habe ich, da läuft ein cross compiler der die
Mathematik richtig emulieren sollte. Auf dem kommt in Mbed das richtige
raus.
https://simulator.mbed.com/#user_1599113530283
Die Größe von float/double kann man ja mal den Compiler anzeigen lassen,
da sollte auch 4/8/8 rauskommen:
1
Serial.println(sizeof(float));
2
Serial.println(sizeof(double));
3
Serial.println(sizeof(1.20658453));
Wenn nicht, dann ist irgendwo versteckt etwas verbogen. Per default
rechnet der gcc mit ARM eabi mit double.
ich habe mal das ganze Programm umgeschrieben damit es im Simulator
läuft, da sieht man das die Berechnung korrekt ist.
Der 'Fehler' liegt in der Genauigkeit von ta, das in der
Vergleichsrechnung aus dem Kommentar benutzte hat eine reduzierte
gegenüber dem was das Programm berechnet.
Das Programm rechnet also korrekt mit 64 Bit FP.
@von Johannes S.
ich habe mal das ganze Programm umgeschrieben damit es im Simulator
läuft, - das ist nett von dir!
da sieht man das die Berechnung korrekt ist. - das beruhigt mich.
Der 'Fehler' liegt in der Genauigkeit von ta, - ?
das in der
Vergleichsrechnung aus dem Kommentar benutzte hat eine reduzierte
gegenüber dem was das Programm berechnet.
Das Programm rechnet also korrekt mit 64 Bit FP. - s.o.
Dann will ich mal sehen, dass ich das genauer hin bekomme. Das da schon
der Fehler liegt, wäre ich ohne Tip nicht drauf gekommen.
Bei der Angabe ta handelt sich übrigens um die "Anzahl der Jahrhunderte"
seit 0.1.1900. (ist eine Rechenhilfe der Astronomen).
Ich hab mir mal auf die Schnelle einen DUE geholt (braucht man immer
mal), aber selbes (falsches) Ergebnis :(
Thomas G. schrieb:> dass Ganze ist nur ein> kleiner Zwischenschritt um den Sonnenauf-/untergang zu berechnen
hmmm, die normale Arduinogenauigkeit reicht aber absolut dafür sogar auf
dem nano, bei mir seit 2015 für meine Rolladen automatisiert zu fahren.
Je nach Rechenmodell wechselt die Genauigkeit nur zwischen Küche,
Wohnzimmer und Schlafzimmer.
Ich denke ob double oder höher macht nichts dafür, aber mag sein das es
einige genauer wünschen.
Wenn ich dahin gekommen wäre, würde ich hier nicht nachfragen. Im Moment
schwankt die Ungenauigkeit abhängig vom Datum um 1 - 5 Minuten (hab
nicht jedes Datum ausprobiert), das ist zumindest unschön.
Bei der Verwendung von Extended-Datentypen wie z.B. "long double" sollte
man unbedingt darauf achten, auch bei numerischen Literalen den
entsprechenden Datentyp anzugeben. Ich habe mal das folgende kleine
Progrämmchen auf einem Linux-Rechner ausprobiert:
ich habe auch eine Rolladensteuerung, die Zeiten lasse ich aber zentral
von einem SunEvents Node in NodeRed berechnen:
https://github.com/freakent/node-red-contrib-sunevents
bzw. der benutzt SunCalc:
https://github.com/mourner/suncalc/blob/master/suncalc.js
Ist JavaScript, aber die Mathe ist ja sehr C++ ähnlich und JS rechnet
auch mit double. Das sollte sich also auch relativ leicht nach C++
konvertieren lassen. Bzw. vielleicht gibt es das auch schon auf github.
Johannes S. schrieb:> die Zeiten lasse ich aber zentral> von einem SunEvents Node in NodeRed berechnen:
genau das wollte ich vermeiden. Es sollte eine StandAlone-Lösung werden.
Hallo,
wie wäre es, Sonnenauf- und Untergangszeiten einmal für ein ganzes Jahr
zu berechnen, und dann als Tabelle (für jeden Tag 2 Zahlen, jeweils
Minuten nach Mitternacht) abzuspeichern?
So habe ich es bei meiner Beckhoff-Steuerung in ST gemacht. Ich denke,
der Fehler über die Jahre wird nicht sehr groß werden.
Man könnte die Berechnung auch mit einer vereinfachten Formel (Link)
machen, angeblich ist der Fehler für Deutschland absolut unter 2
Minuten. Damit kann ich leben.
https://lexikon.astronomie.info/zeitgleichung/
- Hermann-Josef
Thomas G. schrieb:> Im Moment> schwankt die Ungenauigkeit abhängig vom Datum um 1 - 5 Minuten (hab> nicht jedes Datum ausprobiert), das ist zumindest unschön.
bei meiner Rolladensteuerung stört das nicht, es ist ja auch immer
verschieden hell je nach Wolken am Himmel, also wenn dann hilft das nur
mit einem LDR draussen!
Momentan stören mich die Minuten nicht die die Rolläden zu früh oder zu
spät fahren in Abhängigkeit der Helligkeit!