Für ein Projekt muss ich ein Spektrogramm aus einer .WAV-Datei erzeugen können. Ich habe folgendes gelesen, sollte erledigt sein:
Auf dem Bild unten sehen Sie zwei Spektrogramme einer 10000 Hz Sinuswelle, die beide die hanning Fensterfunktion. Auf der linken Seite sehen Sie ein Spektrogramm von audacity und rechts meine Version. Wie du sehen kannst, hat meine Version viel mehr Zeilen / Rauschen. Ist dieses Leck in verschiedenen Behältern? Wie würde ich ein klares Bild bekommen, wie es die Kühnheit erzeugt? Sollte ich etwas nachbearbeiten? Ich habe noch keine Normalisierung vorgenommen, weil ich nicht ganz verstehe, wie das geht.
update
Ich fand dieses Tutorial, das erklärt, wie man generiert ein Spektrogramm in C ++. Ich habe die Quelle kompiliert, um zu sehen, welche Unterschiede ich finden könnte.
Meine Mathematik ist sehr rostig, um ehrlich zu sein, also bin ich mir nicht sicher, was die Normalisierung hier macht:
%Vor%nachdem ich das gemacht habe, habe ich dieses Bild (übrigens habe ich die Farben invertiert):
Ich habe mir dann den Unterschied zwischen den Eingangs-Samples meiner Sound-Library und der des Tutorials angesehen. Meine waren viel höher, also normalisierte ich manuell, indem ich sie durch den Faktor 32767.9 dividiere. Ich gehe dann dieses Bild, das ziemlich gut aussieht, denke ich. Aber es ist falsch, sie durch diese Zahl zu teilen. Und ich würde gerne eine andere Lösung sehen.
Hier ist der vollständige relevante Quellcode.
%Vor%Das ist nicht genau eine Antwort, was falsch ist, sondern eher eine Schritt-für-Schritt-Prozedur, um dies zu debuggen.
Was glaubst du, was diese Linie ausmacht? processed[i] = out[i][0]*out[i][0] + out[i][12]*out[i][13]
Wahrscheinlich ist das falsch: fftw_complex ist typedef double fftw_complex[2]
, also haben Sie nur out[i][0]
und out[i][1]
, wobei der erste der reale und der zweite der imaginäre Teil des Ergebnisses für diesen Bin ist. Wenn das Array zusammenhängend im Speicher ist (was es ist), dann ist out[i][12]
wahrscheinlich dasselbe wie out[i+6][0]
und so weiter. Einige dieser werden über das Ende des Arrays hinausgehen und zufällige Werte hinzufügen.
Stimmt Ihre Fensterfunktion? Drucke windowHanning (i, transform_size) für jedes i aus und vergleiche mit einer Referenzversion (zum Beispiel numpy.hanning oder Matlab-Äquivalent). Dies ist die wahrscheinlichste Ursache, was Sie sehen, sieht wie eine schlechte Fensterfunktion aus, Art.
Ausdruck wird verarbeitet und mit einer Referenzversion verglichen (bei der gleichen Eingabe müssten Sie natürlich die Eingabe drucken und neu formatieren, um sie in pylab / matlab usw. einzufügen). Allerdings sind die -60 und 1e-6 Fudge-Faktoren, die Sie nicht wollen, der gleiche Effekt wird besser auf eine andere Weise getan. Berechnen Sie so:
%Vor% Gibt die Werte von power_in_db[i]
für dasselbe i aus, aber für alle x (eine horizontale Linie). Sind sie ungefähr gleich?
Wenn alles bisher gut ist, setzt der verbleibende Verdächtige die Pixelwerte. Seien Sie sehr explizit beim Clipping für Bereich, Skalierung und Rundung.
%Vor%Auch hier drucken Sie die Werte in einer horizontalen Linie aus und vergleichen Sie sie mit den Graustufenwerten in Ihrem pgm (von Hand mit dem Colorpicker in Photoshop oder Gimp o.ä.).
An diesem Punkt haben Sie alles von Anfang bis Ende validiert und wahrscheinlich den Fehler gefunden.
Der von Ihnen erstellte Code war fast korrekt. Du hast mich also nicht viel korrigiert:
%Vor%Die beiden korrigierten Fehler waren höchstwahrscheinlich für die geringe Variation der aufeinanderfolgenden Transformationsergebnisse verantwortlich. Das Hanning-Fenster ist sehr geeignet, um das "Rauschen" zu minimieren, so dass ein anderes Fenster das Problem nicht gelöst hätte (eigentlich @Alex habe ich bereits auf den 2. Bug in Punkt 2 hingewiesen. Aber in Punkt 3. hat er eine -Inf -bug as log (0) ist nicht definiert, was passieren kann, wenn Ihre Wave-Datei eine Strecke von exakten 0-Werten enthält. Um dies zu vermeiden, ist die Konstante 1e-6 gut genug.
Nicht gefragt, aber es gibt einige Optimierungen:
Setzen Sie p = fftw_plan_dft_r2c_1d(transform_size, in, out, FFTW_ESTIMATE);
außerhalb der Hauptschleife,
Berechnen Sie die Fensterfunktion außerhalb der Hauptschleife,
Verlasse das Array processed
und verwende einfach eine temporäre Variable, um jeweils eine Spektrallinie zu halten,
Die beiden Multiplikationen von out[i][0]
und out[i][1]
können zugunsten einer Multiplikation mit einer Konstanten in der folgenden Zeile aufgegeben werden. Ich habe das (und andere Dinge) für dich gelassen, um dich zu verbessern
Dank @Maxime Coorevits konnte zusätzlich ein Speicherleck vermieden werden: "Bei jedem Aufruf von% co_de wird% Speicher von FFTW3 zugewiesen. In Ihrem Code rufen Sie fftw_plan_dft_rc2_1d()
nur außerhalb der äußeren Schleife auf Tatsächlich müssen Sie dies jedes Mal aufrufen, wenn Sie einen Plan anfordern. "
Tags und Links c++ fft fftw spectrogram