Forum: Mikrocontroller und Digitale Elektronik Berechnung durch Näherungsformel


von Markus (Gast)


Lesenswert?

Hallo

ich möchte in meinem Tiny13 mit der in Excel ermittelte Formel
y = 0.004347x2 + 0.174571x - 155.697431
eine Temperatur (y) berechnen.

Die Formel hab ich genähert durch:
y = (68x/1024)^2 + 89x/512 -156

und entsprechend umgesetzt:
volatile int32_t temperatur;
temperatur = (((68*ADC) >> 10)^2)
           + ((89*ADC) >> 9)
           - 156;

Die ADC-Werte überschreiten den Wert von 350 nie, einen Überlauf sollte 
also weder beim 1. noch beim 2. Term geben. Doch leider stimmt das 
Ergebnis hinten und vorne nicht.

Auch wenn ich im Code die Variable "ADC" durch einen fixen Wert 
ersetzte, weicht die Ausgabe stark vom erwarteten Ergebnis ab. Hier 
einige Beispiele

Faktor an Stelle von "ADC"      Ergebnis        erw. Ergebnis
0                               -154            -156
16                              -151            -153 (= 1^2 + 2 - 156)
128                             -124            -70 (= 8^2 + 22 - 156)
256                             -93             177 (= 17^2 + 44 - 156)
350                             -75             433 (= 23^2 + 60 - 156)

Woran liegt der Fehler???
Besten dank für eure Hilfe

von ... (Gast)


Lesenswert?

Dann schau Dir nochmal genau an, was der Operator ^ macht :)

von Pow (Gast)


Lesenswert?

Weil du in C nicht einfach so ^2 schreiben kannst, dafür gibt es die 
Funktion pow() http://www.elook.org/programming/c/pow.html

MfG

von Markus (Gast)


Lesenswert?

oooops, schande über mich, jetzt funktionierts auch ;)
vielen dank!

von ... (Gast)


Lesenswert?

Pow schrieb:
> dafür gibt es die Funktion pow()

Nee, die nutzt hier nun grade absolut überhaupt nichts.

von minifloat (Gast)


Lesenswert?

Bei einer Bitfummelei etwas zu ver-XOR-n sieht zwar witzig aus, aber so 
tät ich des nicht machen. Schreib dir eben eine pow(); - Funktion. Oder 
eine Makrofunktion. Inline könnte es eine while-Schleife mit 
ordentlichem Funktionsrumpf richten.
mfg mf

von greg (Gast)


Lesenswert?

Wofür pow()? Hier reicht doch einfach x*x zu schreiben. Wenn man den 
Exponenten nicht dynamisch bestimmt, sollte sowas meistens schneller 
sein und weniger Code benötigen, wenn ich mich nicht irre.

von Markus (Gast)


Lesenswert?

wenn ich nun den ersten term mit ((68*ADC) >> 10) * ((68*ADC) >> 10) 
berechne (die funktion pow() kann ich nicht einsetzten, hat keinen platz 
hat in meinem 1k flash), scheint das resultat korrekt zu sein.
rechne ich jedoch (68*68*ADC*ADC) >> 20) (oder 4624 anstelle von 68*68) 
erhalte ich nicht das gewünschte.
mein ADC wert hat zwar eine breite von 11 Bit, wie aber oben erwänt wird 
der ADC-wert aber nie grösser als 380 und braucht somit auch höchstens 9 
bits. damit tritt bei der berechnung keinen überlauf auf und kann immer 
in einer 32-bit variable (eigentlich ja nur 31 bits für den wert, 1 bit 
fürs vorzeichen) gespeichert werden.
woran liegt das?

von Karl H. (kbuchegg)


Lesenswert?

1
380 * 380 * 4624   -> 667705600
und das ist weit über dem mit 16 Bit machbaren Maximum

schon alleine, dass du das Ergebnis (das maximal 16 Bit haben kann) um 
20 Bit nach rechts schieben willst, hätte dich stutzig machen müssen.

von Markus (Gast)


Lesenswert?

aber ich hab ja ein int32_t, also 32 bits (31 für den wert und 1 
vorzeichenbit)?!?!

von Karl H. (kbuchegg)


Lesenswert?

> die funktion pow() kann ich nicht einsetzten

Die Funktion pow willst du auch nicht für so etwas triviales wie ein 
Quadrat einsetzen.

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:
> aber ich hab ja ein int32_t, also 32 bits (31 für den wert und 1
> vorzeichenbit)?!?!


Wo hast du einen int32_t?

von Professor Crey (Gast)


Lesenswert?

Und von welchem Typ ist ADC? Die Zahlen 68, 1024 sind erst mal int.

von Karl H. (kbuchegg)


Lesenswert?

Du meinst den hier?

volatile int32_t temperatur;

der ist uninteressant.

Der besagt nur, dass das Ergebnis deiner Berechung auf 32 Bit 
aufgeblasen wird, nachdem der Ausdruck ausgewertet wurde. Aber solange 
ADC kein 32 Bit Wert ist, ist das eine stink normale 16 Bit Berechnung.


http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

von DirkB (Gast)


Lesenswert?

Und wenn du schon mit int32 rechnest solltest du das >>20 zum Schluss 
machen:

y =   0.004347x2 + 0.174571x - 155.697431
  =  (4558,159872x2 + 183050,960896x  - 163260589,408256 )/ 1024/1024
  = ((4558 * x + 183051)*x - 163260589)>>20

von stru_aus (Gast)


Lesenswert?

ersetze:
(68* bla)>>10
durch
(17* bla)>>8

von Markus (Gast)


Lesenswert?

ok vielen dank, jetzt klappts so wie ichs mir vorgestellt hab.
thx;)

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.