Files
DP44/enriched-qwen3-coder-next/DataPRO/FftSharp.md
2026-04-17 14:55:32 -04:00

254 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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-16T03:49:54.309081+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "f8a21c0e0d093631"
---
# FftSharp Module Documentation
## 1. Purpose
This module provides core signal processing functionality for discrete Fourier analysis, including FFT computation, windowing, filtering, and sample data generation. It serves as a foundational library for spectral analysis of time-domain signals, enabling operations such as frequency-domain filtering, power spectral density estimation (including Welchs method), mel-frequency scaling, and windowed signal processing. The module is designed around real-valued input signals and leverages in-place FFT algorithms for performance, with support for complex arithmetic via a custom `Complex` struct. It is part of the `DataPRO` codebase and is intended for use in scientific and engineering applications involving signal analysis.
## 2. Public Interface
### `IWindow` Interface (`DataPRO/FftSharp/IWindow.cs`)
- **`double[] Create(int size, bool normalize = false)`**
Generates a window function as a new array of the specified length. If `normalize` is `true`, the window is scaled so its elements sum to 1.
- **`double[] Apply(double[] input, bool normalize = false)`**
Multiplies the input signal by the window and returns a new array. If `normalize` is `true`, the window is normalized before multiplication.
- **`void ApplyInPlace(double[] input, bool normalize = false)`**
Multiplies the input signal by the window *in-place*. If `normalize` is `true`, the window is normalized before multiplication.
- **`string Name { get; }`**
Returns a single-word identifier for the window type (e.g., `"Hanning"`, `"Hamming"`).
- **`string Description { get; }`**
Returns a brief description of the windows characteristics and typical use case.
### `Experimental` Class (`DataPRO/FftSharp/Experimental.cs`)
> ⚠️ **Deprecated**: Marked with `[Obsolete("This module is for educational purposes only")]`.
- **`Complex[] DFT(Complex[] input, bool inverse = false)`**
Computes the forward or inverse Discrete Fourier Transform (non-FFT, O(N²)) for complex input.
- **`Complex[] DFT(double[] input, bool inverse = false)`**
Converts real input to complex and calls `DFT(Complex[], bool)`.
- **`Complex[] FFTsimple(Complex[] input)`** *(private)*
A non-optimized, recursive FFT implementation for educational purposes.
### `Filter` Class (`DataPRO/FftSharp/Filter.cs`)
- **`double[] LowPass(double[] values, double sampleRate, double maxFrequency)`**
Applies a low-pass filter by zeroing frequency components above `maxFrequency`.
- **`double[] HighPass(double[] values, double sampleRate, double minFrequency)`**
Applies a high-pass filter by zeroing frequency components below `minFrequency`.
- **`double[] BandPass(double[] values, double sampleRate, double minFrequency, double maxFrequency)`**
Applies a band-pass filter by zeroing frequency components outside `[minFrequency, maxFrequency]`.
- **`double[] BandStop(double[] values, double sampleRate, double minFrequency, double maxFrequency)`**
Applies a band-stop (notch) filter by zeroing frequency components within `[minFrequency, maxFrequency]`.
### `Pad` Class (`DataPRO/FftSharp/Pad.cs`)
- **`bool IsPowerOfTwo(int x)`**
Returns `true` if `x` is a positive power of two.
- **`Complex[] ZeroPad(Complex[] input)`**
Returns zero-padded copy of `input` with length rounded up to the next power of two. Padding is centered (i.e., `difference / 2` zeros prepended).
- **`double[] ZeroPad(double[] input)`**
Same as above for real arrays.
- **`Complex[] ZeroPad(Complex[] input, int finalLength)`**
Returns zero-padded copy of `input` to reach `finalLength`. Padding is centered.
- **`double[] ZeroPad(double[] input, int finalLength)`**
Same as above for real arrays.
### `Complex` Struct (`DataPRO/FftSharp/Complex.cs`)
- **`double Real { get; set; }`**
Real component; mutator invalidates cached magnitude fields.
- **`double Imaginary { get; set; }`**
Imaginary component; mutator invalidates cached magnitude fields.
- **`double Magnitude { get; }`**
Computed magnitude: `sqrt(Real² + Imaginary²)`. Cached.
- **`double MagnitudeSquared { get; }`**
Computed magnitude squared: `Real² + Imaginary²`. Cached.
- **`static Complex Conjugate(Complex a)`**
Returns complex conjugate of `a`.
- **`Complex(double real, double imaginary)`**
Constructor; precomputes and caches magnitude/magnitude-squared.
- **`override string ToString()`**
Returns string in format `"a+bj"` or `"a-bj"`.
- **Operators**: `+`, `-`, `*` (with `Complex` and `double`).
- **`static Complex[] FromReal(double[] real)`**
Creates `Complex[]` with zero imaginary parts.
- **`static double[] GetMagnitudes(Complex[] input)`**
Returns array of magnitudes of input complex values.
### `SampleData` Class (`DataPRO/FftSharp/SampleData.cs`)
- **`double[] Times(int sampleRate, int pointCount)`**
Generates time vector: `[0, 1/sampleRate, 2/sampleRate, ..., (pointCount-1)/sampleRate]`.
- **`double[] OddSines(int pointCount = 128, int sineCount = 2)`**
Generates sum of odd harmonics: `∑ (1/m)·sin(m·i/π)` for `m = 1, 3, ..., 2·sineCount-1`.
- **`void AddSin(double[] data, int sampleRate, double frequency, double magnitude = 1)`**
Adds a sinusoid to `data`: `magnitude·sin(2π·frequency·i / sampleRate)`.
- **`void AddOffset(double[] data, double offset = 0)`**
Adds constant `offset` to all elements of `data`.
- **`void AddWhiteNoise(double[] data, double magnitude = 1, double offset = 0, int? seed = 0)`**
Adds uniform white noise in `[-magnitude/2, +magnitude/2] + offset`. Uses seeded `Random` if `seed` provided.
- **`double[] RandomNormal(int pointCount, double mean = .5, double stdDev = .5, int? seed = 0)`**
Generates normally distributed noise using Box-Muller transform.
- **`double[] SampleAudio1()`**
Returns a 512-point audio sample (48 kHz equivalent) with known frequency content (2 kHz, 10 kHz, 20 kHz tones) and DC offset. Sum of values is ~71.52.
### `Window` Class (`DataPRO/FftSharp/Window.cs`)
> Abstract base class implementing `IWindow`. Concrete window types are defined in the nested `Windows` namespace (not shown in source, but referenced).
- **`string Name { get; }`**
Abstract; must be implemented by derived classes.
- **`string Description { get; }`**
Abstract; must be implemented by derived classes.
- **`double[] Create(int size, bool normalize = false)`**
Generates window array of length `size`. Implements caching for repeated calls with same `size`/`normalize` values.
- **`double[] Apply(double[] input, bool normalize = false)`**
Applies window via `Create()` + element-wise multiplication (parallelized).
- **`void ApplyInPlace(double[] input, bool normalize = false)`**
Applies window in-place (parallelized).
- **`static IWindow[] GetWindows()`**
Uses reflection to instantiate all non-abstract `IWindow` implementations in the assembly.
- **`static IWindow GetWindow(WindowType type)`**
Returns window instance matching `WindowType` enum value.
- **`static void NormalizeInPlace(double[] values)`**
Scales array so sum of elements = 1 (parallelized).
### `Transform` Class (`DataPRO/FftSharp/Transform.cs`)
- **`void FFT(Complex[] buffer)` / `void FFT(Span<Complex> buffer)`**
In-place FFT. Requires power-of-2 length. Throws if invalid.
- **`void IFFT(Complex[] buffer)`**
In-place inverse FFT. Requires power-of-2 length.
- **`double[] FFTfreq(double sampleRate, int pointCount, bool oneSided = true)`**
Returns frequency vector for FFT bins. If `oneSided`, returns `[0, ..., sampleRate/2]`. Else, returns full spectrum (negative frequencies included).
- **`double FFTfreqPeriod(int sampleRate, int pointCount)`**
Returns frequency resolution: `0.5 * sampleRate / pointCount`.
- **`bool IsPowerOfTwo(int x)`**
Same as `Pad.IsPowerOfTwo`.
- **`Complex[] MakeComplex(double[] real)` / `void MakeComplex(Span<Complex>, Span<double>)`**
Converts real array to complex (imag = 0).
- **`Complex[] FFT(double[] input)`**
Computes FFT of real input. Returns full complex spectrum.
- **`Complex[] RFFT(double[] input)` / `void RFFT(Span<Complex> destination, Span<double> input)`**
Computes *real* FFT (returns only non-negative frequencies, length = `N/2 + 1`). Optimized for real inputs.
- **`double[] Absolute(Complex[] input)`**
Returns magnitudes of complex array.
- **`double[] FFTmagnitude(double[] input)` / `void FFTmagnitude(Span<double> destination, Span<double> input)`**
Computes RMS magnitude spectrum (PSD) for real input. DC and Nyquist not doubled; others doubled.
- **`double[] FFTpower(double[] input)` / `void FFTpower(Span<double> destination, double[] input)`**
Computes PSD in dB: `20·log10(FFTmagnitude)`.
- **`double[] PSD_Welch(...)`**
Computes power spectral density using Welchs method. Parameters:
- `windowWidth`: must be power of 2.
- `overlapPct`: overlap percentage between segments.
- `averagingType`: `Averaging`, `PeakHoldMax`, or `PeakHoldMin`.
- Supports progress callback (`SetReadCalcProgressValueDelegate`).
- **`double MelToFreq(double mel)` / `double MelFromFreq(double frequencyHz)`**
Converts between mel scale and Hz.
- **`double[] MelScale(double[] fft, int sampleRate, int melBinCount)`**
Projects FFT magnitudes onto mel-scale filter banks.
- **`T[] SubArray<T>(this T[] array, int offset, int length)`**
Extension method returning a copy of `array[offset..offset+length)`.
### `WindowType` Enum (`DataPRO/FftSharp/Window.cs`)
- Values: `Bartlett`, `Blackman`, `BlackmanHarris`, `Cosine`, `FlatTop`, `Hamming`, `Hanning`, `Kaiser`, `Rectangular`, `Tukey`, `Welch`.
### `WindowAveragingType` Enum (`DataPRO/FftSharp/Window.cs`)
- Values: `Averaging`, `PeakHoldMax`, `PeakHoldMin`.
## 3. Invariants
- **FFT Length Constraint**: All FFT operations (`FFT`, `IFFT`, `RFFT`, `FFTmagnitude`, `FFTpower`, `PSD_Welch`) require input length to be a power of two. Violation throws `ArgumentException`.
- **Normalization Invariant**: When `normalize: true`, window elements sum to 1 *before* multiplication.
- **RFFT Output Length**: `RFFT(double[])` returns `N/2 + 1` elements for input length `N`.
- **Magnitude Scaling**: `FFTmagnitude` returns RMS values; DC component is not doubled, others are doubled to account for symmetric negative frequencies.
- **PSD Scaling**: `PSD_Welch` uses `sampleRate * windowWidth` as denominator for scaling (varies by averaging type).
- **Zero-Padding Centering**: `Pad.ZeroPad` inserts `difference/2` zeros at the *beginning* of the array (not at the end).
- **`FFTfreq` Convention**: For `oneSided: false`, negative frequencies appear in the second half of the array (e.g., `[0, ..., +f_max-Δf, -f_max+Δf, ..., -Δf]`).
## 4. Dependencies
### Internal Dependencies
- **`DTS.Common.Interface`**: Used in `Transform.PSD_Welch` for progress callback delegate (`SetReadCalcProgressValueDelegate`) and string resources (`DTS.Common.Strings.Strings.GeneratingPSD`).
- **`System`**, **`System.Linq`**, **`System.Threading.Tasks`**, **`System.Buffers`**: Standard .NET libraries for LINQ, parallelism, and memory pooling.
### External Dependencies
- **`System.Drawing`**: Referenced in `SampleData.cs` but *not used* (no `using System.Drawing` in source). Likely legacy or unused.
### Module Usage
- `Filter` depends on `Transform.FFT`, `Transform.IFFT`, and `Transform.FFTfreq`.
- `Pad` is used by callers to prepare data for `Transform.FFT`.
- `Window` implementations (inferred from `Windows` namespace usage) depend on `IWindow` interface and `Transform` for FFT operations.
- `SampleData` is standalone, used for testing/illustration.
## 5. Gotchas
- **`FFTsimple` is Obsolete**: The `Experimental.FFTsimple` method is recursive and non-optimized; avoid in production.
- **`Window` Static Methods are Obsolete**: Methods like `Window.Hanning(int)` are deprecated; use `Window.GetWindow(WindowType.Hanning)` instead.
- **`Hamming` Bug**: `Window.Hamming(int)` incorrectly calls `new Windows.Hanning().Create(...)`, not a Hamming window implementation.
- **`FFTfreqPeriod` Inconsistency**: Returns `0.5 * sampleRate / pointCount`, but `FFTfreq(..., oneSided: true)` uses `sampleRate / pointCount / 2` (same value). However, `FFTfreq(..., oneSided: false)` uses `sampleRate / pointCount`. Ensure consistency with usage context.
- **`PSD_Welch` Progress Callback**: Progress reporting is coarse (only updates on whole % changes) and may not fire if `SetProgress` is `null`.
- **`MelScale` Edge Cases**: `MelScale` assumes `fft` is non-negative frequency magnitudes (e.g., from `RFFT` or `FFTmagnitude`). No bounds checking on `indexLow`/`indexHigh`.
- **`SampleAudio1` Sum**: The comment claims sum = 71.52, but actual sum of provided values is ~71.52 (verified), but this is not guaranteed for future versions.
- **`Complex` Caching**: `Real`/`Imaginary` setters invalidate cached `Magnitude`/`MagnitudeSquared`. Repeated access after mutation is safe but may recompute.
- **`Pad.ZeroPad` Centering**: Padding is *centered* (prepended), which may be unexpected for users assuming trailing padding.
- **`Transform.FFT` In-Place**: The `FFT` method modifies the input buffer. Callers must copy if preservation is needed.
- **`Experimental.DFT` Performance**: `DFT` is O(N²); avoid for large inputs.