Logarithmus aus Int berechnen

Gast #1689694
Lesenswert?

Guten Tag

Ich möchte mit dem Atmega48 und den WinAVR einen Analogen Wert einlesen 
und diesen logarithmisch umwandeln. Die A/D Wandlung verläuft wie im 
AVR-GCC-Tutorial. Der Wert lässt sich gut einlesen und wird bisher in 
einen Integer gespeichert.

Für den Logarithmus habe ich die Formel:

x=20*log10(x/1024);

Diese eignet sich aber nicht für Integer und bei Float steig der 
Programmspeicherbedarf um etwa 100% an wenn ich das ADCH Register in den 
Float hineinschreiben will.

Wie kann ich nun das Register sauber in einen Float verrechnen? oder 
kennt jemand eine Alternative zu meiner Lösung?

Freundliche Grüsse

Zangetsu
Persönliche Seite #1689735
Lesenswert?

@zangetsu

So wie ich das sehe willst du dB ausrechnen (20*log10(x)).

Eine Möglichkeit dazu ist Zählen wieviele Nullen (von links aus gesehen) 
bis zur ersten 1 kommen. Jede 0 sind -6dB. Dann die Restlichen 
(beispielsweise 4 Bit) über eine kleine Tabelle ausrechnen um die 
Zwischenschritte von 1-5dB zu erhalten.

Bsp :
0000 1000 0000

4 Nullen -> -24dB
"000" nach der 1 -> +0dB als zus. Addition

0010 1000 0000 -> -12dB
"010" nach der 1 -> ca +2dB -> -10dB

Das ganze ist nur exemplarisch und müsste mal genauer ausgerechnet 
werden.
Aber das wäre neben der Tabelle ein Lösungsweg.
#1689829
Lesenswert?

>Ok muss ich wohl zur Tabelle greifen. Aber nur um sicher zu gehen: gibt
>es wirklich keine "normale" Möglichkeit einen Integer in einen Float zu
>schreiben?

Entweder durch das Casten:
1
float f;
2
int i;
3
i=IrgendwasWildes();
4
f=(float)i;
Dann ist in f statt z.B. 243 die 243,00 gespeichert.

Oder du bastelst die dein Float selbst, indem du das Vorzeichen, den 
Exponent, sowie die Mantisse zurechtfrickelst.
( http://de.wikipedia.org/wiki/Gleitkommazahl )


Zurück zum Logarithmieren:
1) Nimm ne Tabelle in der die Funktionswerte in äquidistanten Abständen 
gespeichert sind und interpoliere dazwischen linear.

2) Mit Kenntnis über den Logarithmus (bzw den betrachteten Bereich), 
kannst du die Tabelle anpassen und dort wo sich die Werte stärker ändern 
mehrere Einträge machen.
1
int Tabelleneintraege[]={1,3,9,16,25,36,100};
2
int zugehörigeWerte[]  ={1,2,3, 4, 5, 6, 10};
3

4
int getWert(int input){
5
  int ret;
6
  int i=0;
7
  while(Tabelleneintrag[i]<input)i++;
8

9
  //dein Wert liegt jetzt zwischen i und i+1
10
  // also musst du zwischen zugehörigeWerte[i] und zugehörigeWerte[i+1]
11
  // linear interpolieren.
12
  
13
  ret=Tabelleneintraege[i]+ \
14
   ( Tabelleneintraege[i+1]-Tabelleneintraege[i]) / \  
15
(zugehörigeWerte[i+1]-zugehörigeWerte[i])*input-Tabelleneinträge[i];
16
  return ret;
17
}

Zu guter Letzt:

Du kennst Festkomma-Arithmetik?
( http://de.wikipedia.org/wiki/Festkommazahl )
( http://www.mikrocontroller.net/articles/Festkommaarithmetik )

Viele Grüße
Stefan
#1689832
Lesenswert?

Falk Brunner schrieb:
> @  Zangetsu (Gast)
>
>>Ok muss ich wohl zur Tabelle greifen. Aber nur um sicher zu gehen: gibt
>>es wirklich keine "normale" Möglichkeit einen Integer in einen Float zu
>>schreiben?
>
> Sicher.
>
>
1
> int a;
2
> float b;
3
> 
4
> b=a;
5
> 
6
>

@Zangetsu

Aber sicher nicht so
1
x=20*log10(x/1024);

denn x / 1024  ergibt bei dir immer 0

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren