Forum: Mikrocontroller und Digitale Elektronik Unkomplizierte Berechnung oder doch schon Gleitkomma Berechnung?


von Felix N. (felix_n888)


Lesenswert?

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:
1
uint16_t co2 = ((KH / 280) * pow(10, 7.90-(PH/100))) * 1000;

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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?

von Felix N. (felix_n888)


Lesenswert?

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

von Rainer V. (a_zip)


Lesenswert?

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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?

von Felix N. (felix_n888)


Lesenswert?

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

von Jim M. (turboj)


Lesenswert?

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.

von Karl (Gast)


Lesenswert?

10^x, da würde ich eine Lookup-Tabelle nehmen. Für den gewünschten 
Wertebereich vorberechnen und im uC ablegen.

von Rainer V. (a_zip)


Lesenswert?

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

von Non-Optimizer (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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.

von Rainer V. (a_zip)


Lesenswert?

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

von Rainer V. (a_zip)


Lesenswert?

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

von A. S. (Gast)


Lesenswert?

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?

von Rainer V. (a_zip)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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?

von Stefan F. (Gast)


Lesenswert?

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.

von Detlef _. (detlef_a)


Lesenswert?

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

von Wolfgang (Gast)


Lesenswert?

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

von foobar (Gast)


Lesenswert?

Und weil's so schön ist, noch mit Tabelle:
1
static const uint16_t co2powtab[300] = {
2
    ... // [i] = 32*100 * pow(10, 7.9 - (600+i)/100.) / (2*2.8) + .5
3
};
4
5
// kh_2:        kh*2    (1..50)
6
// ph_100:      ph*100  (600..900)
7
// co2_100:     co2*100 (1..65535)
8
uint16_t co2_100(uint8_t kh_2, uint16_t ph_100)
9
{
10
    uint32_t c = kh_2 * (uint32_t)co2powtab[ph_100 - 600] + 16;
11
    return (c < 0x200000) ? c / 32 : 0xffff;
12
}

Braucht 600 Bytes für die Tabelle und eine 6bit x 16bit Multiplikation 
mit 22bit-Ergebnis (hier in C halt mit 32bit).

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?


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
Noch kein Account? Hier anmelden.