Im Rahmen der Weiterverarbeitung einer vom ADC eines Atmega8 gewandelten
Spannung muss ich den eingelesenen Wert mit einer recht kleinen
Kommazahl multiplizieren. Also in der Art:
Ergebnis = ADC-Wert * 0,000000071351753
In Bascom ist das ja kein Problem. Nur muss ich das leider in Assembler
lösen. Allerdings fehlt mir da im Moment ein gescheiter Lösungsansatz.
Kann mir da jemand evtl. weiterhelfen?
Du kannst Ergebnis=0 schreiben, wenn du mit 16bit Ganzzahlen rechnest.
Beschreib doch mal was du vorhast. Es gibt bestimmt eine einfachere
Lösung die auch funktioniert.
Es geht hierbei um die Aufloesung eines Polynoms 6. Grades, welches die
nichtlineare Kennlinie eines Sensors beschreibt.
Also ich muss da nicht nur einmal ADC*0.0000000xxxxx rechnen sondern im
Prinzip so:
Ergebnis = ADC*0.0000000xxxxxxxx
Ergebnis = Ergebnis - 0.000000xxxxxxxx
Ergebnis = Ergebnis * ADC
Ergebnis = Ergebnis + 0.00000000xxxxxxxx
Ergebnis = Ergebnis * ADC
Ergebnis = Ergebnis - 0.00000xxxxxxxx
Ergebnis = Ergebnis * ADC
Ergebnis = Ergebnis + 0.000xxxxxxxx
Ergebnis = Ergebnis * ADC
Ergebnis = Ergebnis - 0.0xxxxxxxx
Ergebnis = Ergebnis * ADC
Ergebnis = Ergebnis + 0.0xxxxxxxx
Brauchst du dabei wirklich 8 Stellen Auflösung ?
Der ADC liefert doch gerade mal 3 Stellen, da kannst du eigentlich
spätestens ab der 5. Stelle aufhören ohne dass sich am Ergebnis
wirklich was ändert.
Das kann man evtl. schon machen, da muss ich noch mal schauen. Mir geht
es aber halt darum, wie ich die Multiplikationen möglichst effizient
hinbekomme. Und da fehlt mit irgendwie immer noch der richtige Ansatz.
Mach doch erstmal ne Genauigkeitsabschätzung, wieviel Iterationen
überhaupt nen Sinn ergeben.
Aus 0..1023 kannst Du doch nie 8 Digits rauskitzeln !
Maximal 3 Digits, eher noch weniger je nach Nichtlinearität, dann ist
Ende der Fahnenstange.
Wenn ich das in Assembler machen müßte, würde ich mit Excel ne Tabelle
von etwa 50 Stützwerten ausrechnen lassen und dazwischen einfach linear
interpolieren.
Peter
Max, Deine kleinste Zahl ist ~10e-8, die größte ~10-2, macht 6
Zehnerpotenzen Dynamik, das entspricht 20Bit, 10Bit AD Wandler macht
nochmal 10Bit, zusammen 30, da muß Du in Integer schon mit 64Bit
rechnen, 32 reichen da nicht mehr. Oder Du muß in Assembler und float
rechnen. Beides nicht so schön.
Ich schließe mich meinen Vorrednern an: Die Genauigkeit, die Du
anstrebst, brauchst Du sicher nicht. 20Bit Rechendynamik bei 10Bit AD
Wandler Eingangsdynamik ist bullshit, das geht immer anders. Die
Genauigkeitsanforderungen solltest Du nochmal überdenken.
Cheers
Detlef
@Max:
Ein Polynom 6. Grades sieht normalerweise so aus:
Ergebnis = a0 + a1*ADC + a2*ADC^2 + a3*ADC^3 + ... + a6*ADC^6
Im Prinzip geht das immer mit einfacher Festkommaarithmetik. Das ist in
Assembler nicht so schwierig. Die sehr kleinen Werte, z.B. a6, werden
vermutlich mit den Polynomtermen höheren Grades multipliziert, sodass
das die einzelnen Terme am Ende immer einen "normalen" Wert ergeben.
I.d.R. reicht dann eine 32-Bit-Festkommaarithmetik, z.B. mit 16
Vorkomma- und 16 Nachkommastellen oder auch 24 Vorkomma- und 8
Nachkommastellen. Wenn Du jetzt z.B. den Term a6*ADC^6 wie folgt
aufspaltest
a6*ADC^6 = a6^(1/6)*ADC * a6^(1/6)*ADC * ... * a6^(1/6)
bleibst Du idealerweise immer in Deinem 32-Bit-Zahlenbereich. Du mußt
Dir halt vorher überlegen, in welchem Wertebereich der ADC liegt, damit
eine 32-Bit x 32-Bit-Multiplikation ein vernünftiges Ergebnis liefert.
Du mußt ja nach der Multiplikation, die 64 Bits liefert, immer 32 Bits
abschneiden können, ohne das Ergebnis nennenswert zu verfälschen.
Sinnvollerweise verschiebt man die Binärzahlen vor der Multiplikation
soweit nach links, dass die MSBs möglichst aufgefüllt werden und teilt
das Produkt entsprechend wieder durch Rechtsschiebung. Dadurch erreicht
man maximale Rechengenauigkeit. Bei komplizierten Formeln würde ich dann
aber lieber eine Fließkommaarithmetik verwenden.
Jörg
@Peter Dannegger
>Mach doch erstmal ne Genauigkeitsabschätzung, wieviel Iterationen>überhaupt nen Sinn ergeben.>Aus 0..1023 kannst Du doch nie 8 Digits rauskitzeln !
Klar, sogar 10! Allerdings nur binäre ;-)
MFG
Falk
>Bei komplizierten Formeln würde ich dann aber lieber eine >Fließkommaarithmetik
verwenden
Du hast ihm gerade nachgewiesen, das er auch bei 32Bit Festkomma
arithmetik aufpassen muss, das er nichts verliert. Ein float (und auch
double) auf dem AVR hat 32Bit, 8 Bit Exponent, Mantisse: 23 Bit
Mit deiner Mantisse von 23Bit wird die Situation wohl nur noch
verschlechtert.
Obwohl bei:
>Ergebnis = ADC-Wert * 0,000000071351753
also wenn BASCOM nicht mit 64bit double rechnet wird es wohl kaum
schlechter.
Stichwort: Maschinengenauigkeit
Mach es wie Peter vorschlägt mit einer Tabelle und Interpolation, selbst
mit nur 50 Stützwerten würde ich davon ausgehen das das schon genauer
ist, als dein jetziges BASCOM Programm. Warum muss das eigentlich
unbedingt in Assembler sein?