Forum: Mikrocontroller und Digitale Elektronik effiziente pow(,) - Funktion für ARM32 gesucht


von Erik H. (agutanus)


Lesenswert?

Momentan schreibe ich eine Funktion, zur barometrischen Höhenberechnung 
in einem Modellflugzeug. Das ganze erhält seine Messwerte aus einem 
Bosch BMP085-Sensor und läuft auf einem STM32F100RB mit 24 MHz.
Die Berechnung läuft auch hervorragend, dauert aber aufgrund der 
pow()-Funktion verhältnissmäßig lange...
1
/* calculate altitude in 0.1 m */
2
  B8 = (double)envPressure * 9.869232667e-006;    // 9.87e-6 = 1 / 101325 Pa
3
  B8 = pow(B8, 0.19029495718363465);
4
  altitudeAMSL = (int32_t)(443307.6923 * (1.0 - B8));

Allein die pow()-Funktion benötigt ca. 268 µs zur Ausführung!
(der µC besitzt leider kein float-Rechenwerk)
Die restlichen Berechnungen von Temperatur, Druck, Höhe und 
Mittelwertbildung benötigen lediglich 20 µs.

Nun sollen nebenbei noch eine ganze Menge trigonometrische Berechnungen 
von float-Werten durchgeführt werden, weshalb ich mir nicht sicher bin, 
ob die Rechenzeit irgendwann knapp wird...

Kennt jemand eine effizientere Funktionssammlung für ARM32-Prozessoren?
(sin, cos, tan, pow)

von Marc (Gast)


Lesenswert?

Look up table.

von Marius W. (mw1987)


Lesenswert?

Festkommaarithmetik

von blob (Gast)


Lesenswert?

Der Witz ist, dein Höhensensor wird nie auf 10 Stellen genau 
irgendwelche Werte ausspucken. Mit 32 bit Festkomma kommst du vielleicht 
schon ganz gut hin? Es gibt auch arms mit fpu, für die ganz Harten.

von blob (Gast)


Lesenswert?

pow = Logarithmieren > Multiplizieren > E Funktion

Kuck dich mal nach cordic Verfahren um, damit kann man relativ schnell 
die (co)sinūs berechnen

von Erik H. (agutanus)


Angehängte Dateien:

Lesenswert?

ach: im Anhang noch die komplette Funktion

Über eine look up table habe ich auch schon nachgedacht...
Um die Berechnung zu vereinfachen, könnte man Multiplikatoren statt 
Ausgangswerte ablegen. Dadurch müssen keine Zwischenwerte berechnet 
werden, sondern kann ein Multiplikator für einen festen Bereich von 
Eingabewerten genutzt werden.
Ist halt eine ätzende Arbeit die Multiplikatoren zu berechnen ;-)

Bevorzugen würde ich zwar eine tatsächliche pow()-Funktion, notfalls 
wird es aber die LUT.

Festkommaarithmetik finde ich in diesem Fall ziemlich ungünstig, da ich 
einen exponenten <1 habe ;-)

blob: deinen Beitrag verstehe ich nicht...

von blob (Gast)


Lesenswert?

blob schrieb:
> pow = Logarithmieren > Multiplizieren > E Funktion

Ich glaube mal gehört zu haben, dass die fpu eine Exponentialfunktion in 
diese drei Schritte zerlegt. Das wäre vielleicht ein Hinweis, wieso es 
so lange dauert.

Man kann jede beliebige Zahl in fixcomma darstellen, es muss halt 
skaliert sein. Dh. du hast nen Bruch < 1 ? Dann setze das komma halt an 
Erste stelle
0.FFFFFFFF wäre dann 0.9999... in Dezimal

Wenn du multiplizierst, bekommst du ein 64 bit Ergebnis, davon 
schneidest du halt mit Bitmanipulation den Ausschnitt, in den deine Zahl 
fällt, raus

von holger (Gast)


Lesenswert?

/* calculate altitude in 0.1 m */

Fein, ob dein Teil nun 0.1m oder 1m Auflösung hat
dürfte ziemlich egal sein. Da solltest du mal mit beiden Beinen fest
auf dem Boden bleiben;) Bis 10000m wirst du nicht kommen
mit deinem Spielzeug. Sagen wir mal 3000m. Dann schränkt
sich die Grösse einer LUT schon deutlich ein. Da würde ich gar nicht
mehr lange nachdenken.

von Erik H. (agutanus)


Lesenswert?

Division und Multiplikation mit Festkommaarithmetik darzustellen geht ja 
noch... aber Exponenzialfunktionen? Dabei ändert sich die Skalierung ja 
abhängig des zu potenzierenden Wertes...
bsp:
0.5 ^ const 0.9 = 0.54
1.0 ^ const 0.9 = 1.0
0.5 ^ const(4*0.9) = 0.082
1.0 ^ const(4*0.9) = 1.0
-> unterschiedliche Skalierung je nach Eingangswert


Aber ich bin gerade auf folgende Bibliothek gestoßen:
"arm_math.h" (in der KEIL-Entwicklungsumgebung enthalten)
die bietet interessante Funktionen zur trigonometrischen Berechnung 
an... (leider nur sin und cos)

ich suche mal weiter, ob ich was zu atan2 und pow finden kann.
(in der komplexen Rechnung ist eventuell was zum Errechnen des 
Phasenwinkels einer Komplexen Eingangszahl enthalten)

LUT schaue ich mir an, wenn die Rechenzeit tatsächlich mal knapp wird.
Vermutlich stören ein paar Nichtlinearitäten in der Höhenberechnung auch 
nicht, da es ja vorallem um das Halten einer Höhe geht. Notfalls kann 
man dazu auch einfach den Luftdruck auswerten.

von Florian P. (db1pf)


Lesenswert?

Hallo,

wenn du nur die Höhe halten willst, warum musst du jedes mal 
altitudeAMSL ausrechnen? - Kannst du nicht für das gewünschte 
altitudeAMSL das Soll envPressure ausrechnen und darauf regeln?

Grüße,
Florian

von Erik H. (agutanus)


Lesenswert?

@Florian:
Hast Recht, das kann man auch gut machen:
- zur Initialisierung (Bodenhöhe) einmalig aktuelle Höhe berechnen
- Offset draufgeben und gewünschten Luftdruck berechnen
- Höhenregelung nach Luftdruck

Übrigens funktioniert die Berechnung nun auf <0,5 m relative Höhe genau!
Dazu wird jeweils der Durchschnitt der letzten 16 Messwerte gebildet. 
(alle 640 ms)


Zur Lageberechnung benötige ich später ein mehrfach je Zyklus eine 
atan2() funktion. Dazu habe ich noch nichts in der ARM-Bibliothek 
gefunden...

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.