Forum: Digitale Signalverarbeitung / DSP / Machine Learning Fragen zu FFT


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo allerseits,

ich beschäftige mich im zuge meines "Lichtorgel-Pimpens" etwas mit FFT 
am AVR. Hier scheint die Version von Elm Chan ja weit verbreitet zu 
sein: http://elm-chan.org/works/akilcd/report_e.html die ist 
größtenteils in Assembler, und ich tu mir schwer die zu verstehen...

Frage 1: Der Code stammt aus dem Jahr 2005, scheint aber immer noch gut 
zu funktionieren (und deshalb weit verbreitet zu sein). In den letzten 
10 Jahren dürfte sich aber am Compiler-Sektor doch einiges getan haben, 
sodass eine reine Assembler-Implementierung nicht mehr den riesigen 
Vorsprung vor einer klugen C-Implementierung haben sollte. Kann man das 
so sagen? Wenn ja, gibt es eine sinnvolle C-Implementierung für AVR 
(ATmega328)? Mir gehts weniger darum die auch einzusetzen, sondern mehr 
ums Verstehen (Windowing im Preprocessing hab ich begriffen, bit 
reversal im Postprocessing auch, in der Mitte haperts etwas bei den 
butterfliegen...)

Frage 2: wie ist denn das mit der "Trennschärfe" der Bänder? Wenn ich 
das richtig verstanden habe, haben die Bänder ja immer die doppelte 
Frequenz, also z.B. 100 - 200 - 400 - 800 Hz. Was passiert bei einem 
Signal von 300 Hz?

Frage 3: Wenn ich nur wenige Bänder haben will (Lichtorgel, da reichen 
eigentlich 3, wenn ausbaubar vielleicht 6 oder 8) ist da FFT überhaupt 
die richtige Herangehensweise? Das "Referenzprojekt" 6-kanal-Lichtorgel 
am AVR  nutzt auch die ElmCHan-FFT, um nachher erst wieder (mühsam) die 
Bänder zusammenzufassen. ist das nicht "Rechenzeit verschütten"?

Danke euch, Michi

: Verschoben durch Admin
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Keine Hinweise? Bin ich gar nicht gewöhnt hier...

von Klaus (Gast)


Lesenswert?


von asdfasd (Gast)


Lesenswert?

> Frage 1: [...] eine reine Assembler-Implementierung nicht mehr den riesigen
> Vorsprung vor einer klugen C-Implementierung haben sollte. Kann man das
> so sagen? Wenn ja, gibt es eine sinnvolle C-Implementierung für AVR
> (ATmega328)?

Teilweise sind da Bitfuseleien, die in Assembler einfacher effizient zu 
implementieren sind.  Probiers halt aus.

> Mir gehts weniger darum die auch einzusetzen, sondern mehr ums Verstehen

Wenn's ums Verstehen geht, nimm ne Floatingpoint FFT auf'm PC.  Die 
Fixed-Point-Implementation auf einer 8-Bit-CPU schlägt sich mehr mit den 
Limitierungen der CPU rum als mit dem Algorithmus an sich.

> Frage 2: [...] Wenn ich das richtig verstanden habe, haben die Bänder ja
> immer die doppelte Frequenz, also z.B. 100 - 200 - 400 - 800 Hz.

Nein, das ganzzahlige Vielfache der Grundfrequenz: 100, 200, 300, ...
Und es sind "Bänder", die sich auch etwas überlappen.

> Frage 3: Wenn ich nur wenige Bänder haben will (Lichtorgel, da reichen
> eigentlich 3, wenn ausbaubar vielleicht 6 oder 8) ist da FFT überhaupt
> die richtige Herangehensweise?

Eine FFT hat eine Laufzeit von O(n*log(n)), ein FIR-Filter O(n).  Rein 
theoretisch sind FIRs schneller, solange du nur maximal log(n) Stück 
brauchst (bei 128-FFT also 7 FIR).  Allerdings ist das O(1) bei der FFT 
größer als bei dem FIR, so dass du wohl noch einige FIRs drauf legen 
kannst.  Dazu kommt, dass du bei wenigen diskreten FIRs wohl nicht alle 
mit 128 Samples laufen lässt.

> Das "Referenzprojekt" 6-kanal-Lichtorgel
> am AVR  nutzt auch die ElmCHan-FFT, um nachher erst wieder (mühsam) die
> Bänder zusammenzufassen. ist das nicht "Rechenzeit verschütten"?

Was machst du denn mit der nichtverbrauchten Rechenzeit?  Ne Busyloop? 
Es gibt kein "Geld zurück" für nicht verbrauchte Rechenzeit.  Wenn eine 
Lösung mit FFT einfacher und trotz des Rechenaufwands schnell genug ist, 
was spricht dagegen?

von c-hater (Gast)


Lesenswert?

Michael Reinelt schrieb:

> die ist
> größtenteils in Assembler, und ich tu mir schwer die zu verstehen...

Keine Arme->keine Kekse. Lerne einfach Assembler. AVR-Assembler ist 
wirklich einfach, an einem WE vollständig erlernbar (natürlich nicht die 
perfekte Nutzung, nur die vollständige Sprachkenntnis).
Ganz im Gegensatz zu C. Das benötigst du Wochen allein bis zur 
vollständigen Sprachkenntnis...

Wobei ich sowieso davon ausgehe, daß du (wie die meisten) von C sowieso 
nicht mehr begriffen hast, als nötig ist, um den geklauten Code anderer 
Leute zum Laufen zu bringen und irgendwie zusammenzuleimen...

> Frage 1: Der Code stammt aus dem Jahr 2005, scheint aber immer noch gut
> zu funktionieren (und deshalb weit verbreitet zu sein). In den letzten
> 10 Jahren dürfte sich aber am Compiler-Sektor doch einiges getan haben,

Nicht wirklich. Mit Assembler kann man immer noch um etwas bis sehr viel 
schneller sein als mit C. Hängt von der Aufgabe ab. Es gibt aber nach 
wie vor keine (und wird es auch niemals geben) eine Aufgabe, bei der 
eine Umsetzung in C schneller ist als eine von kompetenten Leuten 
geschriebene Asm-Routine. D.h.: Jeder C-Versuch kann bestenfalls so 
gut ausfallen wie die optimale Asm-Routine, aber niemals besser. 
Tendenziell ist also Asm IMMER im Vorteil. Und weil das so ist, lohnt 
es auch immer, Asm zu lernen...

> Frage 2: wie ist denn das mit der "Trennschärfe" der Bänder? Wenn ich
> das richtig verstanden habe, haben die Bänder ja immer die doppelte
> Frequenz

Das hast du definitiv nicht richtig verstanden. Ganz 
sprach-unabhängig...

> Frage 3: Wenn ich nur wenige Bänder haben will (Lichtorgel, da reichen
> eigentlich 3, wenn ausbaubar vielleicht 6 oder 8) ist da FFT überhaupt
> die richtige Herangehensweise?

Nein, da würde man wohl sinnvollerweise auf Goertzel setzen. Auch wieder 
sprachunabhängig. Allerdings: auch hier wird wieder nur in Assembler der 
optimale Gortzel entstehen können, C-Umsetzungen werden mehr oder 
weniger langsamer sein...

Das liegt daran, daß Goertzel (wie auch FFT) zwar schon relativ simpel 
ist, aber noch nicht simpel genug, daß ein C-Compiler ihn aus eigener 
Kraft wirklich optimal umsetzen könnte...

Das gilt selbst dann noch, wenn der C-Programmierer unendlich viel Zeit 
dafür einsetzt, seinen Compiler in die richtige Richtung zu tricksen. 
Mal abgesehen davon, daß genau das NICHT Sinn der Sache bei der 
Verwendung einer (und sei es auch nur Möchtegern-) Hochsprache ist oder 
sein kann...

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

c-hater schrieb:
> Wobei ich sowieso davon ausgehe, daß du (wie die meisten) von C sowieso
> nicht mehr begriffen hast, als nötig ist, um den geklauten Code anderer
> Leute zum Laufen zu bringen und irgendwie zusammenzuleimen...

Starke Worte, die mich aber nur ein Lächeln kosten...

von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Hallo Michael,

ich habe aus Anlass Deiner Frage meine C-source einer FFT mit integern 
mal rausgesucht und angehängt. Der Code arbeitet mit int16_t 
Eingangsdaten und deckt FFTs der Länge 2^5=32 bis 2^10=1024 ab. Die 
Routine macht 'autoscaling': Sie merkt, wenn der 16Bit Zahlenbereich 
droht überzulaufen und skaliert dann entsprechend, die resultierende 
Skalierung wird rapportiert.

Dieser Code funktioniert, der steckt in vielen laufenden Geräten, ich 
hab aber die Geschwindigkeit vergessen, liegt im ms-Bereich. Ich habe 
die Source aus einem C-Projekt rausgeschnitten, kann sein, das ich was 
vergessen habe, ich habs' auch nicht auf Übersetzbarkeit getestet.

Gern gebe ich auch mehr Unterstützung, der Code ist mir ans Herz 
gewachsen, die Variablennamen habe ich als jugendlicer Programmierer vor 
vielen, vielen Jahren vergeben.

Cheers
Detlef

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Danke, werd ich mir auf jeden Fall zu Gemüte führen!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Erfolg! Meine FFT läuft!

ich bin mal grundsätzlich extrem begeistert von dem Ding, auch von der 
Genauigkeit. Ich speise das Ding mit meinem Funktionsgenerator, und 
anhand der Amplituden der jeweils benachbarten Bänder kann man die 
Mittenfrequenz ziemlich genau einstellen, indem man solange verstellt 
bis die Amplitude der Seitenbänder identisch sind. Und die 
empfindlichkeit liegt bei 6 kHz immer noch bei 1-2 Hz!

Aber - ich habe "leichte" Verständnisprobleme mit der Interpretation des 
Ergebnisvektors, vor allem des ersten Wertes.

Am leichtesten erkläre ich das mal an einem Beispiel:

Ich sample mit 14.423kHz (die krumme zahl ergibt sich aus 12 MHz, 
Prescaler 64 und 13 Cycles im free-running mode des ATmega)

meine FFT hat 64 Slots, das Ergebnis theoretisch auch, wobei die oberen 
32 uninteressant sind (spiegelung der unteren 32)

Ich würde also Frequenzbänder im Abstand 14423/64 = 225 Hz erwarten.

Die sehe ich auch, aber genau um einen Slot nach oben verschoben:

Wenn ich genau 225 Hz einspeise, habe ich ein maximum im Slot 1, Slot 0 
"zappelt", Slot 2 zeigt grob die Hälfte von Slot 1, alle weiteren sind 
auf 0, also ander geschrieben:
x - 40 - 20 - 0 - 0 (x steht fürs zappeln)

Wenn ich genau 450 Hz einspeise, erhalte ich 0 - 20 - 40 - 20 - 0

675 Hz: 0 - 0 - 20 - 40 - 20 - 0

das höchste Band 32 (also [31] wegen start 0) hat das maximum bei 6975 
Hz, erwarten täte ich 7200 Hz

irgendwie ist das alles um eins nach rechts verschoben... ich habe auch 
"meine" FFT mit der Originalversion vom Elm Chan verglichen, die zeigt 
das exakt gleiche Ergebnis.

Erwarte ich falsch, und das passt eh alles, oder ist hier ein Wurm 
drinnen?

das Zappeln des untersten Bandes könnte ich mir noch durch das Windowing 
erklären...

Kann mich jemand bei der Denkfehleranalyse unterstützen?

von Enrico K. (ekoeck)


Lesenswert?

Das unterste Band ist Null Herz (Gleichanteil), nicht vergessen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Enrico Koeck schrieb:
> Das unterste Band ist Null Herz (Gleichanteil), nicht vergessen.

Hmmm, sowas hatte ich schon vermutet... aber die Bänder haben ja immer 
eine "breite", geht dann das unterste Band von 0 Hz bis ???

Irgendow hatte ich heute eine Seite an der Hand, da wurde erklärt, dass 
alle Bänder bis auf das erste und letzte eine bestimmte breite haben, 
nur eben das erste und letzte eine andere... ich find das nicht mehr.

von Enrico K. (ekoeck)


Lesenswert?

Na das Nullte müsste dann von -225Hz - +225Hz gehen, wenn ich mich nicht 
täusche. Und doppelte Höhe wie in echt haben (weil reell). Zumindest der 
Gleichanteil.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Ha! ich glaub ich habs... Gleichanteil dürfte ja eigentlich keiner 
drinnen sein, außer wenn die Frequenz zu tief ist sodass keine komplette 
Schwingung mehr Platz hat.

Aber - durch das Windowing wird eine Verschobene Sinus-Schwingung (also 
eine die grad nicht bei 0 beginnt) vorne und hinten bedämpft, damit 
ergibt sich ein Gleichanteil, er auch mit der phase der Sinus-Schwingung 
mitgeht. Das erklärt genau das "Zappeln" des untersten Bandes...

=> unterstes band ignorieren, und gut ist.

Danke!

von Enrico K. (ekoeck)


Lesenswert?

Genau. Zu bedenken ist aber auch, dass dir eventuell tiefe Frequenzen 
durch die Lappen gehen können, was ja besonders bei einer Lichorgel auch 
zu unerwünschten ergebnissen führen könnte (flackert nicht zum Bass 
mit).

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.