Hi, Ich glaube hier bin ich doch gut aufgehoben mit meinem Problem :) Nun ich habe mal vor längerer Zeit eine FFT in C++ programmiert als ich dabei war die FFT zu "begreifen". Diese funktioniert schlussendlich auch wie sie das tun sollte und ich habe auch was dazugelernt :) Gut das zum 1. Schritt, jetzt möchte ich nach längerer Zeit wieder mal was DSP mäsiges machen und habe die Idee einen Low-Pass filter zu schreiben. Was ich bisher dazu gemacht hatte ist: 1. Das reelle Signal (ein meinem Fall eine Audio Datei) laden und dabei von 32bit int zu double konvertieren. 2. Das Signal in x Stücke aufteilen > (file-länge-in-samples / 1024). Wobei meine FFT 2048 Samples groß ist. Also somit immer die hälfte der FFT füllen. Da Signal halt nur reell > nur in RE. IM Werte bleiben auf 0. 3. Komplexe FFT durchführen. 4. Konvertiere aus den Arrays RE und IM in Polarform. Resultat dann in Arrays Ampl und Phase. Lösche RE und IM > buffer clear. Dann mittels Schleife von 0 bis max. gewünschter Freq. von Polar wieder zurück in RE und IM. Negative Frequenzen werden mit einbezogen. Alle Frequenzen oberhalb von MaxFreq sind nun auf 0 und somit weg. Die Frequenzen wurden vorher von Hz zu Array-Index berechnet, also auf die FFT länge berechnet mittels Index = (Frequenz / (maxFreq/fftsize)) maxFreq = 44100 in meinem Fall / fftsize halt wie oben gesagt 2048. Ok, dann zum 5 Schritt, Komplexe IFFT > 1024 Samples aus RE > zu 32Bit int > in andere Datei sequenziell speichern. Wieder zu Punkt 1, solange bis alle Parts abgearbeitet wurden. Was passiert wenn ich die Datei nun lade und abspiele ist, das leakages entstehen im Frequenz-Spektrum. Das hört sich an wie ein "Zappen" und hängt immer oberhalb der max. Freq die noch vorhanden ist nach dem Filtern. Im Zeitbereich sind das einfach nur heftige Sprünge zwichen jeden Frames die bearbeitet wurden, halt jede 1024 Samples springt er steil nach oben oder unten = also Signal ist zerhackt. Meine Frage, warum passiert das mit dem "zerhacken" warum ist das Signal nicht weich in den Übergängen? Ich habe auch schon versucht, die anderen restlichten 1024 Samples zu "überlappen", also overlap-add Prinzip, kann man aber vergessen bringt nix, Problem besteht weiterhin. Ist das Low-Passen so Schwer? Hab aber auch nix Sinnvolles im Netz gefunden, da ich einerseits nicht die Fachbegriffe für mein exaktes Problem finden kann. Das Overlapp Add ist mir klar, wird zur fast convolution per DFTs verwendet. Meine Anwendung macht ja das gleiche, halt lowpassen per FFT Faltung, nur das ich keinen direkten Kernel (als file oder so) habe mit dem ich dann im Freq-Bereich multiplizieren würde, sondern halt nur die Frequenzen grob auf null setze = Rectangular Frequenz Filtern was ja in einem Sync (Zeit bereich) resulierten müsste!? Anyway, viellecht weis ja jemand um Rat oder einen Tip wie man das mit kleinen fft-lowpassen gescheit macht. Hab halt nur die Möglichkeit ne FFT zu wählen, die größer ist als die Datei (von den Samples her) und dann an einem Stück zu low-passen. Macht aber keinen Sinn bei files > kritische Grenze Gigabytes :S Ne will das schon gescheit machen mit kleinen FFTs. Lieber frage ich hier bevor ich noch 100 Jahre nach ner Lösung suche ... Habe ein Screennshot angehängt wo man das Problem gut sehen kann. Ich bedanke mich für Hilfe und Durchlesen :) Gruß, zerall :D
> 1. Schritt, jetzt möchte ich nach längerer Zeit wieder mal was DSP
mäsiges machen und habe die Idee einen Low-Pass filter zu schreiben.
Soweas macht man mit einem IIR- oder FIR-filter.
Das Ganze mittels kurzer Sequenzen über FFT-Filterung zu berechnen ist
unsinnig. Wollest du nur wissen welche Schlechtigkeiten mit einer
unpassenden Methode auftreten?
Das ist eben das Problem der FFT. Sie ist nicht wirklich amplitudengenau, damit erreichst Du nur eine ungefähre Rekonstruktion des Originals. Mit welcher Funktion hast Du gefenstert? Probiere mal ein Kaiser7. Zudem musst Du die Übergänge smoothen. Dazu benötigst Du zwei interlaced geschachtelte FFTs und anschliessende iFFTs. Den Übergang / Überblendung zwischen den beiden iFFT-Syntheseausgängen bildest Du mit einem Integral-S oder einer Sinusfunktion. Damit entfallen die unstetigen Übergänge und Du bekommst wieder eine halbwegs echte Rekonstruktion. Bei Formant-freien Audio-Sample Synthesen, wird das so gemacht.
Hi, Erstmal Danke für die Antworten! > Soweas macht man mit einem IIR- oder FIR-filter. Hatte ich auch schon versucht, war leider zu langsam (auf der höchsten Compiler Stufe mit sse2 usw). >Wollest du nur wissen welche Schlechtigkeiten mit einer unpassenden Methode auftreten? So weit bin ich noch nicht in die Materie vorgestoßen um das entscheiden zu können :) > Mit welcher Funktion hast Du gefenstert? Wenn ich fenstere (hatte einen Nuttall verwendet) hört sich das Signal Amplituden-Moduliert an, also wobbelig da ja am anfang eingeblendet und am Ende ausgeblendet wird, und somit AMs enstehen + das leakage weiterhin. =( Somit habe ich keine Fenster Funktion momentan drinn. Das mit dem überblenden der Übergänge finde ich jetzt interessant, damit könnte es zumindest "smoother" werden stimmt! Wie müsste ich da überblenden, sprich wenn ich auch eine Fensterfunktion reinhaue, ab welcher Position muss ich quasi überlappen (Addieren), z.B wenn ich jetzt 1024 Samples habe, eine 2048 FFT und ein Low-Pass z.B ab 1500Hz. Wie kann ich zwischen den steilen Veränderungen gescheit interpolieren? Gruß, zerall
> Hatte ich auch schon versucht, war leider zu langsam > (auf der höchsten Compiler Stufe mit sse2 usw). War zu langsam? Das war jetzt ein kleiner Scherz von dir. Also dein PC schafft locker eine 1MHz-Datenrate. Vielleicht machst du ja was mit deinem C++-Programm falsch. Erzeugst du mit jedem Datenwort ein "new"?
Hi, Ich habe damals einen Sync-Filter erzeugt, dazu hab ich ne Funktion verwendet um den Sync so anzupassen, dass er ab einer bestimmen Frequenz cutted + Hann Filter für das smooth-ing des Filters. Den Code für den FIR-Filter habe ich leider nicht mehr, aber ich habe damals vor der Verarbeitung der n * m Durchläufe alles auf den heap allociert. Damals hatte ich auch zuerst die Datei > Samples in den Speicher geladen, so dass auch keine HDD Zugriffe enstehen könnten, zumindest keine unoptimierten. (beim Testen lade ich meist alles in den Speicher) Innerhalb der Schleifen wurde nichts außer der Multiplikationen und Summierung durchgeführt. Damit ich keine Range-Checks durchführen musste in der Schleife, habe ich dieses Problem auch zuvor mit 0-Padding gelöst. Als Datentyp hatte ich nen float verwendet + sse2 option. (Btw: ist das auch irgendwie mit int's vernünftig durchführbar ohne dass ich wegen den Großen Werten Clippe?, vielleicht wäre es ja dann schneller) Compiliert hatte ich das mit Visual Studio 2010 (die Test Version mit allen Optionen freigeschaltet) und trozdem war es leider zu langsam. Der Kernel war auch nicht sehr klein, da ich nur alle Frequenzen von 0-100Hz haben wollte. Aber abgesehen davon hab ich soeben einen Fortschritt gemacht!! Ich habe nun einfach anstatt 1024 Samples in die FFT zu laden etwas mehr, also um genau zu sein 3 * 1024 = 3072 Samples geladen, also den benachbarten Bereich, dann den low-pass durchgeführt, dann halt nur die 1024 S. aus der Mitte dieser 3072 S. rausgelesen. Durch die benachbarten Samples wirkt das Ergebnis nun Smoother, als Window verwende ich immer noch einen Nuttall. Und die Window Funktion kann somit auch seine Wirkung besser erfüllen, da ich ja nicht mehr den vom Ein/Ausblenden betroffenen Bereich verwerte, sondern die Mitte. Puhh, so langsam verstehe ich und begreife mehr, ach ist das Toll :) zerall
Ich verstehe nicht, warum eine FFT schneller sein soll, als ein simples FIR. Beim FIR sind die Frequenzen N,N-1,N-2, ... , 1,0 ja schon zusammengefasst. Und linearer ist es auch noch.
Hi, Ich habe der FIR Sache nochmal eine Chance gegeben, es muss wohl damals am Compiler gelegen haben (oder ähnlichen Problem). Denn ich habe soeben einen 1000 Taps breiten FIR lowpass ziemlich schnell ausgeführt! In 10sec Samples der Länge von 5:00Min. Damit kann ich mich zufrieden geben, dann kann ich somit die FFT aus dem Spiel lassen. Hab die Sache eben schnell from scratch wie damals programmiert, zuerst mit floats dann sogar doubles gerechnet, wobei kein signifikanter Unterschied ensteht im Bezug auf die Berechnungsdauer. Wobei 1000Taps schon übertrieben sind. Als Fenster diesmal ein Hann auf den FIR. Danke für die Motivation!, hat mich nun weitergebracht, auch was die Erfahrung betrifft. Warum es damals langsamer war, ca 1 Min Dauer für Berechnung, kann ich nur auf den Compiler zurückführen. Oder irgendwas hat damals das System verlangsamt. Die Hardware ist die selbe, gleiche cpu, speicher etc, nur Visual Studio 2010 neu drauf. Was ich jetzt mal versuche ist, rein aus Interesse, den FIR auf der GPU (cuda) durchzuführen, also die Multiplikationen. Die Additionen muss dann eben wieder von CPU klar. Ich werde darüber berichten! Problem ist somit gelöst! Danke und Gruß, zerall
Könntest du das posten? Z.B. in der Rubrik CODE-Schnipsel? Mich interessiert nämlich wie das mit dem Lecken aussieht. Wenn Du filterst, ensteht ja wie bei der FFT ein Leck an den Rändern der Begrenzung. Oder ignorierst du das nun einfach?
Hi, Klar kein Problem :), ich poste es mal auf nopaste da es nur ein Stück Code ist, bzw noch im Test-Stadium. Also wenn ich die Convolution mit dem FIR (Sinc+Fensterfunktion) direkt berechne, also mit 2 Schleifen über das Signal, bekomme ich keine harten Sprünge und Leakages mehr im Gegensatz zur FFT Methode, die ich zuvor versucht hatte. Die 2 Schleifen benötigen N mal M Rechenoperationen, wobei N die Filter-Taps und M die Länge des Eingangsignals in Samples. Ich habe das Ganze auch mal auf NVIDIA CUDA geported, also damit kann man die Convolution auf dem Grafikprozessor (GPU) durchführen. Ist auf jeden Fall ein enormer Geschwindigkeits Unterschied im Vergleich zur CPU. Falls jemand sich mit CUDA auseinandersetzt, poste ich den code auch optional dazu. Dabei habe ich das SDK-Sample "vectorAdd" als Vorlage benutzt und verändert. Normale Version: http://nopaste.info/18c44cc0f5.html CUDA Version: http://nopaste.info/1ac57f6349.html Bei Fragen oder Hinweisen, Kritik einfach Antworten, Danke :) Gruß, zerall
Du könntest das Erzeugen der Filterkoeffizienten noch Verbessern, in dem Du eine gerade Zahl von Koeffizienten nimmst, vollständig spiegelsymmetrisch baust, dabei zwei Filterkoeffizienten gleichzeitig schreibst und das Window auch gleich draufmultiplizierst. Technisch etwas verbessern könnte man es mit einem blackman-Window, das für diese App (single-FFT) z.B. eine bessere Sperrdämpfung des Filters generiert. Wenn Du nur einen Tiefpass willst (der headroom zur fs also weiterhin gross ist) böte sich auch ein butterworth(5,7) als Filterform an. Das liefert die bessere Audioqualität.
>Du könntest das Erzeugen der Filterkoeffizienten noch Verbessern, in dem >Du eine gerade Zahl von Koeffizienten nimmst, vollständig >spiegelsymmetrisch baust... Stimmt so spart man sich den halben Prozess, Danke! :) Hier gleich die verbesserte Version: http://nopaste.info/2d1ef2174b.html (Da ich mit den Fenstern noch rumspiele, berechne ich diese noch nachträglich) >Technisch etwas verbessern könnte man es mit einem blackman-Window - bessere >Sperrdämpfung Stimmt, genial Thx! :) (btw, bemerke gerade im Bezug auf Fenster Funktionen, dass die englische wikipedia etwas mehr Informationen als die deutsche wiki zu bieten hat + Spektral-Plots, cool) >Wenn Du nur einen Tiefpass willst (der headroom zur fs also >weiterhin gross ist) böte sich auch ein butterworth(5,7) als Filterform >an. Das liefert die bessere Audioqualität. Muss ich mir mal anschauen, bzw: gibt es da eine gute und einfache Möglichkeit den Butterworth einfach zu generieren? Ich finde gerade nur zu theoretisches Material im Netz.., da ich die z-Tranformation noch lernen muss. Zusatz: Habe soeben die convolution beschleunigen können indem ich wieder die FFT verwende anstatt es direkt zu berechnen. Diesmal habe ich aber den Kernel (den zuvor berechneten Sinc) in den Spektral-Bereich (Amp + Phase) transformiert und anschließend zum Spektrum des Eingangssignals dazugerechnet. Wobei Amplituden multipliziert und Phasen addiert. Nun enstehen keine leakages mehr wie zuvor beim einfachen "auf null setzen" der Frequenzen. Es lag wohl an den Phasen des richtigen Sincs.. :) Code-Ausschnitt: http://nopaste.info/8b096bf65c.html Gruß, zerall
Achtung: Habe einen Fehler in der Filter Funktion korrigiert, ein Wert wurde als int zur sin Berechnung übergeben und hatte somit falsche Werte erzeugt. Hier die aktuellere und fehlerfreie Version: http://nopaste.info/7db49b5948.html Gruß, zerall
Jürgen Schuhmacher schrieb: > Wenn Du nur einen Tiefpass willst (der headroom zur fs also > weiterhin gross ist) böte sich auch ein butterworth Da würde ich aber eher eine Bessel-Filter nehmen, ist effektiver
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.