std.fft — schnelle Fourier-Transformation
Radix-2 für Zweierpotenzen, Bluestein für jede andere Länge; dazu Faltung und Korrelation über die Frequenzebene, Fensterfunktionen und Spektren.
→ Mathematik-Units · std.convolve · std.wavelet · std.complex
import std.fft;
Schicht 0, hängt an std.math, std.math.constants und std.alloc. 21 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Darstellung
Ein komplexes Signal sind zwei f64-Felder gleicher Länge — Realteil und Imaginärteil, getrennt. Die Transformation arbeitet an Ort und Stelle: nach FftForward stehen in denselben Feldern die Frequenzanteile, das Eingangssignal ist überschrieben.
var re: int64 := alloc(n * 8);
var im: int64 := alloc(n * 8);
// ... füllen ...
FftForward(re, im, n); // re/im enthalten jetzt das Spektrum
Wer das Signal danach noch braucht, kopiert es vorher.
Ein vollständiger Durchlauf
unit main;
import std.io;
import std.string;
import std.alloc;
import std.math;
import std.math.constants;
import std.fft;
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }
fn ZI(t: pchar, v: int64): void { Print(t); PrintLn(IntToStr(v)); }
fn main(): int64 {
var n: int64 := 16;
var re: int64 := alloc(n * 8);
var im: int64 := alloc(n * 8);
// Sinus mit 3 Perioden über 16 Abtastwerte
var i: int64 := 0;
while (i < n) {
var t: f64 := (i as f64) / (n as f64);
var arg: f64 := 2.0 * PI * 3.0 * t;
pokef64(re + i * 8, SinF64(arg));
pokef64(im + i * 8, 0.0);
i := i + 1;
}
var e1: f64 := 0.0;
i := 0;
while (i < n) { var v: f64 := peekf64(re + i*8); e1 := e1 + v * v; i := i + 1; }
ZI("IsPowerOfTwo(16) : ", FftIsPowerOfTwo(16) as int64);
ZI("NextPowerOfTwo(17) : ", FftNextPowerOfTwo(17));
FftForward(re, im, n);
ZI("PeakBin : ", FftPeakBin(re, im, n));
ZF("BinFrequency(3, 16000 Hz): ", FftBinFrequency(3, n, 16000.0));
var e2: f64 := 0.0;
i := 0;
while (i < n) {
var r: f64 := peekf64(re + i*8);
var m: f64 := peekf64(im + i*8);
e2 := e2 + r * r + m * m;
i := i + 1;
}
ZF("Energie Zeitbereich: ", e1);
ZF("Energie Freq / n : ", e2 / (n as f64));
FftInverse(re, im, n);
ZF("nach Hin+Rueck x0 : ", peekf64(re));
ZF("nach Hin+Rueck x4 : ", peekf64(re + 32));
return 0;
}
IsPowerOfTwo(16) : 1
NextPowerOfTwo(17) : 32
PeakBin : 3
BinFrequency(3, 16000 Hz): 3000.000000
Energie Zeitbereich: 8.000000
Energie Freq / n : 8.000000
nach Hin+Rueck x0 : 0.000000
nach Hin+Rueck x4 : -0.999999
Drei Aussagen stecken darin:
PeakBinist 3 — genau die Zahl der Perioden im Fenster. Bei 16 000 Hz Abtastrate entspricht Bin 3 einer Frequenz von 3000 Hz, undFftBinFrequencyrechnet das aus.- Die Energie stimmt überein (8 = 8). Das ist der Satz von Parseval: die Energie im Zeitbereich gleicht der im Frequenzbereich, geteilt durch
n. Eine Prüfung, die keine fremde Referenz braucht — sie gilt aus sich heraus und deckt einen falschen Normierungsfaktor sofort auf. - Hin und zurück stellt wieder her.
x4war−1und ist es nach beiden Schritten wieder (bis auf die letzte Stelle).
Welches Verfahren
| Funktion | Länge | Aufwand |
|---|---|---|
FftRadix2 | nur Zweierpotenzen | O(n log n) |
FftBluestein | jede Länge | O(n log n), größere Konstante |
FftDft | jede | O(n²) — zum Gegenprüfen |
FftForward / FftInverse | jede | wählt selbst |
FftForward und FftInverse sind der normale Weg. Sie nehmen Radix-2, wo es geht, und Bluestein sonst. Die Einzelverfahren braucht man nur, wenn man das Verhalten festlegen will — oder FftDft als langsame, aber unabhängige Gegenrechnung beim Prüfen.
FftIsPowerOfTwo und FftNextPowerOfTwo helfen beim Auffüllen, wenn man Bluestein vermeiden will.
FftForwardReal(data, n, outRe, outIm) nimmt ein rein reelles Signal und spart das Nullfeld für den Imaginärteil.
Spektren auswerten
| Funktion | Liefert |
|---|---|
FftMagnitude(re, im, n, out) | Betrag je Bin |
FftPower(re, im, n, out) | Betragsquadrat |
FftPhase(re, im, n, out) | Phasenwinkel |
FftPeakBin(re, im, n) | Bin mit dem größten Betrag |
FftBinFrequency(bin, n, sampleRate) | Bin → Frequenz in Hz |
Fenster
var win: int64 := alloc(n * 8);
FftWindowHann(win, n);
FftApplyWindow(data, win, n);
| Fenster | Eigenschaft |
|---|---|
FftWindowHann | guter Allrounder |
FftWindowHamming | niedrigerer erster Nebenzipfel |
FftWindowBlackman | stärkste Dämpfung, breiterer Hauptzipfel |
Ein Fenster ändert die Amplituden. Wer nach dem Fenstern absolute Pegel ablesen will, muss durch die Fensterverstärkung teilen —FftWindowGain(window, n)liefert sie. Ohne diesen Schritt sind die Beträge systematisch zu klein.
Gefenstert wird, weil die FFT das Fenster als periodisch fortgesetzt ansieht. Passt die Signalfrequenz nicht genau in das Fenster, entsteht am Rand ein Sprung, und dessen Energie verteilt sich über das ganze Spektrum („Leckeffekt„). Im Beispiel oben passt der Sinus mit genau 3 Perioden exakt hinein — deshalb ist dort kein Fenster nötig und der Peak ist scharf.
Faltung und Korrelation
| Funktion | Zweck |
|---|---|
FftConvolveReal(a, na, b, nb, out) | lineare Faltung zweier reeller Folgen |
FftConvolveCircular(are, aim, bre, bim, n) | zyklische Faltung, an Ort und Stelle |
FftCorrelateReal(a, b, n, out) | Kreuzkorrelation |
FftConvolveReal liefert na + nb − 1 Werte — der Zielpuffer muss so groß sein.
Der Unterschied zwischen linear und zyklisch ist kein Detail. Die FFT faltet von Natur aus zyklisch: was rechts hinausläuft, kommt links wieder herein. Für eine lineare Faltung müssen beide Folgen vorher auf mindestensna + nb − 1mit Nullen aufgefüllt werden —FftConvolveRealerledigt das,FftConvolveCircularausdrücklich nicht. Wer die zyklische Fassung für Signalfilterung nimmt, bekommt am Anfang des Ergebnisses das Ende des Signals eingemischt.
Für Filter mit Randbehandlung, 2D und Overlap-Add ist std.convolve die passendere Unit — sie setzt auf std.fft auf.
Offener Punkt
Die inneren Schleifen summieren noch naiv.std.fftist an einer Stelle nicht auf kompensiertes Summieren umgestellt (std.convolvean acht). Bei sehr langen Signalen mit stark verschiedenen Größenordnungen lohnt eine Gegenprobe über std.sum. Für übliche Längen und Wertebereiche fällt es nicht ins Gewicht — die Parseval-Prüfung oben stimmt exakt.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; Peak-Bin, Frequenzzuordnung und Rücktransformation gegen eine unabhängige Referenzrechnung geprüft, die Energiegleichheit als referenzfreie Invariante nachgerechnet.
