Forum: Compiler & IDEs linearisieren zwischen 16-bit werten macht mir noch Schwierigkeiten


von Tobi W. (Gast)


Lesenswert?

Hallo zusammen,

ich stehe hier gerade vor einem kleinen Problemchen.
Ich will mal versuchen es strukturiert zu (be)schreiben:

Ziel ist es, eine Funktion zu bauen, die mir "Zwischenwerte" (durch 
linearisieren) aus einer Wertetabelle generiert.
Die Tabelle ist eine 16-bit -> 16-bit "Abbildungstabelle" (abgelegt in 2 
arrays pos[] und val[]) und wird in etwa (mit krümmeren Zahlen) wie 
folgt aus sehen:
1
pos[] -> val[]
2
--------------
3
35000 -> 25000 ("steigende" und "fallende" Werte sind möglich!!!)
4
36000 -> 18000
5
38000 -> 20000
6
43000 -> 30000
7
50000 -> 40000

Nun habe ich eine Funktion, welche mir aus einem gegebenen Suchwert 
(z.B. sw=39000) ein tabellenindex i(=2 im Beispiel) zurück liefert, da 
pos[i]=38000 <= sw=39000 < pos[i+1]=43000

Was ich nun suche ist eine Funktion die mir im Prinzip nichts anderes 
berechnet als:
f(x) = val[i] + ( sw - pos[i] ) * ( val[i+1] - val[i] ) / ( pos[i+1] - 
pos[i] )
Im Beispiel: f(x) = 20000 + (39000-38000) * (30000-20000) / 
(43000-38000) = 20000 + 1/5 * 10000 = 22000


Und nun zu meinem Problem dabei:
Wie bekomme ich das hin, dass ich das halbwegs effizeint (in GCC) und 
ohne verletzung von Wertebereichsbeschränkungen berechne?
Die Division lässt sich (im Rahmen meiner Kreativität) nicht durch 
effizientere Methoden umschiffen, aber:
- erst dividieren, dann multiplizieren ergibt eine große Ungenauigkeit, 
da z.b. der Faktor 1/5 von oben zu 0 abgerundet werden würde.
- wohingegen aber erst Multiplizieren, und anschließendes Dividieren 
einen überlauf der 16-bit zufolge haben wird.

einen PC würde ich jetzt mit 32-bit rechnen lassen (bzw. das tut er ja 
meist eh immer), für meinen Mikrocontroller wird der Code fertig 
compiliert dann aber wohl ziemlich groß (vermutlich sogar zu groß), da 
dann auchnoch routinen für 32-bit-rechnung (vom compiler) eingebaut 
werden müssten. Oder ist das eine nicht übertragbare Erfahrung von den 
floats, zu denen es ja mehrere Meinungen gibt und ich sie daher diesmal 
möglichst auslassen möchte.

aktuell finde ich also keine nach meiner Meingung sinnvolle bzw. 
zielführende Lösung an, irgendeine muss ich aber wohl finden.
Da ich aber auch noch relativ neu und nur theoretisch Wissend im 
Mikrocontrollerbereich bin, wäre ich über ein paar Erfahrungen und Ideen 
zur Lösung meines Problems von euch Profis recht glücklich.

Vielen Dank
MfG
Tobi

von Karl H. (kbuchegg)


Lesenswert?

Tobi W. schrieb:


> - erst dividieren, dann multiplizieren ergibt eine große Ungenauigkeit,
> da z.b. der Faktor 1/5 von oben zu 0 abgerundet werden würde.

Hst du ja selbst schon festgestellt: Dividieren so weit wie möglich zum 
Abschluss der Berechnung machen

> - wohingegen aber erst Multiplizieren, und anschließendes Dividieren
> einen überlauf der 16-bit zufolge haben wird.

Ich verstehe, dass dein Beispiel ein Konstruiertes ist und sich 
offensichtliche 'Heraushebspielchen' in den realen Werten nicht machen 
lassen.

Daher ...

> einen PC würde ich jetzt mit 32-bit rechnen lassen (bzw. das tut er ja
> meist eh immer), für meinen Mikrocontroller wird der Code fertig
> compiliert dann aber wohl ziemlich groß

Nicht notwendigerweise.
Addition, Subtraktion von 32 Bit Werten ist nicht die Welt. Lediglich 
die Multiplkations und Divisionsroutinen sind merkbar größer.

Aber es hilft nichts. Wenn du 32 Bit brauchst, dann brauchst du 32 Bit


Möglicherweise existiert noch eine andere Möglichkeit. Das kann man aber 
erst sagen, wenn man sich die realen Zahlen ansieht.
Evetuell gibt es eine Möglichkeit, wie du die Tabelle am PC schon 
vorformatierst, so dass sich am µC die Berechnung vereinfacht.

Im Grunde legst du ja von einem Stützpunkt zum nächsten eine Gerade 
hinein.

   y = K * x + d

wobei du k und d bei deiner Lösung zur Laufzeit des Programms 
berechnest. Das muss aber nicht so sein.
Wenn in deiner Tabelle ein

   k_zaehler, k_nenner und ein d

existieren, dann könnte man unter Umständen alles so hindrehen, dass es 
sich mit 16 Bit Arithmetik noch ausgeht. Denn dann könnte man den Bruch, 
der sich k schimpft unter Umständen soweit runterkürzen, dass die 
Zwischenergebnisse nicht zu gross werden.

Das hängt dann natürlich auch von den Werten für x ab, die du durch die 
Formel jagst.

Du siehst also: Wenn man Wissen über die real vorkommenden 
Zahlenbereiche benutzen kann, dann kann man unter Umständen einfachere 
Lösungen finden. Wenn es aber eine Lösung sein muss, die mit allem mehr 
oder weniger klar kommt, dann muss man 16 Bit Multiplikationen 
grundsätzlich im 32 Bit Raum betreiben. Ob man will oder nicht

von Peter (Gast)


Lesenswert?

Hallo,

Wenn val[] und pos[] const sind kannst du

s[i]=1024 * (val[i+1]-val[i]) / (pos[i+1]-pos[i]) vorausberechnen
und dann
f(sw) = val[i]+(sw-pos[i])*s[i]/1024 rechnen.

Division wird jetzt ein shift und wenn die 1024 als 2er Potenz groß 
genug ist bleibt es auch einigermaßen genau. Um 32 Bit kommst du damit 
aber nicht herum.

Du kannst auch einfach alle Tabellenwerte durch einen festen Wert (z.B. 
16) teilen und am Schluß den Funktionswert damit multiplizieren (wieder 
2er Potenz nehmen). Dann verlierst du etwas Genauigkeit, brauchst aber 
keine 32 Bit mehr nehmen.

Peter

PS: ist spät, hoffentlich hab ich keinen Mist geschrieben

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.