Hallo,
Ich habe mir letzten den Artikel zur Festkommaberechnung durchgelesen.
Und würde jetzt gerne mein gesamtes Projekt von float umschreiben auf
Integers. Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen
weil er keine FPU besitzt.
Da stellt sich mir aber eine Frage, und zwar habe ich eine Formel womit
ich den Kohlenstoffdioxid Gehalt aus der Karbonathärte und dem PH Wert
rausrechnen kann.
Die Formel sieht so aus:
Co2 = KH / 2.8 * 10^(7.9-PH)
Am Ende kommt halt eine Komma zahl raus. Den KH Wert in einem uint8_t
Integer fest zu halt ist kein Problem. Dort kann ich einfach statt 4,5
auch 450 schreiben und erhöhe die 2.8 auf 280. Das Problem scheint eher
die Zehnerpotenz zu sein ich habe mir dafür folgende Änderung überlegt
um das in meinem Mikrocontroller ausrechnen zu können:
Den PH Wert bekomme ich im Moment noch als Gleitkomma also z.b 6.80.
Diesen werde ich später in ein 16 Bit Unsigned Integer umwandeln und 680
für 6.80 schreiben.
Ich muss aber den PH Wert in der Exponenten wieder als Gleitkomma
schreiben also geteilt durch 100 rechnen weil sonst dort nicht das
richtige rauskommt.
Am Ende würde ich dann nochmal mit 1000 multiplizieren um das Ergebnis
wieder in ein 16 Bit Unsigned Integer zu wandeln. Also 20,98 in 2098.
Nur stellt diese Art von Berechnung für den Prozessor ein Problem da
bzgl. länger Rechnenzeit? Oder sieht er dieses als normale Division an?
Lg
In welchem Wertebereich bewegen sich die Eingaben dieser Formel, d.h.
die Werte für KH und PH? Und mit welcher realen Auflösung werden die
ermittelt/vorgegeben/wasauchimmer?
Rufus Τ. F. schrieb:> In welchem Wertebereich bewegen sich die Eingaben dieser Formel, d.h.> die Werte für KH und PH? Und mit welcher realen Auflösung werden die> ermittelt/vorgegeben/wasauchimmer?
HI,
Also der KH Wert befindet sich zwischen 0,5 und 25(50 bis 250). Und der
PH Wert zwischen 6.00 und 9.00(600 bis 900). Der daraus resultierende
Co2 Wert ist stark von den beiden Wert abhängig und liegt zwischen 0,00
und 300,00(0 bis 300.000), es wird beim Co2 ein Überlauf dann geben
daher werde ich wahrscheinlich den Integer für den Co2 Wert vergrößern,
realistisch ist dort ein Wert von maximal 40(40000).
Der KH Wert muss manuell gemessen werden und ins Messgerät nach einem
Teilwasserwechsel eingeben werden in meinem Fall wird dieser Wert
zwischen 4 und 7 liegen. Der pH Wert wird von einer pH Elektrode
ermittelt und bewegt sich je nach der Co2 Zugabe zwischen 6.70 und 7.70.
Der Co2 Gehalt liegt dabei zwischen 3mg/l@ph7.70 und 30mg/l@ph6.70
Lg
Felix N. schrieb:> Die Formel sieht so aus:>> Co2 = KH / 2.8 * 10^(7.9-PH)>> Am Ende kommt halt eine Komma zahl raus.
Hallo, man kann mit Festkommaarithmetik eine ganze Menge machen! Du mußt
halt genau abschätzen, mit welchen Werten in welchem Wertebereich zu
rechnen (im doppelten Wortsinn) ist. Früher war das auf Mikrocontrollern
die Regel. Und es gibt hilfreiche Tabellen, die reelle Zahlen oder etwa
PI in ganzzahligen Brüchen mit dem Fehler angeben. (Simpelste Näherung
für z.B. PI ist 22/7). Heutzutage kann man sich so eine Tabelle ja
selbst erzeugen...z.B. mit einer Tabellenkalkulation...Du hast also
Arbeit im Vorfeld und später kannst du ja sehen, ob sich eine
signifikante Ersparniss der Rechenzeit auf dem Controller ergibt! Falls
du aber einen 8-Bit-Controller hast, dann würde ich mir bei großen
Festkommazahlen nicht wirklich eine kürzere Rechenzeit erwarten.
64-Bit-Ganzzahl will auch auf dem Controller erst mal gehandelt
werden...denke ich...
Viel Spass und Erfolg.
Gruß Rainer
Ok, das ist der Wertebereich. Und welche Auflösung haben die Werte?
Werden für "KH" auch 0.51, 0.63 o.ä. unterschieden?
Und wie sieht das beim pH-Wert aus? Mit welcher Auflösung misst Dein
Gerät?
Rufus Τ. F. schrieb:> Werden für "KH" auch 0.51, 0.63 o.ä. unterschieden?
KH gibt es nur in 0,5 Schritten also 0,5, 1, 1,5, 2,0 usw...
Rufus Τ. F. schrieb:> Mit welcher Auflösung misst Dein> Gerät?
Der pH Wert wird mit einer Auflösung von 0.01 dargestellt. Also 6.91,
6.92, 6.93, 6.94, usw...
Rainer V. schrieb:> 8-Bit-Controller
ATMega644P @ 16MHz 5V
Lg
Felix N. schrieb:> Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen> weil er keine FPU besitzt.Felix N. schrieb:> Kohlenstoffdioxid Gehalt aus der Karbonathärte und dem PH Wert> rausrechnen kann.
Äh, wieviele Messwerte berechnest Du so pro Sekunde?
Ich frage das, weil man PH normalerweise relativ langsam misst
(1/Sekunde) und da hätte man mehr als genug Zeit für ein paar Float
Berechnungen. Auch auf einem eher lahmen 8-Bitter.
Felix N. schrieb:> Den PH Wert bekomme ich im Moment noch als Gleitkomma also z.b 6.80.> Diesen werde ich später in ein 16 Bit Unsigned Integer umwandeln und 680> für 6.80 schreiben.>> Ich muss aber den PH Wert in der Exponenten wieder als Gleitkomma> schreiben also geteilt durch 100 rechnen weil sonst dort nicht das> richtige rauskommt.
Hallo, du hast das Programm mit Gleitkomma also schon fertig?! Dann
versuche doch mal Schritt für Schritt die einzelnen Rechenoperationen in
Festkomma "dazwisch zu schieben" dann kannst du gleich auch Abschätzen,
wo es kritisch wird.
Gruß Rainer
Sowas lohnt sich nur dann, wenn die Rechnung wirklich merklich Zeit
frisst. Das ist meistens nur dann der Fall, wenn sie oft durchgeführt
wird. Ein Typischer solcher Fall ist die Verarbeitung von ADC-Daten.
Bei einer Rechnung, die einmal pro Sekunde gemacht wird, lohnt sich der
Aufwand so gut wie nie.
Man kann sich das - wenn du keinen Debugger hast der das kann - mit dem
Oszilloskop herausmessen:
Setze vor der Rechnung einen Port, setze ihn danach zurück. Am
Oszilloskop kannst du sehen, ob der Port >1% der Zeit an ist.
Ist das nicht so, kannst du dir gerne überlegen, ob eine lange
Entwicklungszeit für eine Einsparung von <1% gerechtfertigt ist oder
nicht.
Ich habe schon auf PIC24 in C einfach in float gerechnet. Meist für die
Anzeige auf dem Display. Wenn man das einmal pro Sekunde tut, und es
dauert dann 2ms? Total Banane ;-)
Ich habe auf die harte Tour gelernt:
Optimieren tut man erst, wenn es nötig ist.
Optimieren tut man nur da, wo es messbar (!!!) etwas bringt, und nicht
da, wo man glaubt es bringe etwas. Man optimiert NACH der Messung.
Natürlich gilt immer:
Beim Code-schreiben mitdenken ist Gold wert. Im User Interface ist float
oft ok, in der 400µs-ISR sicher nicht.
Felix N. schrieb:> Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen> weil er keine FPU besitzt.
Was ist für Dich "viel Zeit" bzw. wieviel Tausend mal muß diese Rechnung
je Sekunde erfolgen?
Der Mensch kann kaum mehr als 5 Werte je Sekunde erfassen, eine
schnellere Ausgabe hat daher keinen Sinn.
Felix N. schrieb:> Und würde jetzt gerne mein gesamtes Projekt von float umschreiben auf> Integers.
Wenn es mit float läuft und der Bediener nicht sekundenlang auf das
Ergebnis warten muß, gibt es keinen Grund dafür.
Die float-Libs sind bei den meisten Compilern recht ausgereift. Mit
Integer kann man da kaum noch was optimieren, dafür aber leicht
Rundungsfehler oder Überläufe reinkriegen.
Felix N. schrieb:> Der pH Wert wird mit einer Auflösung von 0.01 dargestellt. Also 6.91,> 6.92, 6.93, 6.94, usw...
Dargestellt. Wird er auch mit dieser Auflösung tatsächlich ermittelt?
Ich glaube nicht, daß für die Berechnung Deiner CO2-Werte tatsächlich
diese Auflösung relevant ist, vor allem, wenn der "hinten rausfallende"
Wert mit einem uint8_t darstellbar ist.
Du könntest Dir mal eine Excel-Tabelle o.ä. basteln, in der Du für
verschiedene Wertekombinationen von pH-Wert und "KH" ausrechnest,
welcher tatsächliche Wert resultiert.
Ich habe den Verdacht, daß sich das ganze auf eine recht simple Tabelle
reduzieren lassen dürfte.
Felix N. schrieb:> ATMega644P @ 16MHz 5V
Hallo, du hast also einen 8-Bitter...und programmierst natürlich nicht
in Assembler. Also sollte es doch einfach sein, den von mir
vorgeschlagenen Weg zu gehen. Du weißt aber, dass das Typenhandling
nicht ohne sein kann?! Die Foren sind voll von Fragen wie..."mein int
ist kein int :-)"
Viel Erfolg, Rainer
Rufus Τ. F. schrieb:> Ich habe den Verdacht, daß sich das ganze auf eine recht simple Tabelle> reduzieren lassen dürfte.
...und wenn sich das alles mit einer Tabelle erschlagen lassen würde,
dann bist du komplett aus dem Schneider...8-Bitter...
Gruß Rainer
Felix N. schrieb:> Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen> weil er keine FPU besitzt.
gemessen oder geschätzt? Ohne Messung (mit einem SysTicker bzw.
µs-Ticker) macht eine Umstellung wenig Sinn.
Und, ... wieviel schneller muss es werden? Also ist Schnelligkeit
überhaupt eine wirkliche Anforderung oder wäre es nur schöner?
Felix N. schrieb:> Co2 = KH / 2.8 * 10^(7.9-PH)
Das kann man ggf. auch zusammenfassen, z.B. zu
Co2=KH * (10^7.9 / 2.8) / 10^PH.
Dann enfällt die Subtraktion und der Rest ist konstant. Der Compiler
wird 7.9-PH sicher kaum auseinanderdröseln.
Wenn er z.B. 10ms rechnet, ... stört das?
Achim S. schrieb:>> Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen>> weil er keine FPU besitzt.>> gemessen oder geschätzt? Ohne Messung (mit einem SysTicker bzw.> µs-Ticker) macht eine Umstellung wenig Sinn.
Guter Einwand! Nur weil ein Proz. keine FPU hat, muß er nicht
"langsamer" sein!
Gruß Rainer
Felix N. schrieb:> Ich habe mir letzten den Artikel zur Festkommaberechnung durchgelesen.> Und würde jetzt gerne mein gesamtes Projekt von float umschreiben auf> Integers.
Lass den Quatsch!
> Da der Prozessor wohl sehr viel Zeit braucht die zu Berechnen> weil er keine FPU besitzt.
Ich kenne keinen aktuellen µC der viel oder sogar sehr viel Zeit
bräuchte.
Achim S. schrieb:> Wenn er z.B. 10ms rechnet, ... stört das?
Du redest von einem 4-Bitter?
Deine Überlegungen zum Rechnen mit Integer Zahlen finde ich korrekt.
Kann man machen, aber da die Zahlen groß werden und Divisionen ohnehin
"teuer" sind, könnte der Schuss nach Hinten losgehen.
Ich würde beide Varianten ausprobieren, wenn es wichtig ist, Zeit zu
sparen. Wenn Zeit egal und float genau genug ist, würde ich das nehmen.
Meistens ist es besser, Code einfach und gut lesbar zu gestalten, als
auf Performance zu optimieren. Oft ist es sogar besser, notfalls auf
einen schnelleren µC zu wechseln, als Zeit mit Code-Optimierung zu
vergeuden.
Ja, interessante Aufgabe.
Die Formel lautet CO2=(KH/2.8)*10^(7.9-ph)
Ich ziehe eine geeignete Konstante raus, eine rationale Zahl mit einer
Potenz von 2 im Nenner, die ich komfortabel in einer integer
Multiplikation und einem Shift verarbeiten kann. KH spielt auch keine
Rolle, das wird bei der Multiplikation verwurstet, das läuft von 1/2 bis
50/2 in 1/2 Schritten.
Dann muss ich noch 10^c1 rechnen, c1 läuft von 0.00 bis 3.00 in
3000Schritten. Das biegt ich um auf 2^c2, jetzt läuft c2 von 0 bis ~10
in 3000 Schritten, das sind ~30000 ticks, läßt sich durch eine 15Bit
Zahl darstellen.
Jetzt muss ich also 2^(c3/16348), mit einer natürlichen 15Bit Zahl c3
und der 16384ten Wurzel daraus, also 15Mal die Quadratwurzel. 2^c3
berechne ich mit 'square and multiply',
https://de.wikipedia.org/wiki/Bin%C3%A4re_Exponentiation, das kostet
maximal 15 Multiplikationen für den square, der multiply wird zum shift.
Immer wenn das Ergebnis droht zu gross zu werden, ziehe ich die
integer-Wurzel, geht auch schnell https://embdev.net/topic/246322#new
Also summa summarum ca. 17 multiply mit einem 32Bit Ergebnis, 15 billige
Wurzeln und einige shifts.
Muss man nochmal auf overflows abklopfen, aber geht schon.
Schönes Ding
math rulez!
Cheers
Detlef
Felix N. schrieb:> Und der PH Wert zwischen 6.00 und 9.00(600 bis 900).
Das wäre immerhin eine Dynamik von einem Faktor 1000.
Was willst du im Exponenten mit Integerzahlen, wenn du sowieso 10^x als
float rechnest?
Felix N. schrieb:> Den KH Wert in einem uint8_t> Integer fest zu halt ist kein Problem. Dort kann ich einfach statt 4,5> auch 450 schreiben
Das wird nix. 450 verträgt sich nicht mit dem Wertebereich von uint8_t
Felix N. schrieb:> Da der Prozessor wohl sehr viel Zeit braucht
Das klingt eher nach einer Lösung auf der Suche nach dem Problem,
als einem Problem auf der Suche nach der Lösung.