Forum: Digitale Signalverarbeitung / DSP / Machine Learning FFT Verständnisfrage


von Chris (christophe_d)


Lesenswert?

Hi,

ich verwende momentan einen STM32F4 um über einen externen DAC 
Audiosignale auszugeben. Das funktioniert problemlos und wie gewünscht.

Nach dem ich diese Hard- und Firmware nun schon mal habe, wollte ich mit 
dem ganzen auch noch ein wenig spielen um selber ein wenig damit zu 
lernen. Sprich ich stelle mir vor, dieses Audiosignal vor der Ausgabe 
mit einer Art Klangregler anzupassen (d.h. Höhen, Mitten und Tiefen 
verändern).

So wie ich das sehe, geht das mit einer FFT-Library wie z.B. der von 
https://stm32f4-discovery.net/2015/07/hal-library-14-fast-fourier-transform-for-stm32fxxx/

Diese Library erzeugt mir aus jeweils einem Teil des Audiosignals ein 
Array, welches die in dem Signal enthaltenen Frequenzen und deren 
Amplitude beschreibt. So wie ich das verstehe, müsste ich dieses Array 
jetzt entsprechend meiner Wünsche anpassen, also die Amplituden der 
unteren/mittleren/oberen Frequenzen anheben/absenken.

Allerdings: wie geht es dann weiter? Wie wandele ich dieses Array wieder 
in ein Audiosignal um?

Oder bin ich hier grundsätzlich auf dem Holzweg und so ein 
Digitalklangregler ist vollkommen anders zu implementieren?

: Verschoben durch Admin
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Chris schrieb:
> Allerdings: wie geht es dann weiter? Wie wandele ich dieses Array wieder
> in ein Audiosignal um?
Mittels einer inversen FFT?

> Oder bin ich hier grundsätzlich auf dem Holzweg und so ein
> Digitalklangregler ist vollkommen anders zu implementieren?

Naja, ist nicht ganz ausgeschlossen, dass das mit FFT hin und zurueck 
irgendwie funktionieren kann, aber mit ein paar Filtern statt der 
zweifachen Transformiererei wirds sicher mit weniger Rechenbumms gehen.

Gruss
WK

von Franko P. (sgssn)


Lesenswert?

In der Regel arbeiten die FFT-Routinen mit komplexen Zahlen. Rückwärts 
geht das nur, wenn du Zugang zum komplexen Ergebnis hast. Wenn das schon 
in rein reelle Werte umgerechnet ist, dann funzt die iFFT nicht.

Gruß

von Christoph M. (mchris)


Lesenswert?

>Oder bin ich hier grundsätzlich auf dem Holzweg und so ein
>Digitalklangregler ist vollkommen anders zu implementieren?

Holzweg .. eher ja.
Einen Klangregler macht man eher über eine Filterbank.
Such mal im Netz ...

von Andras H. (kyrk)


Lesenswert?

Bei einer FFT Funktion Library kann man meist sagen ob man FFT oder IFFT 
macht. Meist gibt es da einen Parameter worüber man das setzt.

Aber so einen Parameter sehe ich bei dir nicht. Schade.

https://dsp.stackexchange.com/questions/51214/calculate-ifft-using-only-real-forward-fft

An hand davon könntest du es per Hand selber implementieren. Aber ich 
würde an deiner stelle lieber eine andere FFT Lib suchen.




#include <math.h>
#include "fft.h"
#include "c_fft.h"

#define SWAP(a,b)tempr=(a);(a)=(b);(b)=tempr

float PI = 3.14159265354;

static void DanielsonLanzcosRoutine(FftInputType *data, unsigned long 
cnt, int isign);
static void BitReversal(FftInputType *data, unsigned long cnt);

void FFT (FftInputType *data, unsigned long cnt) {
    //the complex array is real + complex so the array
    //as a size n = 2 * number of complex samples
    //real part is the data[index] and
    //the complex part is the data[index+1]
  BitReversal(data, cnt);
  DanielsonLanzcosRoutine(data, cnt, 1);
}

void IFFT (FftInputType *data, unsigned long cnt) {
    unsigned long i = 0;
    unsigned long n = cnt;
  BitReversal(data, cnt);
  DanielsonLanzcosRoutine(data, cnt, -1);
  for (i = 0; i < n / 2; i++) {
    data[i * 2] /= (n / 2);
  }
}

void calculateMagnitueAndPhaseFromComplex(FftInputType *data, unsigned 
long cnt) {
  unsigned long x = 0;
  float ampl = 0.0;
  float fiPI = 0.0;
  float fiC = 0.0;
  for (x = 0; x < cnt; x += 2) {
    ampl = sqrt((pow((float)data[x], 2)) + (pow((float)data[x + 1], 
2)));
    fiPI = tan((float)data[x + 1] / (float)data[x]);
    fiC = (180.0 * fiPI / (2.0 * PI));
    if ((ampl < 0.0001) && (ampl > -0.0001)) {
      fiC = 0.0;
    }
    while (fiC > 360.0) {
      fiC -= 360.0;
    }
    while (fiC < -360.0) {
      fiC += 360.0;
    }
    data[x] = (FftInputType)ampl;
    data[x + 1] = (FftInputType)fiC ;
  }
}


static void BitReversal(FftInputType *data, unsigned long cnt) {
    //binary inversion (note that the indexes
    //start from 0 witch means that the
    //real part of the complex is on the even-indexes
    //and the complex part is on the odd-indexes
    unsigned long i = 0;
    unsigned long j = 0;
    unsigned long n = cnt;
  double tempr = 0;
    for (i = 0; i < n / 2; i += 2) {
    unsigned long m = 0;
        if (j > i) {
            //swap the real part
            SWAP(data[j], data[i]);
            //swap the complex part
            SWAP(data[j + 1], data[i + 1]);
            // checks if the changes occurs in the first half
            // and use the mirrored effect on the second half
            if ((j / 2) < (n / 4)) {
                //swap the real part
                SWAP(data[(n - (i + 2))] , data[(n - (j + 2))]);
                //swap the complex part
                SWAP(data[(n - (i + 2)) + 1] , data[(n - (j + 2)) + 1]);
            }
        }
        m = n / 2;
        while (m >= 2 && j >= m) {
            j -= m;
            m = m / 2;
        }
        j += m;
    }
}

static void DanielsonLanzcosRoutine(FftInputType *data, unsigned long 
cnt, int isign) {
  unsigned long n = cnt;
    unsigned long mmax = 0;
    //Danielson-Lanzcos routine
    mmax = 2;
    //external loop
    while (n > mmax) {
    double wtemp = 0;
    double theta = 0;
    double wi = 0;
    double wpi = 0;
    double wr = 0;
    double wpr = 0;
    unsigned long m = 0;
    unsigned long istep = 0;
    istep = mmax <<  1;
        theta = isign * (2 * PI / mmax);
        wtemp = sin(0.5 * theta);
        wpr = -2.0  wtemp  wtemp;
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        //internal loops
        for (m = 1; m < mmax; m += 2) {
      unsigned long i = 0;
      unsigned long j = 0;
            for (i = m; i <= n; i += istep) {
        double tempi = 0;
        double tempr = 0;
        j = i + mmax;
                tempr = wr * (float)data[j - 1] - wi * (float)data[j + 1 
- 1];
                tempi = wr * (float)data[j + 1 - 1] + wi * (float)data[j 
- 1];
                data[j - 1] = (float)data[i - 1] - tempr;
                data[j + 1 - 1] = (float)data[i + 1 - 1] - tempi;
                data[i - 1] += tempr;
                data[i + 1 - 1] += tempi;
            }
            wr = (wtemp = wr)  wpr - wi  wpi + wr;
            wi = wi * wpr + wtemp * wpi + wi;
        }
        mmax = istep;
    }
}

von Mann Fred (Gast)


Lesenswert?

Franko P. schrieb:
> In der Regel arbeiten die FFT-Routinen mit komplexen Zahlen. Rückwärts
> geht das nur, wenn du Zugang zum komplexen Ergebnis hast.

In der Mechanik zerlegen wir die Schwingungen in einem System auch 
mittels FFT und verwenden bei der Wiedersynthese nur die Beträge. Der 
Unterschied ist, dass die Phasen, die ursprünglich im System waren, 
verloren gehen. Wir erzeugen eigene Phasen, um das System zu steuern.

Der herauskommende Signal ist dann anders. Aber:

Da beim Audio die Phasen egal sind, weil man sie nicht hören kann, 
müsste das eigentlich auch egal sein, oder?

von Rolf (rolf22)


Lesenswert?

Mannfred T. schrieb:
> Da beim Audio die Phasen egal sind, weil man sie nicht hören kann

Na, zumindest bei Musik sind sie nicht so ganz egal. Stöpsel mal einen 
deiner Stereolautsprecher um und horche, ob du dann was anderes hörst. 
;-)

von Mann Fred (Gast)


Lesenswert?

Das ist aber etwas gänzlich anderes, weil L und R andere Signale 
bekommen.

Die Frage ist doch die:

Klingen 50% Sinus (100 Hz * wt) + 50% Sinus (150 Hz * wt) genau so wie
50% Sinus (100 Hz * wt) + 50% Sinus (150 Hz * wt - alpha)

Da die beiden Frequenzen schweben, bilden sich ohnehin alle 
Konstellationen irgendwann einmal - nur zu anderen Zeitpunkten, als im 
anderen Fall.

von Peter G. (ham)


Lesenswert?

Hallo

nicht so ganz zu deiner formulierten Frage (oder doch?), aber bezüglich 
der Überschrift bzw. des Betreffs dann doch passend (und sei es nur für 
die Mitleser, die wieder besseren Erfahrungen auf eine endliche 
verständliche Erklärung gehofft haben...) ;-)

FFT an sich - wie sie im technischen Zusammenhang entsteht, gebraucht 
und angewandt wird, ist eigentlich gar nicht so schwer und wird in 
einigen Videos (und seltener sogar in Texten) eigentlich recht 
verständlich erklärt.

z.B. hier im ersten Teil, der noch ohne Mathematik auskommt:

https://www.youtube.com/watch?v=spUNpyF58BY


Leider ist aber genau die Mathematik dahinter, dann doch sehr komplex 
;-), fern vom Alltagsverständnis und irgendwie schafft es kein Video und 
auch kein an (relativen) Laien und Hobbyisten wie mir gedachte Text das 
wirklich so zu erklären, dass man es als interessierter Laie auch 
mathematisch wirklich nachvollziehen kann und für seine Anwendungen 
selbst  (ohne "magische" fertige Online - Programmanwendungen wo man 
"nur" die entsprechenden Zahlen für ein ganz bestimmtes Problem eingeben 
braucht) berechnen kann, bzw. einen klar ist, was man (und wie) dann 
überhaupt aus den High End Mathe "Baukasten" gebraucht.

Obwohl das Wort "komplex" in der Mathematik sicherlich genau genommen 
wenig mit dem Begriff wie er im Alltag genutzt (gemeint) wird zu tun 
hat, so passt das "komplex" aus dem Alltag mit dem Sinn "Verwirrend", 
"verzwickt", "unverständlich" usw. schon ganz gut zusammen...

Dergute W. schrieb:
> Mittels einer inversen FFT?

Das hört sich nach eine schwer verständliches Konzept noch mal eine 
"Schippe" verwirrender zu machen... (?)

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Bei einem reellen Signal f(t) (ohne irgendwelche Symmetrien) hast Du ein 
konjugiert-komplexes Specktrum: F*(jw) = F(-jw), also Betrag ist eine 
gerade Funktion und die Phase ungerade, oder Realteil ist gerade und 
Imaginärteil ist ungerade.
Wenn Du nun im Bildbereich filterst, in dem Du mit einer reellen 
Filterfunktion multiplizierst, bleibt das resultierende Specktrum 
konj-komplex und damit ist die Rücktransformierte wieder reell.

von Gunnar F. (gufi36)


Lesenswert?

Manni T. schrieb:
> Da beim Audio die Phasen egal sind, weil man sie nicht hören kann,
> müsste das eigentlich auch egal sein, oder?

Nein, die Phase ist essentiell. Zerleg mal einen Sägezahn in Frequenzen, 
setz die Phasen auf Null und gib sie wieder aus. Da kommt eine komplett 
andere Funktion raus.

von Max H. (nilsp)


Lesenswert?

Chris schrieb:
> Hi,

Hi!

> Nach dem ich diese Hard- und Firmware nun schon mal habe, wollte ich mit
> dem ganzen auch noch ein wenig spielen um selber ein wenig damit zu
> lernen. Sprich ich stelle mir vor, dieses Audiosignal vor der Ausgabe
> mit einer Art Klangregler anzupassen (d.h. Höhen, Mitten und Tiefen
> verändern).

Ich habe ein wenig den Eindruck, das Dir ein paar Grundlagen in der 
Signalbearbeitung fehlen. Das ist kein Problem, jeder fängt mal an. Aber 
ich würde nicht gleich mit FFT basierten Algorithmen anfangen.

Da es erst mal um das Rumprobieren geht, empfehle ich Dir, das Filtern 
über Biquad Filter zu realisieren. Der mathematische Unterbau davon ist 
zwar auch nicht ohne, aber es ist viel einfacher erst einmal die Formeln 
oder fertige Algorithmen zu nehmen und einen Filtereffekt zu erzeugen.

Wenn Du mit FFT einsteigst: Auch das ist möglich, allerdings wirst Du 
Dich zwingend mit so lustigen Dingen wie komplexen Zahlen, Fenster 
Funktionen, Overlap-and-add Verfahren, negativen Frequenzen usw 
auseinandersetzen müssen.

Ich halte den Lerneffekt, das mit einer FFT mal durchzuziehen für enorm, 
aber so als erster Versuch, um mit seiner DAC/ADC Schleife auf dem 
Microcontroller zu spielen, ist es nicht geeignet.

Fang daher mal besser mit High- und Lowpass Filtern zweiter Ordnung - 
implementiert als Biquads an. Das ist für den Anfang schon 
herausfordernd genug.

von Gerhard Z. (germel)


Lesenswert?

Und zum Lernen der Grundlagen gibt es gute Hilfe:
https://www.dspguide.com
Du kannst das Buch (bzw. alle Kapitel daraus) als PDF runter laden.

von Markus M. (adrock)


Lesenswert?

Nur eine Kurze Anmerkung: Grundsätzlich muss das mit der inverse-fft 
funktionieren (wenn auch vlt. nicht in Echtzeit).

Es gibt prof. Audio-Software, die einem auf der Y-Achse statt der 
Amplitude quasi das Ergebnis der FFT darstellt (Y-Achse = 
Frequenzbänder, Farbe der Pixel analog zur Amplitude des Frequenzbandes 
in der FFT).

Der Clou ist, man kann dann in dieser Grafik fröhlich editieren und 
somit gezielt Frequenzen eliminieren.

von Dergute W. (derguteweka)


Lesenswert?

Peter G. schrieb:
> Dergute W. schrieb:
>> Mittels einer inversen FFT?
>
> Das hört sich nach eine schwer verständliches Konzept noch mal eine
> "Schippe" verwirrender zu machen... (?)
Aeeeh - neee. Die FFT und iFFT sind sich nicht so ganz unaehnlich, was 
die Rechnerei angeht.
Das Konzept: FFT, am Ergebnis rumdoktoren, iFFT wird schon verwendet. 
Ich wuerd's halt nur nicht fuer eine Klangregelung hernehmen.


Gunnar F. schrieb:
> Zerleg mal einen Sägezahn in Frequenzen,
> setz die Phasen auf Null und gib sie wieder aus. Da kommt eine komplett
> andere Funktion raus.
Das ist unbestritten. Die Frage ist eher: Hoert die sich vielleicht 
nicht genauso an, wie der original Saegezahn?
Problematisch werden dann evtl. Begrenzungseffekte, weil bei 
unguenstiger Phasenlage der Oberwellen kurze, aber hohe Momentanwerte im 
Signal auftauchen koennen. Die muss dann der Verstaerker und 
Lautsprecher erstmal verzerrungsfrei rueberbringen (Und die Cochlea 
verdauuen).

Gruss
WK

von C-hater (c-hater)


Lesenswert?

Dergute W. schrieb:

> Aeeeh - neee. Die FFT und iFFT sind sich nicht so ganz unaehnlich, was
> die Rechnerei angeht.

So isses. Das ist dieselbe Soße mit einem minimalen Unterschied, der 
allerdings so gut wie keinen Einfluß auf die benötigte Rechenleistung 
hat.

> Das Konzept: FFT, am Ergebnis rumdoktoren, iFFT wird schon verwendet.

Und funktioniert tatsächlich auch.

> Ich wuerd's halt nur nicht fuer eine Klangregelung hernehmen.

Ganz genau. Das ist völlig am Thema vorbei. Das ist die Lösung der 
Doofen, die nur Wichsvorlagen zusammen bauen können und ihre Unfähigkeit 
notfalls mit brachialer Rechenleistung erschlagen...

von Mann Fred (Gast)


Lesenswert?

Gunnar F. schrieb:
> Nein, die Phase ist essentiell. Zerleg mal einen Sägezahn in Frequenzen,
> setz die Phasen auf Null und gib sie wieder aus. Da kommt eine komplett
> andere Funktion raus.

Sicher. Aber hört das Ohr auch etwas anderes? Die Sinneshaare werden 
trotzdem genau so angeregt. Die Wellen sind nur gegeneinander 
zeitversetzt.

von Max H. (nilsp)


Lesenswert?

Manni T. schrieb:
> Sicher. Aber hört das Ohr auch etwas anderes? Die Sinneshaare werden
> trotzdem genau so angeregt. Die Wellen sind nur gegeneinander
> zeitversetzt.

Jein, bei einem konstanten Ton, in moderat gespielter Lautstärke, hört 
man in der Tat keinen Unterschied. (Wobei: Das kommt wieder auf den 
Hörer an. Ich kenne Leute, die den Unterschied zwischen einem steigenden 
und fallenden Sägezahn reproduzierbar wahrnehmen können).

Sobald die Lautstärke aber ansteigt, und nicht lineare Effekte in useren 
Ohren zum Tragen kommen, wird eine Phasenverschiebung hörbar. 
Insbesondere passiert das in den Transienten.

Und noch was, da wir ja über FFT sprechen: Es kommt doch sehr selten 
vor, das man eine FFT über ein gesammtes Musikstück macht. Dort kann man 
unter Umständen ohne Phaseninformationen auskommen.

In der Praxis macht man die FFT für fast jede Bearbeitung über kleine 
Teilstücke, bearbeitet dann in der Frequenzebene und wandelt zurück.

Verzichtet man hier auf die Phase, so passen die einzenden Blöcke nicht 
mehr sauber zusammen, und man hört die fehlende bzw. falsche Phase als 
Störsignal.

von J. S. (engineer) Benutzerseite


Lesenswert?

Max H. schrieb:
> Ich kenne Leute, die den Unterschied zwischen einem steigenden
> und fallenden Sägezahn reproduzierbar wahrnehmen können

Manche Audiophile können wirklich Erstaunliches wahrnehmen. Soweit das 
der Fall ist, liegt das aber hauptsächlich an der Übertragung durch die 
Signalkette und die Lautsprecher. Du bekommst ja keinen perfekten 
Sägezahn in die Luft, sondern einen gedämpften Anstieg und weiters die 
durch die geschluckten Anteile des Signals angeregten Schwingungen der 
Membran. Das ist schon "ab Lautsprecher" etwas anderes, weil das Signal 
nicht völlig DC liegt und durch die nicht phasenneutrale Signalkette 
deformiert wird - d.h. die Höhen werden in der Phase stärker verschoben, 
als die tiefen Anteile und je nach Lage und Anstieg des Signals kommt da 
dann etwas leicht anderes heraus. Das ist das klassische Verhalten 
solcher analoger Pfade mit ihrem nicht stabilen DC-Verhalten.

Bei einem voll symmetrischen, um Null schwingenden Sägezahn auf hohen 
Frequenzen spielt das kaum eine Rolle und dann ist das Signal auch 
gleich dem anderen: Ein idealer Sägezahn, der in X gespiegelt ist, ist 
nämlich ganz exakt dasselbe wie ein in Y gespiegelter, also z.B. wie bei 
einem verpolten Lautsprecher. Soweit man ab da noch Unterschiede hört, 
liegt das definitiv am Lautsprecher, der in die Zugrichtung etwas anders 
strahlt, als in die Druckrichtung.

von J. S. (engineer) Benutzerseite


Lesenswert?

Max H. schrieb:
> bei einem konstanten Ton

Das ist der Punkt. Der Ton ist ja nicht konstant und in den Fällen, in 
denen die Amplituden und Frequenzen es sind, kommt auch nicht 
zwangsläufig dasselbe heraus.

Grundsätzlich bildet sich zwar in der Tat jede Form der 
Amplitudenkonstellation, wenn der Ton schwebt, das tut aber nicht jedes 
Signalkonvolut. Wenn die Frequenzen strikt ganzzahlig passen, ändert 
sich die Signalform nicht. Die ist statisch und fest durch die Phasen 
definiert. Nehmen wir den klassischen Fall der 1. und 3. Oberwelle mit 
jeweils +/-90° Versatz: Im Fall 1 näher sich das Signal einem Dreieck, 
im anderen Fall einem Rechteck.

Noch komplizierter wird es bei 3 oder mehr Frequenzen.

Die FFT und iFFT hat aber noch ein anderes Problem: Selbst ausgedehnte 
FFT über mehrere Perioden des tiefstfrequentesten Signals brauchen eine 
Fensterung und haben folglich Artefakte. Bei der Resynthese schlagen 
diese dann als falsche Frequenzanteile zu. D.h. z.B. spiegelt sich eine 
Frequenz von 200Hz bei einem Blackman-Harris mit Cos2 auch ein wenig in 
die 400Hz hinein.

von A. F. (chefdesigner)


Lesenswert?

Dergute W. schrieb:
> Ich wuerd's halt nur nicht fuer eine Klangregelung hernehmen.

Aus dem Gitarrenforum hört man dass Faltungsoperationen so arbeiten. 
Besonders Faltungshall in den Effektgeräten und Mischpulten. Sicher 
macht auch der Kemper so Sachen.

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.