Hallo, Ich habe einen Drucksensor mit einem Messbereich von 0 - 10 bar und einen mit -1 - +1 bar. Beide geben eine analoge/lineare Spannung von 1-5 Volt aus. Die wird runter geteilt auf 1,235V und mit einem 10bit ADC eingelesen. Bei einer Spannungsausgabe von 0-5 Volt wäre ja die Rechnung für den Druck ganz "normal": U = 1,235 * (ADC/1023) Druck = 10 * (U/1,235) Da mein Spannungsbereich am Sensor aber erst bei einem Volt beginnt, beträgt die Spannung am ADC 0,247 - 1,235V bzw. seine Werte von 205 - 1023 (Hab ich mir zumindest so zusammengereimt). Kann mir jemand sagen wie ich die Formel mit dem o.ä. Spannungsbereich aussehen müsste und wie würde sie mit dem Sensor: -1 - +1 Bar aussehen. Danke im Voraus. Alex
Alexander K. schrieb: > Kann mir jemand sagen wie ich die Formel mit dem o.ä. Spannungsbereich > aussehen müsste und wie würde sie mit dem Sensor: -1 - +1 Bar aussehen. Sowas konnte früher (tm) ein Schüler der 8. Klasse berechnen. In welche Klasse gehst du? Siehe AD-Wandler.
na ja, der Messbereich umfasst halt 2 Bar zwischen -1 und +1. Damit liegt "0" bar genau "in der Mitte", also bei 512, 0 enspricht "-1" Bar und 1023 "+1" bar. Oder in deiner Formel Druck = -1 + 2*(U/Umax) Das "Da mein Spannungsbereich am Sensor aber erst bei einem Volt beginnt" verstehe ich nicht
Michael P. schrieb: > na ja, der Messbereich umfasst halt 2 Bar zwischen -1 und +1. Damit > liegt "0" bar genau "in der Mitte", also bei 512, Nö. Denk nochmal nach. > Das "Da mein Spannungsbereich am Sensor aber erst bei einem Volt > beginnt" verstehe ich nicht Dort liegt dein Problem.
Michael P. schrieb: > Das "Da mein Spannungsbereich am Sensor aber erst bei einem Volt > beginnt" verstehe ich nicht Alexander K. schrieb: > Beide geben eine analoge/lineare Spannung > von 1-5 Volt aus. Das bedeutet im Falle des 0-10-Bar-Sensors, daß 1V 0 Bar entsprechen, und 5V 10 Bar.
Alexander K. schrieb: > (ADC/1023) Sollte da nicht 1024 stehen, wie im Datenblatt beschrieben? Alexander K. schrieb: > Kann mir jemand sagen wie ich die Formel mit dem o.ä. Spannungsbereich > aussehen müsste und wie würde sie mit dem Sensor: -1 - +1 Bar aussehen. Lineare Interpolation. oder Geradengleichung. In der Arduino Welt: https://www.arduino.cc/reference/de/language/functions/math/map/
Arduino F. schrieb: > Alexander K. schrieb: >> (ADC/1023) > Sollte da nicht 1024 stehen Korrekterweise und schon allein um es dem Compiler einfacher zu machen sollte da 1024 stehen. Siehe den Beitrag "ADC-Spannung korrekt berechnen?" und den darin verlinkten Beitrag "1023 oder 1024" Für mich sind 1023 an dieser Stelle schlicht ein Programmfehler. Und wenn ich diesen Fehler sehe, dann sind da sicher noch mehr...
:
Bearbeitet durch Moderator
Falk B. schrieb: > In welche > Klasse gehst du? Ich gehe in gar keine Klasse und arbeite üblicherweise auch nicht in der Branche ;) Lothar M. schrieb: > Siehe den Beitrag "ADC-Spannung korrekt berechnen?" und den darin > verlinkten Beitrag "1023 oder 1024" Danke für den Hinweis.
Wenn da im Nullfall immer 1 Volt am Eingang steht, musst du diesen Offset eben abziehen.
Alexander K. schrieb: > Ich gehe in gar keine Klasse und arbeite üblicherweise auch nicht in der > Branche ;) Schon mal was von einer linearen Geradengleichung gehört?
1 | Sensor ADC-Eingang ADC-Wert Druck1 Druck2 |
2 | 1V 0,247V 205 0bar -1bar |
3 | 3V 0,741V 615 5bar 0bar |
4 | 5V 1,235V 1023 10bar 1bar |
5 | |
6 | p = f(adc) = M*ADC+N |
7 | |
8 | // 10 Bar Sensor |
9 | M = dy/dx = (10bar-0bar)/(1023-205)=0,0122 bar/LSB |
10 | N = P2-M*ADC = 10bar - 0,0122bar/LSB*1023 = -2,506bar |
11 | |
12 | // +/-1 Bar Sensor |
13 | M = dy/dx = (1bar- -1bar)/(1023-205)=0,002445 bar/LSB |
14 | N = P2-M*ADC = 1bar - 0,002445bar/LSB*1023 = -1,5bar |
Man kann das mit Fließkomma rechnen und ist fertig. Man kann aber auch 5 Minuten nachdenken und Festkommaarithmetik benutzen. Wenn man alles in Millibar rechnet, braucht es keine Kommas. Dabei darf im Zwischenergebnis kein Überlauf auftreten, also Rechnung mit 32 Bit. Beim +/1bar Sensor reichen die Millibar nicht, da muss man eher auf Mikrobar gehen. Klingt komisch, ist aber so. Kann man aber am Ende wieder auf Millibar umrechnen.
1 | int p; |
2 | p = 122 * (int32_t)ADC - 2506; // 10 bar Sensor |
3 | p = (2445 * (int32_t)ADC - 1500000) / 1000; // +/-1 bar Sensor |
Matthias S. schrieb: > Wenn da im Nullfall immer 1 Volt am Eingang steht, musst du diesen > Offset eben abziehen. Nullfall? Ich kenn einen Wasserfall und Durchfall, aber keinen Nullfall ;-)
Moin, ich habe so einen Drucksensor in mein Heizungsrohr eingebaut. Liefert auch von 1 bis 5 V. Dann ist es etwas in Vergessenheit geraten. Ich hatte vor, wie in anderen Schaltungen die Werte mit einem ATtiny84 zu messen und zu speichern. Abfrage über I2C. Der hat die Möglichkeit über“ Differential ADC Channel“ zu messen. Leider ist der Minuspol mit dem Gehäuse verbunden und somit der „Rauschabstand“ kleiner. Dadurch ist es für mich günstiger mit 5V VCC ADC Input Voltage Range zu messen. Gruß Carsten
Falk B. schrieb: >
1 | > Sensor ADC-Eingang ADC-Wert Druck1 Druck2 |
2 | > 1V 0,247V 205 0bar -1bar |
3 | > 3V 0,741V 615 5bar 0bar |
4 | > 5V 1,235V 1023 10bar 1bar |
5 | > |
6 | > p = f(adc) = M*ADC+N |
7 | > |
8 | > // 10 Bar Sensor |
9 | > M = dy/dx = (10bar-0bar)/(1023-205)=0,0122 bar/LSB |
10 | > N = P2-M*ADC = 10bar - 0,0122bar/LSB*1023 = -2,506bar |
11 | > |
12 | > // +/-1 Bar Sensor |
13 | > M = dy/dx = (1bar- -1bar)/(1023-205)=0,002445 bar/LSB |
14 | > N = P2-M*ADC = 1bar - 0,002445bar/LSB*1023 = -1,5bar |
15 | > |
16 | > |
> > Man kann das mit Fließkomma rechnen und ist fertig. Man kann aber auch 5 > Minuten nachdenken und Festkommaarithmetik benutzen. Wenn man alles > in Millibar rechnet, braucht es keine Kommas. Dabei darf im > Zwischenergebnis kein Überlauf auftreten, also Rechnung mit 32 Bit. Beim > +/1bar Sensor reichen die Millibar nicht, da muss man eher auf Mikrobar > gehen. Klingt komisch, ist aber so. Kann man aber am Ende wieder auf > Millibar umrechnen. > >
1 | > int p; |
2 | > p = 12,2 * (int32_t)ADC - 2506; // 10 bar Sensor |
3 | > p = (2445 * (int32_t)ADC - 1500000) / 1000; // +/-1 bar Sensor |
4 | >
|
Danke für die konkrete Lösung! Funktioniert gut (nachdem ich deinen Kommafehler ausgebessert habe ;)) Für die 10 Bar Ausführung hätte ich mir jetzt auch die Formel zusammengereimt:
1 | int p; |
2 | p = (10/819) * (adc-205); |
Lineargleichnug dürfte aber die universellere Lösung sein.?
Alexander K. schrieb: > p = (10/819) * (adc-205); Besser so: p = (10* (adc-205)) / 819; Denn was ist (10/819) als Integer? Richtig: 0
Alexander K. schrieb: > Beide geben eine analoge/lineare Spannung > von 1-5 Volt aus. Die wird runter geteilt auf 1,235V und mit einem 10bit > ADC eingelesen. Diesen Satz solltest du noch mal überdenken. Herunterteilen eines Bereichs auf einen festen Wert?? Ich nehme mal an, die wird mit 1,235/5 multipliziert. Sauber formulieren ist oft die halbe Lösung. Ausgangslage bei dem +-1 Sensor: U_adc = U_sensor * 1,235/5 ADC = U_adc * 1024/1,235 U_sensor = 2*Druck + 3 Wir eliminieren U_adc: ADC = (U_sensor * 1,235/5) * 1024/1,235 U_sensor = 2*Druck + 3 Wir eliminieren U_sensor: ADC = (2*Druck + 3) * 1,235/5 * 1024/1,235 Auflösen nach Druck: Druck = (ADC * 5/1024 -3)/2 Kein Problem von Elektronik, kein Problem von Software. Stimmt schon, alles nur Rechnen Klasse 8 oder so.
Falk B. schrieb: > Nullfall? Ich kenn einen Wasserfall und Durchfall, aber keinen Nullfall > ;-) Siehste doch - eben erfunden und was für ein schönes Wort das ist...
Alexander K. schrieb: > int p; > p = (10/819) * (adc-205); > > Lineargleichnug dürfte aber die universellere Lösung sein.? Funktioniert so nicht, weil 10/819=0 ist als Integerrechnung. Siehe Festkommaarithmetik. Bestenfalls so.
1 | p = (((int32_t)adc-205)*10)/819; |
Erst alle Multiplikationen, dann alle Divisionen.
Falk B. schrieb: > p = (((int32_t)adc-205)*10)/819; > > Erst alle Multiplikationen, dann alle Divisionen. Wenn, dann doch wohl besser p = (((int32_t)adc-205)*25)/2048;
:
Bearbeitet durch User
Rainer W. schrieb: >> Erst alle Multiplikationen, dann alle Divisionen. > > Wenn, dann doch wohl besser > > p = (((int32_t)adc-205)*25)/2048; Das ist der nächste Schritt zur Optimierung. Man kann und sollte aber nicht zuviel auf einmal machen, das versteht keiner.
Alexander K. schrieb: > was spricht dagegen mit einem float oder double zu arbeiten? Der 8-Bit Programmierer Ehrencodex ;-) Heutzutage schert sich kaum noch einer um Resourcenbedarf und sinnvoll Lösungen, da darf auch mal ein 32 Bit Controller ne LED blinken. Dagegen ist ne Fließkommaberechnung harmlos. Nimm sie und gut. Es gibt andere, echte Probleme auf dieser Welt.
Falk B. schrieb: > Heutzutage schert sich kaum noch einer um Resourcenbedarf und sinnvoll > Lösungen, da darf auch mal ein 32 Bit Controller ne LED blinken. Wenn Moby das liest, eröffnet er gleich die nächsten 10 Threads.
Alexander K. schrieb: > was spricht dagegen mit einem float oder double zu arbeiten? Solange Dein Arduino genug freien Speicher hat, nichts. Falk B. schrieb: >> was spricht dagegen mit einem float oder double zu arbeiten? > Der 8-Bit Programmierer Ehrencodex ;-) > Heutzutage schert sich kaum noch einer um Resourcenbedarf und sinnvoll > Lösungen, Man sollte sich bemühen, immer sparsam zu agieren. Im Gegensatz zum PC kann man im Mikrocontroller nicht mal eben etwas RAM / ROM nachrüsten.
Falk B. schrieb: > Der 8-Bit Programmierer Ehrencodex ;-) Na, nicht nur, Fließkommazahlen sind verbuggt. Mit Integern ist man da schon eher auf der sicheren Seite. Darüber hinaus kann man öfter auch (positive) Überraschungen erleben wenn man sich Mühe gibt, und kommt auch eher vom Automatismus weg, Fließkommazahlen benutzen zu müssen. Im Zweifelsfall kann man es einfacher machen, und fehlerfreier. Wie gesagt, im Zweifelsfall, aber nicht im Sinne von voreiliger Optimierung. Die ist nämlich zu recht als Wurzel allen Übels verpönt. Erstmal gucken, dass überhaupt was läuft. Also durchaus keine triviale Frage ;) (https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil)
MaWin O. schrieb: > Wenn Moby das liest, eröffnet er gleich die nächsten 10 Threads. Wäre ja gar nicht so schlimm, wenn das nicht ständig der selbe neuaufgegossene kalte Kaffee wäre. Ich fand z.B. diese zugeHolmten Threads gar nicht so übel, auch wenn ich gelegentlich recht dankbar war für das ein oder andere Stoppschild da.
Beitrag #7457222 wurde von einem Moderator gelöscht.
Rbx schrieb: > Ich fand z.B. diese zugeHolmten Threads gar nicht so übel, auch wenn ich > gelegentlich recht dankbar war für das ein oder andere Stoppschild da. ehm... wat?
Beitrag #7457236 wurde von einem Moderator gelöscht.
Stefan F. schrieb: > Rbx schrieb: >> Fließkommazahlen sind verbuggt > > Inwiefern? "verbuggt" ist vielleicht der falsche Begriff. Eine Zahl wie 1,235 lässt sich z.B. nur näherungsweise als Fließkommazahlen darstellen. Deswegen ist beispielsweise von einem Vergleich von Fließkommazahlen auf Gleichheit in den meisten Fällen unbedingt abzuraten.
:
Bearbeitet durch User
Rainer W. schrieb: > "verbuggt" ist vielleicht der falsche Begriff. Ja! Denn sie funktionieren wie spezifiziert. Rainer W. schrieb: > Deswegen ist von einem Vergleich von > Fließkommazahlen auf Gleichheit in den meisten Fällen unbedingt > abzuraten. Ja! Tipp: Sage "immer"! Denn wüsste man vorher, dass sie exakt gleich sind, bräuchte man keinen Vergleich mehr.
:
Bearbeitet durch User
Arduino F. schrieb: > Tipp: Sage "immer"! > Denn wüsste man vorher, ob sie exakt gleich sind, bräuchte man keinen > Vergleich mehr. Nein, sag ich nicht. Und natürlich können die Binärpräsentationen zweier Float Zahlen gleich sein, auch wenn man vorher nicht weiß, dass sie gleich sind. Wenn klar ist, dass die Binärpräsentation der beiden zu vergleichenden Zahlen auf gleiche Weise entsteht, d.h. im Fall der "Gleichheit" beide binär gleich werden müssen, kann der Vergleich kappen ;-)
Rainer W. schrieb: > Deswegen ist beispielsweise von einem Vergleich von > Fließkommazahlen auf Gleichheit in den meisten Fällen > unbedingt abzuraten. Das sind Grundlagen in praktisch jeder Programmiersprache.
Stefan F. schrieb: > Das sind Grundlagen in praktisch jeder Programmiersprache. Welche Programmiersprache verbietet dir, Floats auf Gleichheit zu prüfen?
Rainer W. schrieb: > Welche Programmiersprache verbietet dir, Floats auf Gleichheit zu > prüfen? Welche Programmiersprachen erlaubt dir keine Dummheiten zu begehen?
Rainer W. schrieb: > Welche Programmiersprache verbietet dir, Floats auf Gleichheit zu > prüfen? Warum sollte eine Programmiersprache das verbieten? Float Variablen können den gleichen Wert enthalten.
Stefan F. schrieb: > Warum sollte eine Programmiersprache das verbieten? Float Variablen > können den gleichen Wert enthalten. Naja, sie können schon, aber häufig tun sie es nicht obwohl sie gleich sein müssten - wenn man es mit dem Taschenrechner nachrechnet. Verbieten muss man es nicht, aber vielleicht warnen? [Vielleicht tut das ein Compiler auch, habe schon lange keine Floats mehr verwendet]. Ich möchte nicht wissen, wie viele da schon darüber gestolpert sind ... Wie wäre es mit |Wert1 - Wert2| < epsilon?
Stefan F. schrieb: > Das sind Grundlagen in praktisch jeder Programmiersprache. Das sind die Grundlagen des üblichen binary32 Zahlentyps der IEEE754: - https://de.wikipedia.org/wiki/IEEE_754 Stefan F. schrieb: > Rbx schrieb: >> Fließkommazahlen sind verbuggt > Inwiefern? Wenn man sie noch nicht ganz verstanden hat, dann mutet es einen leicht so an, wenn man einen Vergleich wie z.B.
1 | f=2.0+1.33 |
2 | if (f==3.33) |
3 | tuwas(); |
macht und tuwas() nicht aufgeriufen wird. Mich stört an floats eher, dass sie zwar eine gewaltige Dynamik haben, aber nur 6 signifikante Stellen. Man kann also nicht sicher sein, dass nach dieser Rechnung wie erwartet f = 100.001 ist.
1 | f = 1000.0; |
2 | f+= 0.001; |
Drum nehme ich float nur dort, wo es nötig ist. Und sonst eben einen Integer in "Dezigrad" oder "Centibar" oder "Millimeter", wenn ich wegen einer höheren Auflösung 0,1 Grad oder 0,01 bar oder 0,001 m auflösen will.
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Mich stört an floats eher, dass sie zwar eine gewaltige Dynamik haben, > aber nur 6 signifikante Stellen. Es gibt ja auch noch double (64 Bit) und long double (80 Bit). > Man kann also nicht sicher sein, dass > nach dieser Rechnung iwe erwartet f = 100.001 ist. f = 1000.0; > f+= 0.001; Nix ist perfekt.
Falk B. schrieb: > Es gibt ja auch noch double (64 Bit) und long double (80 Bit). Klar. Aber das macht den 8-Bit-Andruiden nicht schneller oder das Ergebnis besser.
Lothar M. schrieb: > Klar. Aber das macht den 8-Bit-Andruiden nicht schneller oder das > Ergebnis besser. Von einem 8-Bit Andruiden war in der gesamten Diskussion, bis auf meine Anmerkung des 8-Bit Programmierer Ehrenkodex, keine Rede.
Falk B. schrieb: > Von einem 8-Bit Andruiden war in der gesamten Diskussion, bis auf meine > Anmerkung des 8-Bit Programmierer Ehrenkodex, keine Rede. Da hast du durchaus Recht. Allerdings habe ich einfach auf den Eröffnungspost einen Wahrscheilichkeitsalgorithmus angewendet und besonders diese Information linear extrapoliert, wo Alexander K. schrieb: >>>> mit einem 10bit ADC eingelesen.
:
Bearbeitet durch Moderator
Lothar M. schrieb: >> Es gibt ja auch noch double (64 Bit) und long double (80 Bit). > Klar. Aber das macht den 8-Bit-Andruiden nicht schneller Und auch FPU der ARM Coretx-M Controller kann nur 32 Bit float.
Klaus H. schrieb: > Wie wäre es mit |Wert1 - Wert2| < epsilon? Dazu müsstest du vorher immer erst epsilon anhand des absolut größeren Wertes von Wert1 und Wert2 festlegen.
Stefan F. schrieb: > Inwiefern? Könntest du die Frage noch etwas genauer stellen? Auf Stackoverflow gibt es immerhin 10 Reputationpoints für eine gute Antwort auf eine ähnliche, allerdings genauere Frage. https://stackoverflow.com/questions/588004/is-floating-point-math-broken So allgemein kann man nur sagen, dass Zahlen, wie z.B. 3,1415 für sich gesehen erstmal nicht problematisch sind. Die Probleme kommen in der Computeranwendung u.a. durch (statisches) Rundungsverhalten bei (iterierenden) Funktionen oder beim Zahlen konvertieren oder rund um Registerbitbreiten. Beim Heron-Verfahren zum Wurzelziehen, da sind die Fließkommazahlen ganz gut, denn das funktioniert über Annäherungen an die Genauigkeit. Wenn es aber um hergeleitete Genauigkeit geht: - die Fließkommazahlen gaukeln Genauigkeit vor, obwohl sie nur als Annäherung zu verstehen sind und man aufpassen muss. - die Probleme, die sie mitbringen sind mehrdimensional, und man kann nicht alle Problemfälle überblicken - - man muss aber die Schwierigkeiten verstehen z.B. für Testprogramme, die dann wichtiger werden. Gibt man sich keine Mühe, kann es zum Unfall kommen, und das ist sch.. Fuzzy Logic könnte man eventuell auf Fließkommazahlen anwenden. Das ist aber wo implementiert?
:
Bearbeitet durch User
Lothar M. schrieb: > Und sonst eben einen > Integer in "Dezigrad" oder "Centibar" oder "Millimeter", wenn ich wegen > einer höheren Auflösung Z0,1 Grad oder 0,01 bar oder 0,01 m auflösen > will. me too und wenn ich größer oder gleich wissen will nehme ich strcmp will ich Kommata einsetzen durch umrechnen mache ich das im String um aus 500 CentiVolt 5,00V zu machen.
Ich frage mich, wie viele sich die Mühe gemacht und wirklich einmal überprüft haben wie lange einfache FP-Rechenoperationen dauern. Ich hab's vor langer Zeit schon, deshalb benutze ich FP selbst auf 8-Bittern ziemlich oft. WIMRE waren das nämlich so um die 300-500 CPU-Zyklen pro Operation bei den kleinen AVRs. Also 1/2ms bei einer CPU Geschwindigkeit von 1MHz. Oder 1/32ms bei 16MHz. Wenn man eine Berechnung nur ein paar zehn- oder hundertmal pro Sekunde macht, interessiert das fast niemanden.(#) Bei einer simplen Mul/Div Operation um ADC Werte umzurechnen, muss man sich auch keine Gedanken um die Genauigkeit von float/double machen. Oder um Error-Propagation, … Wollt's nur mal erwähnen. ;-) (#) Nitpicker mal ausgeschlossen.
Norbert schrieb: > Wenn man eine Berechnung nur ein paar zehn- oder hundertmal pro Sekunde > macht, interessiert das fast niemanden. Außer, wenn man Strom sparen muss, z. B. bei Batteriebetrieb. Da ist es schon ein Unterschied, ob der µP in den Tiefschlaf gehen kann oder in der Zeit rechnen muss.
Rolf schrieb: > Außer, wenn man Strom sparen muss, Sicherlich richtig. Wenn man im Batteriebetrieb ist. Dann weiß man aber auch um diese Dinge. Nebenbei: Auch die FixPoint Arithmetik braucht ein Tütchen CPU-Zyklen. Vor allem wenn man versucht eine halbwegs akzeptable Genauigkeit heraus zu holen und mit 16, evtl. sogar 32 Bit rechnet.
Rolf schrieb: > Außer, wenn man Strom sparen muss Oder wenn man z.B. solche Operationen auf ein größeres Array wiederholt anwenden muss. Norbert schrieb: > WIMRE waren das nämlich so um die 300-500 CPU-Zyklen pro Operation bei > den kleinen AVRs. > Also 1/2ms Eine einzige Rechenoperation macht kein Programm. Der Witz ist, dass jede einzelne derartige float-Rechnung eben 50 mal langsamer ist als die integer-Rechnung, die das selbe Ergebnis bringt. Und dann nennt der Programmierer den Controller "zu langsam", statt sein Programm "ungeeignet geschrieben". Wenn man ein klein wenig Gehirnschmalz in sein Programm steckt, dann muss man oft überhaupt gar nicht umrechnen. Oder erst dann, wenn irgendwer irgendwelche Werte auf einer Anzeige sehen will.
Lothar M. schrieb: > Der Witz ist, dass > jede einzelne derartige float-Rechnung eben 50 mal langsamer ist als > die integer-Rechnung Nö Lothar, das ist kein Witz, das ist einfach so. Allerdings muss ich zugeben, das die CPUs nun nicht mehr zu 90% herum-idlen, sondern nur noch zu 89%. Das ist zugegebenermaßen nur schwer zu ertragen, aber man muss auch mal bereit sein ein Opfer zu bringen. PS. Wenn ich auf anderen Systemen 500ksps per DMA vom ADC bekomme, diese verarbeiten und weiterschieben muss, dann nehme ich auch FixPoint. Dann, nur dann.
:
Bearbeitet durch User
Lothar M. schrieb: > Eine einzige Rechenoperation macht kein Programm. Der Witz ist, dass > jede einzelne derartige float-Rechnung eben 50 mal langsamer ist als > die integer-Rechnung, die das selbe Ergebnis bringt. Das halte ich für einen Irrtum. Miss mal nach, wenn mit 16 oder eher 32 Bit grerechnet wird! Ich würde vermuten, daß Float weniger als Faktor 5 langsamer ist.
Norbert schrieb: > Ich frage mich, wie viele sich die Mühe gemacht und wirklich einmal > überprüft haben wie lange einfache FP-Rechenoperationen dauern. meist geht es nicht um die Dauer sondern das einem der RAM ausgeht weil alles auf dem Stack passiert, das kann schöne versteckte Fehler ergeben.
Joachim B. schrieb: > meist geht es nicht um die Dauer sondern das einem der RAM ausgeht weil > alles auf dem Stack passiert, das kann schöne versteckte Fehler ergeben. Und morgen geht die Welt unter! Nein! Der Norbert hat schon recht!
Joachim B. schrieb: > meist geht es nicht um die Dauer sondern das einem der RAM ausgeht weil > alles auf dem Stack passiert, das kann schöne versteckte Fehler ergeben. Das tritt aber auch mit anderen Funktionalitäten auf und hat nichts direkt mit Floatingpoint zu tun. Ich empfehle bei Embedded Systemen immer Stacküberwachung einzubauen. Die Diskussion scheint Richtung Glaubenskrieg zu gehen. Ich nutze das was am besten passt. Und auch auf kleinen 8Bittern funktioniert float gut. Und manchmal braucht man auch Integer/Fixpoint Operationen auf 32Bittern.
:
Bearbeitet durch User
Falk B. schrieb: > Und morgen geht die Welt unter! Nein! Der Norbert hat schon recht! Nein, man redet hier ein Problem herbei, was man in einfachen Anwendungen kaum hat. Mit dem Rechnen ist das auch so eine Sache: 16 MHz sind 0,0625µs. Mal 500 komme ich auf 32 MIKROsekunden, nicht ms! Mein 8MHz-Arduino liest vom angeschlossenen ADS1115 alle 10 Sekunden zwei Spannungen und schreibt diese auf eine SD-Karte. Ich habe mich um Variablentypen nicht geschert, da fliegen 4 Nachkommastellen herum. Das läuft mit einer 18650-LiIon an die 500 Stunden, mit aktivem OLED natürlich weniger. Mein Spannungslogger kann auch jede Sekunde zur Karte schreiben, da bin ich weder in Zeitnot noch stürzt irgendwas ab. Zeitnot habe ich mal an anderer Stelle gefangen, wo die A/D des ATMega benutzt werden und damit eine Regelung im Millisekunden-Bereich läuft. Das war nicht die Float-Rechnerei, sondern zweistellige Millisekunden für mein I2C-LCD. Ich hätte gerne ein Problem passt hier wohl besser.
Klaus H. schrieb: > Die Diskussion scheint Richtung Glaubenskrieg zu gehen. Treffer, versenkt - (+1) !
Joachim B. schrieb: > jeder hat recht Ich wünsche dir, dass du als Sieger aus dieser Konfrontation hervorgehst. Selbst wenn es der zweite Sieger ist.
Ich hab mal gemessen. Einmal im Simulator im staubigen AVR-Studio mit dem ollen 2010er avr gcc (der noch einen "Bug" hat und sich in einigen Situationen viel RAM gönnt, so auch hier) und einmal mit Arduino UNO. Im AVR-Studio mit Optimierung -Os (minimale Codegröße) compiliert. Beim Arduino wurde die Zeit per Oszi gemessen. In beiden Fällen mit 16 MHz CPU-Takt.
1 | WinAVR-20100110 |
2 | FLASH /B RAM /B Zeit /us |
3 | float 2860 264 197,0 |
4 | int32 186 0 4,1 |
5 | |
6 | Arduino 1.8.13 |
7 | FLASH /B RAM /B Zeit /us |
8 | float 1666 9 23,0 |
9 | int32 920 9 4,2 |
Ziemliche Unterschiede! Aber bei ein paar handvoll oder auch hundert Berechnungen/s kein wirkliches Problem. Bei größeren Arduinos mit 32 Bit geht es noch schneller, wenn ne FPU vorhanden ist bedeutungslos.
Falk B. schrieb: > Ziemliche Unterschiede! Aber bei ein paar handvoll oder auch hundert > Berechnungen/s kein wirkliches Problem. Ähnliches hab ich hier mal gemessen: Beitrag "Re: Linearisierung eines Ausgangssignal mit Mikrocontroller" Fazit: Float ist einsetzbar
:
Bearbeitet durch User
Eine Sache die hier nicht berücksichtigt wird: Bei Integer-Operationen kann es unüberlegt schnell zu Überläufen kommen. So geschehen bei der Kalibration eines Sensors über eine Polynom-Funktion. Trotz Optimierungen konnte der Überlauf nur sehr aufwändig abgefangen werden, da sich die Faktoren in den Einzelgeräten stark unterschieden. Mit float hatte sich das Problem erledigt.
Hallo, wenn man über “ Differential ADC Channel“ messen würde und dir Referenzspannung und Eingang mit einem Trimmer auf 4 V und 1V regeln würde, würden 1V =0bar =0 und 10bar =4V =1023 bzw. 1000 ergeben können (je nach Trimmung). Dadurch würden 1/5 der Werte nicht „verschenkt“ werden also 0-1V. Gruß Carsten
Carsten-Peter C. schrieb: > wenn man über “ Differential ADC Channel“ messen würde und Du hast mitbekommen, dass Alexander K. ausgestiegen ist und hofft, nach den Schulferien endlich Grundrechnen zu lernen? Differential ist nett gedacht, aber er hat es ja nicht nötig, seinen ADC zu benennen. 10-Bit lässt einen AVR vermuten, der das vermutlich nicht kann. Es fehlen auch Details zu den Drucksensoren. Dass die als Endwert 5 Volt liefern, lässt vermuten, dass es deren Betriebsspannung sein könnte. Da wäre eine ratiometrische Messung sinnvoll - also µC-Referenz und Sensoren an der selben Versorgung.
Manfred P. schrieb: > lässt vermuten Könnte auch ein 4-20 mA Sensor an einer 250 Ohm Bürde sein... ;-)
Klaus H. schrieb: > Bei Integer-Operationen kann es unüberlegt schnell zu Überläufen kommen. Richtig, "unüberlegt" und "Integer-Operation" passt nicht wirklich zusammen, sobald Multiplikationen ins Spiel kommen.
:
Bearbeitet durch User
Rainer W. schrieb: > "unüberlegt" und "Integer-Operation" passt nicht wirklich zusammen Generell finde ich, dass "unüberlegt" und "programmieren" nicht zusammenpassen. Denn ich kann z.B.
1 | int i = 1000000000; |
2 | i += 1; |
schreiben und bekomme 1000000001 heraus. Wenn ich aber
1 | float f = 1000000000.0; |
2 | f += 1.0; |
schreibe, dann ist f nach dem ersten Befehl annähernd 1000000000. Und nsch der Addition kommt unverändert annähernd 1000000000 heraus.
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Generell finde ich, dass "unüberlegt" und "programmieren" nicht > zusammenpassen. Mit immer leistungsfähigeren Prozessoren und immer unübersichtlicheren Abstraktionsebenen/Bibliotheken fällt das leider immer häufiger zusammen. Die Beziehung zu dem, was der µC wirklich tut, gerät oft weit ins Hintertreffen.
Lothar M. schrieb: > Generell finde ich, dass… Generell finde ich, dass man immer wissen sollte was man macht.
1 | #include <stdio.h> |
2 | |
3 | // gcc -Wall -Wextra -pedantic -std=c11 -Os -o "x" "x.c"
|
4 | |
5 | int main(void) { |
6 | float xf = 0.0, yf = 1.0; |
7 | double xd = 0.0, yd = 1.0; |
8 | |
9 | for(int i= 0; i < 25; i++) { |
10 | xf += yf; |
11 | printf("%3d %.25f\n", i, xf); |
12 | yf /= 2.0; |
13 | }
|
14 | for(int i= 0; i < 54; i++) { |
15 | xd += yd; |
16 | printf("%3d %.54f\n", i, xd); |
17 | yd /= 2.0; |
18 | }
|
19 | return 0; |
20 | }
|
1 | ~/tmp$ "./x" |
2 | 0 1.0000000000000000000000000 |
3 | 1 1.5000000000000000000000000 |
4 | 2 1.7500000000000000000000000 |
5 | 3 1.8750000000000000000000000 |
6 | 4 1.9375000000000000000000000 |
7 | 5 1.9687500000000000000000000 |
8 | 6 1.9843750000000000000000000 |
9 | 7 1.9921875000000000000000000 |
10 | 8 1.9960937500000000000000000 |
11 | 9 1.9980468750000000000000000 |
12 | 10 1.9990234375000000000000000 |
13 | 11 1.9995117187500000000000000 |
14 | 12 1.9997558593750000000000000 |
15 | 13 1.9998779296875000000000000 |
16 | 14 1.9999389648437500000000000 |
17 | 15 1.9999694824218750000000000 |
18 | 16 1.9999847412109375000000000 |
19 | 17 1.9999923706054687500000000 |
20 | 18 1.9999961853027343750000000 |
21 | 19 1.9999980926513671875000000 |
22 | 20 1.9999990463256835937500000 |
23 | 21 1.9999995231628417968750000 |
24 | 22 1.9999997615814208984375000 |
25 | 23 1.9999998807907104492187500 |
26 | 24 2.0000000000000000000000000 |
27 | 0 1.000000000000000000000000000000000000000000000000000000 |
28 | 1 1.500000000000000000000000000000000000000000000000000000 |
29 | 2 1.750000000000000000000000000000000000000000000000000000 |
30 | 3 1.875000000000000000000000000000000000000000000000000000 |
31 | 4 1.937500000000000000000000000000000000000000000000000000 |
32 | 5 1.968750000000000000000000000000000000000000000000000000 |
33 | 6 1.984375000000000000000000000000000000000000000000000000 |
34 | 7 1.992187500000000000000000000000000000000000000000000000 |
35 | 8 1.996093750000000000000000000000000000000000000000000000 |
36 | 9 1.998046875000000000000000000000000000000000000000000000 |
37 | 10 1.999023437500000000000000000000000000000000000000000000 |
38 | 11 1.999511718750000000000000000000000000000000000000000000 |
39 | 12 1.999755859375000000000000000000000000000000000000000000 |
40 | 13 1.999877929687500000000000000000000000000000000000000000 |
41 | 14 1.999938964843750000000000000000000000000000000000000000 |
42 | 15 1.999969482421875000000000000000000000000000000000000000 |
43 | 16 1.999984741210937500000000000000000000000000000000000000 |
44 | 17 1.999992370605468750000000000000000000000000000000000000 |
45 | 18 1.999996185302734375000000000000000000000000000000000000 |
46 | 19 1.999998092651367187500000000000000000000000000000000000 |
47 | 20 1.999999046325683593750000000000000000000000000000000000 |
48 | 21 1.999999523162841796875000000000000000000000000000000000 |
49 | 22 1.999999761581420898437500000000000000000000000000000000 |
50 | 23 1.999999880790710449218750000000000000000000000000000000 |
51 | 24 1.999999940395355224609375000000000000000000000000000000 |
52 | 25 1.999999970197677612304687500000000000000000000000000000 |
53 | 26 1.999999985098838806152343750000000000000000000000000000 |
54 | 27 1.999999992549419403076171875000000000000000000000000000 |
55 | 28 1.999999996274709701538085937500000000000000000000000000 |
56 | 29 1.999999998137354850769042968750000000000000000000000000 |
57 | 30 1.999999999068677425384521484375000000000000000000000000 |
58 | 31 1.999999999534338712692260742187500000000000000000000000 |
59 | 32 1.999999999767169356346130371093750000000000000000000000 |
60 | 33 1.999999999883584678173065185546875000000000000000000000 |
61 | 34 1.999999999941792339086532592773437500000000000000000000 |
62 | 35 1.999999999970896169543266296386718750000000000000000000 |
63 | 36 1.999999999985448084771633148193359375000000000000000000 |
64 | 37 1.999999999992724042385816574096679687500000000000000000 |
65 | 38 1.999999999996362021192908287048339843750000000000000000 |
66 | 39 1.999999999998181010596454143524169921875000000000000000 |
67 | 40 1.999999999999090505298227071762084960937500000000000000 |
68 | 41 1.999999999999545252649113535881042480468750000000000000 |
69 | 42 1.999999999999772626324556767940521240234375000000000000 |
70 | 43 1.999999999999886313162278383970260620117187500000000000 |
71 | 44 1.999999999999943156581139191985130310058593750000000000 |
72 | 45 1.999999999999971578290569595992565155029296875000000000 |
73 | 46 1.999999999999985789145284797996282577514648437500000000 |
74 | 47 1.999999999999992894572642398998141288757324218750000000 |
75 | 48 1.999999999999996447286321199499070644378662109375000000 |
76 | 49 1.999999999999998223643160599749535322189331054687500000 |
77 | 50 1.999999999999999111821580299874767661094665527343750000 |
78 | 51 1.999999999999999555910790149937383830547332763671875000 |
79 | 52 1.999999999999999777955395074968691915273666381835937500 |
80 | 53 2.000000000000000000000000000000000000000000000000000000 |
81 | ~/tmp$ |
Lothar M. schrieb: > Generell finde ich, dass "unüberlegt" und "programmieren" nicht > zusammenpassen. Keine Sorge, dass übernimmt ja jetzt die KI... 😂
Rainer W. schrieb: >> Generell finde ich, dass "unüberlegt" und "programmieren" nicht >> zusammenpassen. > > Mit immer leistungsfähigeren Prozessoren und immer unübersichtlicheren > Abstraktionsebenen/Bibliotheken fällt das leider immer häufiger > zusammen. > Die Beziehung zu dem, was der µC wirklich tut, gerät oft weit ins > Hintertreffen. Bist du des Mobys! ;-) Stimmt aber leider. Sieht man auch fast jeden Tag, was da an Softwareungetümen zusammengebacken wird, die immmer größer und träger werden! Bloatware at it's best!
Ich empfehle https://www.karlin.mff.cuni.cz/~hron/NMMO403/What_every_computer_scientist_should_know_about_floating-point_arithmetic-Goldberg-1991.pdf ein reprint des goldberg-papers. Oder bei TAOCP nachlesen.
Danke für den Artikel Wilhelm ! Den hatte ich vor Jahren nur in einer schlechten Papierkopie.
Falk B. schrieb: > Ich hab mal gemessen. Einmal im Simulator im staubigen AVR-Studio mit > dem ollen 2010er avr gcc (der noch einen "Bug" hat und sich in einigen > Situationen viel RAM gönnt, so auch hier) und einmal mit Arduino UNO. Der Ramverbrauch its das eine, aber daß der (leicht staubige) arduino-gcc (7.3.0) bei float einen fast um den Faktor 10 schnelleren Code produzieren soll als der staubige 2010er (vermutlich ein 4.5), ist dann doch nicht nachvollziehbar. Oliver
Norbert schrieb: > yf /= 2.0; Irgendwie eine sehr vorteilhafte Wahl, wenn der Rechner sowieso im Binärsystem arbeitet und die Schleife genau rechtzeitig abgebrochen eird. Mit ein paar Iterationen mehr oder einer unbinären Zahl sieht man das dann besser, dass dich der xf Wert nicht mehr ändert, obwohl yf nicht 0 ist.
1 | #include <stdio.h> |
2 | int main(void) { |
3 | float xf, yf; |
4 | |
5 | xf = 0.0, yf = 1.0; |
6 | for(int i= 0; i < 30; i++) { |
7 | xf += yf; |
8 | printf("%3d %.25f %.025f\n", i, xf, yf); |
9 | yf /= 2.0; |
10 | }
|
11 | |
12 | xf = 0.0, yf = 1.0; |
13 | for(int i= 0; i < 30; i++) { |
14 | xf += yf; |
15 | printf("%3d %.25f %.025f\n", i, xf, yf); |
16 | yf /= 3.33; |
17 | }
|
18 | |
19 | return 0; |
20 | }
|
Da sieht man dann, dass sich ab der der sechsten Nachkommastelle nichts mehr tut:
1 | 0 1.0000000000000000000000000 1.0000000000000000000000000 |
2 | 1 1.5000000000000000000000000 0.5000000000000000000000000 |
3 | 2 1.7500000000000000000000000 0.2500000000000000000000000 |
4 | 3 1.8750000000000000000000000 0.1250000000000000000000000 |
5 | 4 1.9375000000000000000000000 0.0625000000000000000000000 |
6 | 5 1.9687500000000000000000000 0.0312500000000000000000000 |
7 | 6 1.9843750000000000000000000 0.0156250000000000000000000 |
8 | 7 1.9921875000000000000000000 0.0078125000000000000000000 |
9 | 8 1.9960937500000000000000000 0.0039062500000000000000000 |
10 | 9 1.9980468750000000000000000 0.0019531250000000000000000 |
11 | 10 1.9990234375000000000000000 0.0009765625000000000000000 |
12 | 11 1.9995117187500000000000000 0.0004882812500000000000000 |
13 | 12 1.9997558593750000000000000 0.0002441406250000000000000 |
14 | 13 1.9998779296875000000000000 0.0001220703125000000000000 |
15 | 14 1.9999389648437500000000000 0.0000610351562500000000000 |
16 | 15 1.9999694824218750000000000 0.0000305175781250000000000 |
17 | 16 1.9999847412109375000000000 0.0000152587890625000000000 |
18 | 17 1.9999923706054687500000000 0.0000076293945312500000000 |
19 | 18 1.9999961853027343750000000 0.0000038146972656250000000 |
20 | 19 1.9999980926513671875000000 0.0000019073486328125000000 |
21 | 20 1.9999990463256835937500000 0.0000009536743164062500000 |
22 | 21 1.9999995231628417968750000 0.0000004768371582031250000 |
23 | 22 1.9999997615814208984375000 0.0000002384185791015625000 |
24 | 23 1.9999998807907104492187500 0.0000001192092895507812500 |
25 | 24 2.0000000000000000000000000 0.0000000596046447753906250 |
26 | 25 2.0000000000000000000000000 0.0000000298023223876953125 |
27 | 26 2.0000000000000000000000000 0.0000000149011611938476562 |
28 | 27 2.0000000000000000000000000 0.0000000074505805969238281 |
29 | 28 2.0000000000000000000000000 0.0000000037252902984619141 |
30 | 29 2.0000000000000000000000000 0.0000000018626451492309570 |
31 | 0 1.0000000000000000000000000 1.0000000000000000000000000 |
32 | 1 1.3003003597259521484375000 0.3003003001213073730468750 |
33 | 2 1.3904806375503540039062500 0.0901802703738212585449219 |
34 | 3 1.4175617694854736328125000 0.0270811617374420166015625 |
35 | 4 1.4256942272186279296875000 0.0081324810162186622619629 |
36 | 5 1.4281364679336547851562500 0.0024421864654868841171265 |
37 | 6 1.4288698434829711914062500 0.0007333893445320427417755 |
38 | 7 1.4290900230407714843750000 0.0002202370378654450178146 |
39 | 8 1.4291561841964721679687500 0.0000661372469039633870125 |
40 | 9 1.4291760921478271484375000 0.0000198610359802842140198 |
41 | 10 1.4291820526123046875000000 0.0000059642752603394910693 |
42 | 11 1.4291838407516479492187500 0.0000017910736005433136597 |
43 | 12 1.4291844367980957031250000 0.0000005378599325922550634 |
44 | 13 1.4291845560073852539062500 0.0000001615194946680276189 |
45 | 14 1.4291845560073852539062500 0.0000000485043543108076847 |
46 | 15 1.4291845560073852539062500 0.0000000145658720640540196 |
47 | 16 1.4291845560073852539062500 0.0000000043741357202975450 |
48 | 17 1.4291845560073852539062500 0.0000000013135542653586185 |
49 | 18 1.4291845560073852539062500 0.0000000003944607418482349 |
50 | 19 1.4291845560073852539062500 0.0000000001184566750245253 |
51 | 20 1.4291845560073852539062500 0.0000000000355725761347347 |
52 | 21 1.4291845560073852539062500 0.0000000000106824549206408 |
53 | 22 1.4291845560073852539062500 0.0000000000032079443268440 |
54 | 23 1.4291845560073852539062500 0.0000000000009633466984196 |
55 | 24 1.4291845560073852539062500 0.0000000000002892933017706 |
56 | 25 1.4291845560073852539062500 0.0000000000000868748635855 |
57 | 26 1.4291845560073852539062500 0.0000000000000260885470128 |
58 | 27 1.4291845560073852539062500 0.0000000000000078343983116 |
59 | 28 1.4291845560073852539062500 0.0000000000000023526721275 |
60 | 29 1.4291845560073852539062500 0.0000000000000007065081696 |
Oliver S. schrieb: > ist dann doch nicht nachvollziehbar. Wundert mich schon auch ein wenig. 10 Jahre Compilerentwicklung ergeben 10 fach schnelleren Code. Wenn man das mal extrapoliert...
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Irgendwie eine sehr vorteilhafte Wahl, wenn der Rechner sowieso im > Binärsystem arbeitet Das war ja der Plan. Man kann - so wie du - zeigen, das man sich Probleme einfangen kann wenn man im Dezimalsystem über die Genauigkeit einer float Variablen hinaus noch weiter arbeiten will. Oder das man eine erstaunliche Genauigkeit erreicht, wenn man die Mantisse im dualen System massiert. Beides ist richtig, beides muss man wissen. PS. Die Schleifen wurden nicht rechtzeitig abgebrochen, sondern erst nachdem der erste Rechenfehler auftrat. So ehrlich bin ich dann doch… ;-)
:
Bearbeitet durch User
Rainer W. schrieb: > Richtig, "unüberlegt" und "Integer-Operation" passt nicht wirklich > zusammen, sobald Multiplikationen ins Spiel kommen. Da muss(te) wohl jeder mal durch, während der Rechenoperation einen Überlauf, obwohl Eingabe und Ausgabe im zulässigen Bereich liegen.
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.