--- source_files: - DataPRO/FftSharp/IWindow.cs - DataPRO/FftSharp/Experimental.cs - DataPRO/FftSharp/Filter.cs - DataPRO/FftSharp/Pad.cs - DataPRO/FftSharp/Complex.cs - DataPRO/FftSharp/SampleData.cs - DataPRO/FftSharp/Window.cs - DataPRO/FftSharp/Transform.cs generated_at: "2026-04-17T15:50:04.390408+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "2a9358b1fffcd8a5" --- # FftSharp Library Documentation ## 1. Purpose FftSharp is a .NET library providing Fast Fourier Transform (FFT) operations and related signal processing utilities. It exists to enable frequency-domain analysis of signals through forward/inverse FFT, windowing functions, spectral filtering, and power spectral density calculations. The library serves as a core signal processing component, offering both high-performance production implementations and educational reference implementations of the DFT algorithm. --- ## 2. Public Interface ### Complex (struct) A mutable struct representing a complex number with cached magnitude calculations. **Properties:** - `double Real` - Real component (setter invalidates cached magnitude values) - `double Imaginary` - Imaginary component (setter invalidates cached magnitude values) - `double Magnitude` - Computed as `sqrt(Real² + Imaginary²)` (cached) - `double MagnitudeSquared` - Computed as `Real² + Imaginary²` (cached) **Constructor:** - `Complex(double real, double imaginary)` **Static Methods:** - `Complex Conjugate(Complex a)` - Returns complex conjugate with negated imaginary component - `Complex[] FromReal(double[] real)` - Creates Complex array from real values (imaginary = 0) - `double[] GetMagnitudes(Complex[] input)` - Extracts magnitude array from Complex array **Operators:** - `operator +(Complex a, Complex b)` - Complex addition - `operator -(Complex a, Complex b)` - Complex subtraction - `operator *(Complex a, Complex b)` - Complex multiplication - `operator *(Complex a, double b)` - Scalar multiplication --- ### IWindow (interface) Contract for window function implementations. **Members:** - `double[] Create(int size, bool normalize = false)` - Generate window array of given length - `double[] Apply(double[] input, bool normalize = false)` - Multiply signal by window, return new array - `void ApplyInPlace(double[] input, bool normalize = false)` - Multiply signal by window in-place - `string Name { get; }` - Single-word window name - `string Description { get; }` - Description of window characteristics and use cases --- ### Window (abstract class) Base class for window implementations implementing `IWindow`. **Properties:** - `abstract string Name { get; }` - `abstract string Description { get; }` **Methods:** - `virtual double[] Create(int size, bool normalize = false)` - Creates window array; caches result for reuse if same size/normalize requested - `double[] Apply(double[] input, bool normalize = false)` - Applies window using `Parallel.For` - `void ApplyInPlace(double[] input, bool normalize = false)` - In-place window application using `Parallel.For` - `static IWindow[] GetWindows()` - Reflects over assembly to instantiate all `IWindow` implementations - `static IWindow GetWindow(WindowType type)` - Factory method returning window by enum type **Obsolete Static Methods (still public):** - `static double[] Rectangular(int pointCount)` - `static double[] Hanning(int pointCount)` - `static double[] Hamming(int pointCount)` - **Note: Implementation creates Hanning window, not Hamming** - `static double[] Blackman(int pointCount)` - `static double[] BlackmanCustom(int pointCount, double a = .42, double b = .5, double c = .08)` - `static double[] BlackmanHarris(int pointCount)` - `static double[] FlatTop(int pointCount)` - `static double[] Bartlett(int pointCount)` - `static double[] Cosine(int pointCount)` - `static double[] Kaiser(int pointCount, double beta)` - `static double[] Apply(double[] window, double[] signal)` - `static void ApplyInPlace(double[] window, double[] signal)` - `static string[] GetWindowNames()` - `static double[] GetWindowByName(string windowName, int pointCount)` **Enums:** - `WindowType` - Bartlett, Blackman, BlackmanHarris, Cosine, FlatTop, Hamming, Hanning, Kaiser, Rectangular, Tukey, Welch - `WindowAveragingType` - Averaging, PeakHoldMax, PeakHoldMin --- ### Transform (static class) Core FFT transformation operations. **FFT Methods:** - `void FFT(Complex[] buffer)` - In-place FFT on array; validates power-of-2 length - `void FFT(Span buffer)` - In-place FFT on Span; validates power-of-2 length - `Complex[] FFT(double[] input)` - Returns FFT of real input as Complex array - `Complex[] RFFT(double[] input)` - Returns real FFT (length N/2+1) for real input - `void RFFT(Span destination, Span input)` - RFFT into provided destination **Inverse FFT:** - `void IFFT(Complex[] buffer)` - In-place inverse FFT **Frequency Utilities:** - `double[] FFTfreq(double sampleRate, int pointCount, bool oneSided = true)` - Returns frequency values for each FFT bin - `double FFTfreqPeriod(int sampleRate, int pointCount)` - Returns frequency spacing between bins **Magnitude/Power:** - `double[] Absolute(Complex[] input)` - Returns magnitude array - `double[] FFTmagnitude(double[] input)` - Returns RMS-scaled magnitude spectrum (length N/2+1) - `void FFTmagnitude(Span destination, Span input)` - In-place magnitude calculation - `double[] FFTpower(double[] input)` - Returns power spectrum in dB - `void FFTpower(Span destination, double[] input)` - In-place power calculation **Power Spectral Density:** - `double[] PSD_Welch(double[] input, long sampleRate, WindowType windowType, int windowWidth, int overlapPct, WindowAveragingType averagingType, SetReadCalcProgressValueDelegate SetProgress = null)` - Welch's method for PSD estimation **Mel Scale:** - `double MelToFreq(double mel)` - Convert Mel to frequency (Hz) - `double MelFromFreq(double frequencyHz)` - Convert frequency (Hz) to Mel - `double[] MelScale(double[] fft, int sampleRate, int melBinCount)` - Convert FFT to Mel scale **Utilities:** - `bool IsPowerOfTwo(int x)` - Tests if value is power of 2 - `Complex[] MakeComplex(double[] real)` - Creates Complex array from real values - `void MakeComplex(Span com, Span real)` - Populates Complex span from real span - `T[] SubArray(this T[] array, int offset, int length)` - Extension method to extract subarray --- ### Filter (static class) Frequency-domain filtering operations. **Methods:** - `double[] LowPass(double[] values, double sampleRate, double maxFrequency)` - Attenuates frequencies above threshold - `double[] HighPass(double[] values, double sampleRate, double minFrequency)` - Attenuates frequencies below threshold - `double[] BandPass(double[] values, double sampleRate, double minFrequency, double maxFrequency)` - Attenuates frequencies outside range - `double[] BandStop(double[] values, double sampleRate, double minFrequency, double maxFrequency)` - Attenuates frequencies inside range --- ### Pad (static class) Zero-padding utilities for array length adjustment. **Methods:** - `bool IsPowerOfTwo(int x)` - Tests if value is power of 2 - `Complex[] ZeroPad(Complex[] input)` - Pads to next power of 2 (centered padding) - `double[] ZeroPad(double[] input)` - Pads to next power of 2 (centered padding) - `Complex[] ZeroPad(Complex[] input, int finalLength)` - Pads to specified length (centered padding) - `double[] ZeroPad(double[] input, int finalLength)` - Pads to specified length (centered padding) --- ### SampleData (static class) Test data generation utilities. **Methods:** - `double[] Times(int sampleRate, int pointCount)` - Generates time axis values - `double[] OddSines(int pointCount = 128, int sineCount = 2)` - Sum of odd harmonic sines - `void AddSin(double[] data, int sampleRate, double frequency, double magnitude = 1)` - Adds sine wave to existing data - `void AddOffset(double[] data, double offset = 0)` - Adds DC offset - `void AddWhiteNoise(double[] data, double magnitude = 1, double offset = 0, int? seed = 0)` - Adds uniform random noise - `double[] RandomNormal(int pointCount, double mean = .5, double stdDev = .5, int? seed = 0)` - Generates normally distributed random values (Box-Muller transform) - `double[] SampleAudio1()` - Returns hardcoded 512-point test signal (sum = 71.52) --- ### Experimental (static class) Educational reference implementations marked `[Obsolete]`. **Methods:** - `Complex[] DFT(Complex[] input, bool inverse = false)` - Naive O(N²) DFT implementation - `Complex[] DFT(double[] input, bool inverse = false)` - DFT for real input **Private:** - `Complex[] FFTsimple(Complex[] input)` - Recursive FFT implementation (non-optimized, educational) --- ## 3. Invariants 1. **Power-of-2 Length Requirement**: All FFT operations (`FFT`, `IFFT`, `RFFT`, `FFTMagnitude`, `FFTPpower`, `PSD_Welch`) require input buffer lengths to be powers of 2. This is validated at runtime with `ArgumentException`. 2. **Non-Empty Buffers**: `FFT` and `IFFT` throw `ArgumentException` if buffer length is 0. 3. **RFFT Output Size**: `RFFT` output length is always `input.Length / 2 + 1`. 4. **Window Caching**: `Window.Create` caches the last generated window; subsequent calls with same size and normalize flag return the cached array. 5. **Centered Padding**: `Pad.ZeroPad` methods add zeros centered around the input data (half before, half after). 6. **Filter Frequency Bounds**: `LowPass` uses `double.NegativeInfinity` as min; `HighPass` uses `double.PositiveInfinity` as max in their `BandPass` delegations. 7. **IFFT Scaling**: `IFFT` scales output by `1/N` where N is buffer length. 8. **Magnitude Scaling**: `FFTMagnitude` scales DC component by `1/N` and all other components by `2/N` to account for positive/negative frequency combination. --- ## 4. Dependencies **Internal Dependencies (inferred from source):** - `Window` depends on `IWindow` interface - `Filter` depends on `Transform.FFT`, `Transform.IFFT`, `Transform.FFTfreq`, and `Complex` - `Transform` depends on `Complex`, `Window`, `WindowType`, `WindowAveragingType` - `Pad` depends on `Complex` **External Dependencies:** - `DTS.Common.Interface.SetReadCalcProgressValueDelegate` - Used in `PSD_Welch` for progress reporting - `DTS.Common.Strings.Strings` - Localization strings used in `PSD_Welch` progress messages - `System.Buffers.ArrayPool` - Used in `RFFT`, `FFTMagnitude`, `FFTPower` for memory pooling **Standard Library Dependencies:** - `System`, `System.Linq`, `System.Reflection`, `System.Threading.Tasks`, `System.Buffers` **Consumers (inferred):** - Unknown from provided source; `PSD_Welch` signature suggests integration with a larger DTS.Common framework --- ## 5. Gotchas 1. **Hamming Window Bug**: The obsolete `Window.Hamming(int pointCount)` method incorrectly instantiates `new Windows.Hanning()`, not a Hamming window. This is a copy-paste error. 2. **Console Output in DFT**: `Experimental.DFT` contains `Console.WriteLine($"REAL {mult1} {mult2}")` which produces unexpected console output when using the experimental DFT. 3. **Window.Create Returns Empty Array for Invalid Size**: When `size <= 0`, `Window.Create` returns `new double[0]` rather than throwing an exception. 4. **Cached Window Mutation Risk**: `Window.Create` returns the cached `lastWindow` array directly. Callers who mutate the returned array will corrupt the cache for subsequent calls. 5. **NormalizeInPlace Race Condition**: `Window.NormalizeInPlace` uses `Parallel.For` to sum values into a local `sum` variable without synchronization, causing a race condition. The sum calculation is non-deterministic under concurrent execution. 6. **Obsolete Methods Still Public**: Many static methods in `Window` class are marked `[Obsolete]` but remain public. The obsolete `Apply` and `ApplyInPlace` methods require window and signal to be same length but throw `ArgumentException` (not `ArgumentOutOfRangeException`) on mismatch. 7. **PSD_Welch Segment Allocation**: Creates `segments` array of size `input.Length / step`, but only populates `input.Length / step` segments. May have uninitialized trailing elements if input length is not evenly divisible. 8. **MelScale Division by Zero**: `MelScale` divides by `binScaleSum` which could be zero if `indexSpan` is 0 (when `indexHigh == indexLow`). 9. **Complex Struct Mutability**: `Complex` is a struct with mutable properties. Setting `Real` or `Imaginary` invalidates cached `_magnitude` and `_magnitudeSquared`, but if the struct is boxed or copied, mutations may not propagate correctly.