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
Gast
#6391670
> 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
Hmmmm, und wie stelle ich das an?
Gast
#6391698
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?
Gast
#6391743
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
1 | |
und weiter ungefähr zu
1 | |
Wenn du es genau wissen willst, musst du es binär hin schreiben. https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats
Gast
#6391762
Nur eps ist schon als double deklariert und die Konstanten sind es auch, wenn eben nicht per Compiler Option umgebogen.
Gast
#6391780
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.
Gast
#6391781
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.
Gast
#6391801
Ich meinte, mit welcher Methode kontrollierst du das Ergebnis? Debugger?
öhm, ich weiss nicht genau was du meinst;
Serial.print("eps= ");
Serial.println(eps,15);
Meintest du so etwas?
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.
Gast
#6391823
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
1 | |
? Beim STMDuino sollte das gehen.
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.
Gast
#6391851
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?
Gast
#6391876
Thomas G. schrieb: > Core dürfte 1.8.3 sein. Dann wird das der Roger Clark core sein. Im PrintFloat steht als Kommentar:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/cores/maple/Print.cpp Ob der Algorithmus die double Nachkommas richtig ausgibt weiss ich nicht. probiere es mit dem STM32duino core, der sollte das Serial.printf unterstützen. oder per sprintf() in einen buffer schreiben und dann ausgeben.
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.
Gast
#6391887
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.
Gast
#6391891
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.
Gast
#6392058
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 | |
2 | |
3 | |
Wenn nicht, dann ist irgendwo versteckt etwas verbogen. Per default rechnet der gcc mit ARM eabi mit double.
Gast
#6393212
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.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
@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.
Also, die Formeln und der Rechenweg geben eine Genauigkeit von ca 1 min her.
Thomas G. schrieb: > Also, die Formeln und der Rechenweg geben eine Genauigkeit von ca 1 min > her und das reicht dir oder nicht?
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:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
Hierbei gab es dann die folgenden Ergebnisse:
1 | |
2 | |
3 | |
4 | |
Es machte keinen Unterschied, ob ich das Programm mittels "gcc" oder "gcc -m32" kompilierte.
Gast
#6396490
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.
Gast
#6396830
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!
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
