PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : double to integer oder exp(x) mit integer



fambi_mail
27.02.2006, 19:27
Mein eigentliches Problem ist es eine Exponentialfunktion in der Schleife zu rechnen. Leider kann die aber nur mit double arbeiten. Als Ergebnis brauche ich aber eine Ganzzahl. Deshalb müsste ich jetzt das Double Ergebnis wieder in Integer umwandeln, wofür es auch keine Standardfunktion gibt. Das kann doch nicht die Lösung sein.
Hat vielleicht schon jemand ähnliche Erfahrungen gemacht?

PasstScho
27.02.2006, 20:23
kannst du nicht int bla=(int)deindouble; machen?

ruediw
27.02.2006, 22:46
Es gibt in JEDER Programmiersprache Funktionen um Zahlen
zwischen den verschiedenen Formaten umzurechnen ...

ManniMammut
27.02.2006, 23:12
@Ruediw: Darf ich den Sinn deiner Bemerkung hinterfragen? Natürlich kann man in jeder Programmiersprache sog. "casts" durchführen.

PasstSchos Vorschlag müsste theoretisch funktionieren.

fambi_mail
28.02.2006, 08:24
Ja, aber es gibt keine casts fuer float nach integerzahlen, da da dies etwas komplizierter ist, wegen der internen abspeicherung von exponent und mantisse

fambi_mail
28.02.2006, 09:08
Ergänzung: Du hast recht für folgendes Szenario

int i = 0;
double x = 41.27346;

i = (int) x;

das funktioniert!

Aber: i = (int) exp(x);

geht nicht!


Sobald ich irgendwo im Code eine exp-Funktion aus der math library verwenden kann ich den Code nicht mehr compilieren und eine brauchbare Fehlermeldung kommt auch nicht. Nur dass das Objectfile nicht vorhanden ist.

Evtl. muss man einen speziellen Schalter umlegen oder noch etwas einbinden?

Ich benutzte uebrigends das AVR-Studio mit AVR-GCC Plugin

ogni42
28.02.2006, 09:14
Poste doch mal Dein makefile

SprinterSB
28.02.2006, 09:40
Links du auch die libm dazu? mit -lm

::Edit::

Nochwas: Wozu brauchst du eigentlich exp? Vielleicht gaht das viel billiger mit anderen Funktionen?

fambi_mail
28.02.2006, 13:24
Gerne wuerde ich auch etwas einfacheres nehmen, aber was?

SprinterSB
28.02.2006, 14:04
Wozu brauchst du denn exp?

ManniMammut
28.02.2006, 14:08
~> man exp
achnee, unter Windows gibts ja keine man-Pages ^^

Also, dann klär ich mal auf: exp ist die natürliche Logarithmusfunktion

SprinterSB
28.02.2006, 14:15
Fast. exp ist die Exponentialfunktion.

Ja nach Verwendungszweck kann man ja nen anderen Weg wählen, als den Brummer double exp(double). (double ist eh ne Mogelpackung, intern ist das nur float)
-- Urbildbereich?
-- Genauigkeit?
-- Muss es Basis e sein? Oder tut's auch z.B. 2?
-- etc?

fambi_mail
28.02.2006, 14:42
Nein, es geht nur darum das OCR0-Register fuer eine PWM zu fuellen. Und zwar soll das Tastverhältnis mit 40*exp(-t/tau)+30 abklingen. Das Ergebniss muss also noch auf Werte von 0 ... 255 (OCR0 ist 8bit) scaliert werden. Die Zeit von der oberen Schwelle zur unteren Schelle soll ca. 300ms sein, also in der Zeit ist die PWM auf der unteren Schelle.

Natürlich kann man eine Tabelle machen, aber wie sieht es dann aus, wenn tau sowie die Schwellen als Paramenter vorgebbar sein sollen?!

fambi_mail
28.02.2006, 14:45
also das 40*exp(-t/tau)+30 war dann natürlich das Tastverhältnis in Prozent

SprinterSB
28.02.2006, 16:00
Was sind denn t und tau. Integrale Typen oder floats? *würmer-aus-der-Nase-zieh*

fambi_mail
28.02.2006, 16:24
entschuldigung ... fuer tau reichen ganze zahlen aus. t werde ich ueber eine Laufvariable gewinnen. Ich weiss noch nicht, da ich dann nicht so viele Zíschenwerte bekomme.

Wie gesagt. Eine PWM soll mit einem Tastverhältnis von 70% bis 30% innheralb von 0.3 sec exponentiell abklingen.

ruediw
28.02.2006, 20:40
Ja, aber es gibt keine casts fuer float nach integerzahlen, da da dies etwas komplizierter ist, wegen der internen abspeicherung von exponent und mantisse

@fambi_mail
Ist doch nicht wahr !! Programmierst Du in Assembler ?

Wenn es keine direkte von Float zu integer gibt, so gibt
es immer eine von Float zu einem String und eine
von einem String zu einem Integer.

Die Programmiersprache für einen modernen uC (ausser Assembler)
die das nicht kann, möchte ich mal sehen....

Meinst Du dass wenn du den Befehl nicht kennst, es diesen Befehl
automatisch nicht gibt ??

SprinterSB
01.03.2006, 09:02
Mal ganz abgesehen davon, daß

(int) exp ((double) t/tau) funktionieren sollte...

Was du willst in eine geometrische Progression, d.h. zwei aufeinander folgende Werte haben immer den gleichen Quotienten.

Nehmen wir mal an, du begnügst dich mit einem duty von 16 Bit, also Werten 0...0xffff. Nehmen wir weiterhin an, zwei aufeinanderfolgende Werte haben einen Quotienten von 1.01. Auf 0xffff folgt also 0xfd76. Zwei benachbarte Werte sind also durch 1.01 zu teilen, was hier gleichbedeutend damit ist, sie mit 0x10000/1.01 = 0xfd77 zu multiplizieren. Wir haben also 16-Bit Werte, bei denen wir alle 16 Bits als Nachkommastellen interpretieren. Multiplizieren wir zwei dieser Werte, haben wir 32 Bit Nachkommastellen, und schieben das Ergebnis der Mul daher um 16 nach rechts:

extern uint16_t fixprod16 (const uint16_t, const uint16_t); // Prototyp für *.h

uint16_t fixprod16 (const uint16_t a, const uint16_t b)
{
uint32_t ab = (uint32_t) a*b;
return ab >> 16;
}

Der Nachfolger von x ist dann

fixprod16 (x, 0x10000/1.01)

Das ist auf jeden Fall deutlich effizienter als Geschütze wie exp.

Als Argumente von fixprod16 gehen natürlich auch Werte, die nicht zur Compilezeit bekannt sind.

fambi_mail
01.03.2006, 17:36
Hallo Georg-Johann, ich habe nicht soviel verstanden von dem was du meinst.

uint16_t x,y;

for (x=10;x>0;x--){
y=fixprod16 (x, 0x10000/1.01);
}

also so funktioniert es nicht. Was ist denn x und ist fuer 0x10000 eine variable zu verwenden?

SprinterSB
01.03.2006, 17:53
Eher so was:

#include <avr/io.h>
...
uint16_t i; // Laufvariable
uint16_t duty = ...; // Duty, mit dem angefangen wird

for (i=0; i<100; i++)
{
duty = fixprod16 (duty, faktor);
OCR1A = duty;
}

Dabei gibt faktor an, um welches Verhältnis sich zwei aufeinander folgende dutys unterscheiden:
64887 --> 1.01
62415 --> 1.05
59578 --> 1.1
46341 --> Wurzel(2)
43690 --> 1.5
32768 --> 2
20860 --> PI
16384 --> 4

etc.

SprinterSB
01.03.2006, 18:11
Wenn also dein Faktor als double vorliegt, etwa dFaktor, dann
ist

faktor = (uint16_t) (65536.0 / dFaktor), wobei für dFaktor gelten muss
0 < dFaktor < 0.99998

Ich weiß ja nicht, wie du an den Faktor kommst, aber double-Arithmetik ist recht klotzig. Wahrscheinlich geht das auch per schlanker und schneller fix-Arithmetik.

Ist zwar nicht so schön hinzuschreiben, aber es lohnt die paar Zeilen Code.

SprinterSB
02.03.2006, 11:14
Sorry, für dFaktor muss :oops: natürlich gelten
dFaktor > 1.001, weil er ja das Abklingen angibt, also um welchen Faktor die neue Duty kleiner ist als sie alte.

Die obige Schleife ist natürlich nur der prinzipielle Aufbau. In vivo ist das viel zu schnell und muss noch verzögert werden.