Hallo zusammen,
ich versuche gerade eine FFT auf einem 8 Bit Controller zu
implementieren. Da ich das Rad ja nicht neu erfinden muss, versuche ich
bereits vorhanden Code zu übernehmen:
http://forum.arduino.cc/index.php/topic,38153.0.html
Als ersten Schritt probiere ich das ganze erstmal auf PC zum laufen zu
bekommen. Am Code habe ich folgendes angepasst:
-Das Array "normal" als char angelegt statt im Flash
-"Normales" Auslesen des Arrays statt mit pgm_read_word_near()
-Funktionsaufruf hinzugefügt
-Ausgabe der Ergebnisse per printf
Inzwischen lässt sich das Projekt kompilieren aber das Ergebnis scheint
nicht zu stimmen. Wenn ich es richtig verstehe, müsste das Ergebnis doch
ins Array geschrieben werden, dann sollte doch bei einem Sinus ein
bestimmter Wert im Array stark ausschlagen? Stattdessen sind aber alle
denkbaren Werte im Array vertreten (inclusive negativer Werte). Falls
sich jemand mit der FFT auskennt und mir einen Tipp geben könnte, wäre
ich wirklich sehr dankbar, ich komme hier einfach nicht weiter.
Die Kommentare habe ich herausgenommen, weil der Code hier schon so lang
war. Im Original (siehe Link) sind die ausführlichen Kommentare ja noch
zu lesen.
1
#include<stdio.h>
2
#include<stdlib.h>
3
4
5
intfix_fft(charfr[],charfi[],intm,intinverse);
6
intfix_fftr(charf[],intm,intinverse);
7
8
intmain(intargc,char**argv)
9
{
10
#define N_WAVE 256 /* full length of Sinewave[] */
Beim Lesen des Artikels hast du einen der letzten Sätze übersehen:
Unfortunately, there is a flow in the code, no FFT performed
if you copy/paste as it is.
Falls du es auf einem Atmel AVR implementieren möchtest, schau dir mal
die Routinen von Chan an: http://elm-chan.org/works/akilcd/report_e.html
Der hat 'ne FFT-Routine in AVR-Assembler geschrieben, aber mit Interface
zur Verwendung aus C-Code heraus.
Die Library kannst du auf der verlinkten Seite unten runterladen, die
Sourcen für den Audio-Analyser (als Beispiel für die Verwendung der Lib)
ebenso.
Georg G. schrieb:> Beim Lesen des Artikels hast du einen der letzten Sätze übersehen:>> Unfortunately, there is a flow in the code, no FFT performed> if you copy/paste as it is.
Verdammt, das habe ich wirklich übersehen. Danke für den Hinweis. Aber
es stellt sich die Frage, was man tun muss, um den Code zu übernehmen.
Der User focalist hat es ja scheinbar hinbekommen.
Wie auch immer, solange ich damit nicht weiterkomme, sehe ich mir mal
die Routinen von Chan an. Fragen dazu folgen ;)
Achso, der Controller steht noch nicht ganz fest, aber es soll
wahrscheinlich irgendein PIC werden. Aber das müsste sich ja recht leid
adaptieren lassen, oder?
Vor allen Dingen mal aufräumen im Code.
Wenn ich for Schleifen sehe, die bei 1 anfangen, fangen bei mir die
Alarmglocken zu schrillen an.
Der Datentyp char ist schlecht gewählt. Kein Mensch weiß´, ob 'char' auf
diesem Compiler ein signed oder ein unsigned Datentyp ist. Immer
explizit sein! Es gibt 3(!) kleine Datentypen
* signed char
Für kleine Integer mit Vorzeichen
* unsigned char
Für kleine Integer ohne Vorzeichen. Das ist der Datentyp der Wahl,
wenn man es mit Bytes zu tun hat
* char
Für alles was mit Textverarbeitung zu tun hat.
Hier hat man es nicht mit Textverarbeitung zu tun. Daher ist
plain/vanilla char nicht angebracht, sondern ein 'ask for trouble'.
Josef schrieb:> Achso, der Controller steht noch nicht ganz fest, aber es soll> wahrscheinlich irgendein PIC werden. Aber das müsste sich ja recht leid> adaptieren lassen, oder?
Moment, da habe ich nicht nachgedacht. Die Libarys gehen ja nur für AVR.
Dann hilft mir das wohl nicht so einfach weiter, oder?
Karl Heinz Buchegger schrieb:> Immer explizit sein!
Wird gemacht :)
Karl Heinz Buchegger schrieb:> ist ziemlich offensichtlicher Blödsinn. Das sollte offenbar ein> Swap-Code sein, so wie das hier steht, ist es eine 0-Operation.
Ich verstehe nicht ganz, was du meinst, fr[m] und fr[mr] werden doch
getauscht, oder nicht? Wie müsste es denn anders heißen?
Josef schrieb:> Karl Heinz Buchegger schrieb:>> ist ziemlich offensichtlicher Blödsinn. Das sollte offenbar ein>> Swap-Code sein, so wie das hier steht, ist es eine 0-Operation.> Ich verstehe nicht ganz, was du meinst, fr[m] und fr[mr] werden doch> getauscht, oder nicht? Wie müsste es denn anders heißen?
Ich hab diesen Einwand wieder zurück gezogen, weil ich nach dem 5-ten
mal Code lesen gemerkt habe, dass das eine mal die Indexvariable m
heißt, während sie das andere mal mr heißt. So einfach sieht man das
nicht und das fällt für mich genauso unter Code-aufräumen:
Variablennamen so wählen, dass man aus 2 Meter Entfernung mit
Sonnenbrille erkennen kann, dass es sich um unterschiedliche Variablen
handelt. Persönlich mache ich seit langem einen großen Bogen um
veröffentlichten Code, bei dem 90% aller Variablen einen ein- oder
zweibuchstabigen Namen tragen.
Aus dem hier werde ich nicht schlau
1
shift=0;
2
for(i=0;i<n;++i)
3
{
4
j=fr[i];
5
if(j<0)
6
j=-j;
7
m=fi[i];
8
if(m<0)
9
m=-m;
10
if(j>16383||m>16383)
mal angenommen, dass ein char tatsächlich ein signed char ist. Dann
ändert sich der Zahlenwert bei der Zuweisung an den int j nicht. Auch
nicht bei negativen Zahlen. Aber wie soll ja dann größer als 16383
werden?
Angenommen char ist in Wirklichkeit in unsigned char. Dann werden
'negtive Werte' aus dem Original im Bereich 128 bis 255 abgebildet.
Wieder gibt es keine Chance jemals größer als 16383 zu werden.
So richtig hab ich noch nicht durchschaut, was hier eigentlich passieren
soll.
OK, bei dem Code kann man sich wirklich schnell man vertun. Aufräumen
würde ich trotzdem nur ungern, weil mir das Risiko hoch erscheint, dass
ich dabei nur weitere Fehler einprogrammiere. Das ist jetzt schon das
dritte Code-Beispiel, dass ich erfolglos versuche zum Laufen zu bringen
- Wirklich frustrierend! Falls jemand noch etwas für PIC Controller
kennt, wäre das auch super.
Bei dem Codestück muss ich dir Recht geben, die if-Abfrage müsste
tatsächlich nie erfüllt werden ... Ratlosigkeit
Ich müsste mich jetzt auch wieder in die FFT und den Butterfly
Algorithmus einlesen, wie der konkret funktioniert.
Wenn du das ganze sowieso am PC laufen hast, hindert dich ja nichts
daran, den Code mit printf zu spicken, erst mal mit einer kleineren
Datenmenge zu operieren und dann anhand der Ausgaben kontrollieren, ob
die richtigen Werte (sowohl Index als auch Zahlenwerte) miteinander
verrechnet werden.
Karl Heinz Buchegger schrieb:> Angenommen char ist in Wirklichkeit in unsigned char. Dann werden> 'negtive Werte' aus dem Original im Bereich 128 bis 255 abgebildet.> Wieder gibt es keine Chance jemals größer als 16383 zu werden.
Im Kopf der fft.cpp schreibt der Autor, dass alle Werte short int sind
und von -32768 bis +32767 laufen. Float war ihm zu langsam und zu
unbequem. Vermutlich ist einer der Fehler im Code, dass fr[] und fi[]
als char definiert sind. In seinem Beispiel Code weist er auch int Werte
zu und nicht char.
Karl Heinz Buchegger schrieb:> Ich müsste mich jetzt auch wieder in die FFT und den Butterfly> Algorithmus einlesen, wie der konkret funktioniert.
Geht mir auch so, nur dass ich nicht sicher bin, ob ich überhaupt in der
Lage bin den Stoff wirklich zu verstehen.
Karl Heinz Buchegger schrieb:> Wenn du das ganze sowieso am PC laufen hast, hindert dich ja nichts> daran, den Code mit printf zu spicken, erst mal mit einer kleineren> Datenmenge zu operieren und dann anhand der Ausgaben kontrollieren, ob> die richtigen Werte (sowohl Index als auch Zahlenwerte) miteinander> verrechnet werden.
Dafür mache ich es erstmal am PC. Bisher ist der FFT-Code aber eine
Black Box für mich. So kann ich natürlich auch nichts debuggen.
Georg G. schrieb:> Im Kopf der fft.cpp schreibt der Autor, dass alle Werte short int sind> und von -32768 bis +32767 laufen. Float war ihm zu langsam und zu> unbequem. Vermutlich ist einer der Fehler im Code, dass fr[] und fi[]> als char definiert sind. In seinem Beispiel Code weist er auch int Werte> zu und nicht char.
Stimmt. Gerade habe ich einfach mal blauäugig alles zu unsigned short
int gemacht, aber natürlich ohne Erfolg. Ich frage mich nur, wie es sein
kann, dass der Code beim Autor und auch anderen funktioniert hat. Dann
kann doch eigentlich nichts so grundsätzliches falsch sein.
Als Zwischenergebnis:
In dem Paket sind zwei FFT Funktionen, für real/imaginär Daten und für
nur-real-Daten.
Die nur-real-Daten Funktion hat in der Theorie den Charme, das sie
drastisch schneller ist. Leider funktioniert sie in der angegebenen Form
nicht.
Die real/imaginär Daten Funktion funktioniert gut, wenn man nur real
Daten vorgibt und das imaginäre Feld mit Nullen füllt. Mit imaginär
Daten ungleich Null habe ich es nicht versucht.
Es sind einige verbesserungsfähige Stellen in dem Programm. Als
Beispiel: Man muss kein int16_t aus einer Tabelle von int8_t Werten
lesen. Die Kommentare sind teilweise - wohl aus historischen Gründen -
irreführend.
Vielleicht findet sich ja noch jemand, der die Macken sucht und hier
publiziert.
Josef schrieb:> Achso, der Controller steht noch nicht ganz fest, aber es soll> wahrscheinlich irgendein PIC werden. Aber das müsste sich ja recht leid> adaptieren lassen, oder?
Wenn es ein dsPIC wird (und das wäre bei einer FFT vielleicht sinnig),
hat sich Microchip schon darum gekümmert:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en023598
Die Bibliothek ist beim C30 Compiler dabei. Du darfst sie einfach
benutzen.
fchk