DWT mit Haar und Daubechies db2/db3/db4, mehrstufig, zweidimensional nach Mallat, Schwellenwertverfahren und Entrauschen.
→ Mathematik-Units · std.fft · std.convolve
import std.wavelet;
Schicht 0, hängt an std.math und std.alloc. 20 Funktionen, vier Wavelet-Konstanten. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
| Konstante | Filterlänge | Verschwindende Momente |
|---|---|---|
WAV_HAAR | 2 | 1 |
WAV_DB2 | 4 | 2 |
WAV_DB3 | 6 | 3 |
WAV_DB4 | 8 | 4 |
WavFilterLen(kind) und WavVanishingMoments(kind) geben beides zur Laufzeit aus; WavFilterLow und WavFilterHigh liefern die Koeffizienten selbst.
Verschwindende Momente sagen, welche Signalanteile die Details nicht sehen. Haar mit einem Moment bildet konstante Abschnitte auf null ab; db2 mit zwei Momenten zusätzlich lineare Anstiege, db3 auch quadratische. Für Kompression und Entrauschen ist das der entscheidende Punkt: je mehr Momente, desto mehr Detailkoeffizienten sind praktisch null und desto weniger bleibt zu speichern.
Der Preis ist die Filterlänge — db4 verrechnet acht Nachbarn und verschmiert damit einen Sprung im Signal über acht Stellen. Für Signale mit echten Kanten ist Haar oft die bessere Wahl, obwohl es „das einfachste„ ist.
unit main;
import std.io;
import std.string;
import std.alloc;
import std.wavelet;
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }
fn main(): int64 {
var n: int64 := 8;
var a: int64 := alloc(n * 8);
var i: int64 := 0;
while (i < n) { pokef64(a + i * 8, (i + 1) as f64); i := i + 1; }
var c: int64 := alloc(n * 8);
WavDwt(a, n, WAV_HAAR, c);
i := 0;
while (i < 4) {
Print("Naeherung["); Print(IntToStr(i)); Print("] = ");
PrintF64(peekf64(c + i * 8));
i := i + 1;
}
i := 4;
while (i < 8) {
Print("Detail ["); Print(IntToStr(i - 4)); Print("] = ");
PrintF64(peekf64(c + i * 8));
i := i + 1;
}
ZF("Energie Signal : ", 204.0);
ZF("Energie Koeffizient : ", WavEnergy(c, n));
ZF("EnergyRatio(k=4) : ", WavEnergyRatio(c, n, 4));
var r: int64 := alloc(n * 8);
WavIdwt(c, n, WAV_HAAR, r);
ZF("Rueck x0 : ", peekf64(r));
ZF("Rueck x7 : ", peekf64(r + 56));
return 0;
}
Naeherung[0] = 2.121320
Naeherung[1] = 4.949747
Naeherung[2] = 7.778174
Naeherung[3] = 10.606601
Detail [0] = -0.707106
Detail [1] = -0.707106
Detail [2] = -0.707106
Detail [3] = -0.707106
Energie Signal : 204.000000
Energie Koeffizient : 203.999999
EnergyRatio(k=4) : 0.990196
Rueck x0 : 0.999999
Rueck x7 : 7.999999
Das Signal ist 1, 2, …, 8. Drei Beobachtungen:
n = 8 also vier und vier, hintereinander im selben Feld.WAV_DB2 wären sie null — zwei verschwindende Momente erfassen lineare Anteile vollständig.
WavEnergyRatio(c, n, 4) sagt, welcher Anteil der Energie in den ersten vier Koeffizienten steckt: 99,02 %. Genau das ist die Aussage, auf der Kompression beruht — die Hälfte der Zahlen trägt fast die ganze Information.
| Funktion | Zweck |
|---|---|
WavMaxLevel(n, kind) | wie oft lässt sich zerlegen? |
WavDwtMulti(a, n, kind, levels, out) | mehrstufig vorwärts |
WavIdwtMulti(coeff, n, kind, levels, out) | zurück |
WavApproxLen(n, levels) | Länge des Näherungsteils |
WavDetailRange(n, levels, level, …) | wo liegt die Detailebene level? |
Bei jeder Stufe wird nur der Näherungsteil weiter zerlegt; die Details bleiben liegen. Deshalb braucht man WavDetailRange, um im Ergebnisfeld die einzelnen Ebenen wiederzufinden. WavMaxLevel(64, WAV_HAAR) ergibt 5.
var sigma: f64 := WavEstimateSigma(coeff, n, levels);
var t: f64 := WavUniversalThreshold(sigma, n);
WavThresholdSoft(coeff, n, t);
Oder in einem Schritt: WavDenoise(a, n, kind, levels, …).
| Funktion | Verhalten |
|---|---|
WavThresholdHard(c, n, t) | alles unter t auf null, der Rest bleibt |
WavThresholdSoft(c, n, t) | alles unter t auf null, der Rest wird um t verkleinert |
WavEstimateSigma | Rauschstärke aus den feinsten Details geschätzt |
WavUniversalThreshold(sigma, n) | Schwelle nach Donoho–Johnstone |
Hart oder weich ist keine Geschmacksfrage. Hartes Schwellen lässt die überlebenden Koeffizienten unangetastet und erhält Kanten scharf, erzeugt aber Sprünge an der Schwelle — im Bild sichtbar als Artefakte um Kanten herum. Weiches Schwellen ist stetig und liefert glattere Ergebnisse, verkleinert dabei aber auch die echten Koeffizienten, dämpft also das Nutzsignal mit. Für Bilder ist meist weich richtig, für Signale mit scharfen Ereignissen hart.
WavEstimateSigmaschätzt das Rauschen aus den feinsten Detailkoeffizienten — dort steckt bei natürlichen Signalen fast nur Rauschen. Das setzt voraus, dass das Signal auf der feinsten Ebene tatsächlich glatt ist; bei bewusst hochfrequenten Daten überschätzt die Schätzung das Rauschen und die Entrauschung nimmt zu viel weg.
WavDwt2D(img, w, h, kind, …) und WavIdwt2D zerlegen nach Mallat: erst zeilenweise, dann spaltenweise. Das Ergebnis sind vier Viertel — Näherung oben links, waagerechte, senkrechte und diagonale Details in den übrigen.
| Frage | Unit |
|---|---|
| Welche Frequenzen stecken drin? | std.fft |
| Wo tritt eine Frequenz auf? | std.wavelet |
| Filtern mit einem Kern | std.convolve |
Die FFT sagt, welche Frequenzen ein Signal enthält, aber nicht wann — sie verteilt ein kurzes Ereignis über das ganze Spektrum. Die Wavelet-Transformation behält beides, Ort und Skala, und ist deshalb bei Sprüngen, Kanten und einmaligen Ereignissen die passende Wahl.
Noch nicht auf kompensiertes Summieren umgestellt — zwei Stellen.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; die Energieerhaltung als referenzfreie Invariante nachgerechnet, die Rücktransformation Wert für Wert geprüft.
Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).