--- source_files: - DataPRO/ExocortexDSP/Polynomial.cs - DataPRO/ExocortexDSP/FourierDirection.cs - DataPRO/ExocortexDSP/AssemblyInfo.cs - DataPRO/ExocortexDSP/ComplexMath.cs - DataPRO/ExocortexDSP/PassFilter.cs - DataPRO/ExocortexDSP/ComplexStats.cs - DataPRO/ExocortexDSP/Complex.cs generated_at: "2026-04-16T03:48:44.236669+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "e35f8b9ef214514d" --- # Exocortex.DSP Module Documentation ## 1. Purpose This module provides core digital signal processing (DSP) functionality for the Exocortex Technologies library. It defines foundational types and utilities including complex number representations (`Complex`, `ComplexF`), polynomial evaluation (`Polynomial`, `SimplePolynomial`), filter implementations (`PassFilter`), Fourier transform direction specification (`FourierDirection`), and statistical operations on complex arrays (`ComplexStats`). The module serves as the mathematical backbone for signal analysis and transformation operations within the larger DataPRO system. ## 2. Public Interface ### Structs #### `Complex` - **`public Complex(double real, double imaginary)`** Constructs a double-precision complex number from real and imaginary components. - **`public Complex(Complex c)`** Copy constructor. - **`public static Complex FromRealImaginary(double real, double imaginary)`** Factory method to create a complex number from real/imaginary parts. - **`public static Complex FromModulusArgument(double modulus, double argument)`** Factory method to create a complex number from polar coordinates (modulus and argument in radians). - **`public double GetModulus()`** Returns the magnitude (Euclidean norm) of the complex number. - **`public double GetModulusSquared()`** Returns the squared magnitude (faster than `GetModulus()`). - **`public double GetArgument()`** Returns the phase angle (argument) in radians. - **`public Complex GetConjugate()`** Returns the complex conjugate. - **`public void Normalize()`** Scales the complex number to unit magnitude (throws `DivideByZeroException` if zero). - **`public static explicit operator Complex(ComplexF cF)`** Explicit cast from single-precision `ComplexF` to `Complex`. - **`public static explicit operator Complex(double d)`** Explicit cast from `double` to `Complex` (real part = `d`, imaginary part = 0). - **`public static explicit operator double(Complex c)`** Explicit cast from `Complex` to `double` (returns real part). - **`public static bool operator ==(Complex a, Complex b)`** Equality comparison (exact). - **`public static bool operator !=(Complex a, Complex b)`** Inequality comparison (exact). - **`public override bool Equals(object o)`** Object equality (delegates to `==`). - **`public int CompareTo(object o)`** Compares based on magnitude (modulus). Supports comparison with `Complex`, `double`, `ComplexF`, `float`, or `null`. - **`public static Complex operator +(Complex a)`** Unary plus. - **`public static Complex operator -(Complex a)`** Unary negation. - **`public static Complex operator +(Complex a, double f)` / `operator +(double f, Complex a)`** Addition with real scalar. - **`public static Complex operator +(Complex a, Complex b)`** Complex addition. - **`public static Complex operator -(Complex a, double f)` / `operator -(double f, Complex a)`** Subtraction with real scalar. - **`public static Complex operator -(Complex a, Complex b)`** Complex subtraction. - **`public static Complex operator *(Complex a, double f)` / `operator *(double f, Complex a)`** Scalar multiplication. - **`public static Complex operator *(Complex a, Complex b)`** Complex multiplication. - **`public static Complex operator /(Complex a, double f)`** Scalar division (throws `DivideByZeroException` if `f == 0`). - **`public static Complex operator /(Complex a, Complex b)`** Complex division (throws `DivideByZeroException` if divisor is zero). - **`public static bool IsEqual(Complex a, Complex b, double tolerance)`** Approximate equality check within `tolerance`. - **`public override string ToString()`** Returns string in format `"( {Re}, {Im}i )"`. - **`public static Complex Zero`** Static property returning `(0, 0)`. - **`public static Complex I`** Static property returning `(0, 1)` (imaginary unit). - **`public static Complex MaxValue` / `MinValue`** Static properties for extreme values. #### `ComplexF` - *Note: Definition not provided in source files, but referenced extensively in `ComplexStats` and `ComplexMath`. Assumed to be a single-precision counterpart to `Complex`.* ### Classes #### `Polynomial` - **`protected double[] coefficients`** Protected field storing the polynomial coefficients (index 0 = constant term). - **`public Polynomial(params double[] coefficients)`** Constructor initializing coefficients via deep copy. - **`public abstract double Evaluate(double value)`** Abstract method to evaluate the polynomial at `value`. - **`public double GetCoefficient(int index)`** Returns coefficient at `index`, or `double.NaN` if `coefficients == null`, `index < 0`, or `index >= coefficients.Length`. #### `SimplePolynomial : Polynomial` - **`public SimplePolynomial(params double[] coefficients)`** Constructor delegating to base class. - **`public override double Evaluate(double value)`** Evaluates polynomial using Horner’s method: `retval = c[0] + c[1]*x + c[2]*x² + ...` Computed iteratively for efficiency. #### `ComplexMath` - **`private ComplexMath()`** Private constructor (static class pattern). - **`public static void Swap(ref Complex a, ref Complex b)`** Swaps two `Complex` instances. - **`public static void Swap(ref ComplexF a, ref ComplexF b)`** Swaps two `ComplexF` instances. - **`public static Complex Sqrt(Complex c)`** Computes complex square root using principal branch. Formula: `real = √2/2 * √(|c| + Re(c))` `imag = sign(Im(c)) * √2/2 * √(|c| - Re(c))` where `|c|` is modulus. - **`public static ComplexF Sqrt(ComplexF c)`** Single-precision variant of `Sqrt`. - **`public static Complex Pow(Complex c, double exponent)`** Computes `c^exponent` via polar form: `modulus = |c|^exponent`, `argument = arg(c) * exponent`, then converts back: `(modulus * cos(arg), modulus * sin(arg))`. - **`public static ComplexF Pow(ComplexF c, double exponent)`** Single-precision variant of `Pow`. #### `ComplexStats` - **`private ComplexStats()`** Private constructor (static class pattern). - **`public static Complex Sum(Complex[] data)` / `Sum(ComplexF[] data)`** Computes sum of array elements using recursive divide-and-conquer (base case ≤1000 elements). - **`public static Complex SumOfSquares(Complex[] data)` / `SumOfSquares(ComplexF[] data)`** Computes `Σ(data[i] * data[i])` (note: *not* `|data[i]|²`). - **`public static Complex Mean(Complex[] data)` / `Mean(ComplexF[] data)`** Computes arithmetic mean: `Sum(data) / data.Length`. - **`public static Complex Variance(Complex[] data)` / `Variance(ComplexF[] data)`** Computes variance as: `SumOfSquares(data)/n - Sum(data)`. Throws `DivideByZeroException` if `data.Length == 0`. - **`public static Complex StdDev(Complex[] data)` / `StdDev(ComplexF[] data)`** Computes standard deviation: `Sqrt(Variance(data))`. Throws `DivideByZeroException` if `data.Length == 0`. - **`public static double RMSError(Complex[] alpha, Complex[] beta)` / `RMSError(ComplexF[] alpha, ComplexF[] beta)`** Computes root mean squared error between two arrays: `sqrt( Σ |beta[i] - alpha[i]|² / n )`. Arrays must be non-null and equal length. #### `PassFilter` - **`public static double[] HighPass(double[] values, double sampleRate, double centerFrequency, PassFilterType type, uint order)`** Applies high-pass filtering via FFT. Delegates to `RunFilter(..., lowPass: false)`. - **`public static double[] LowPass(double[] values, double sampleRate, double centerFrequency, PassFilterType type, uint order)`** Applies low-pass filtering via FFT. Delegates to `RunFilter(..., lowPass: true)`. - **`private static double[] RunFilter(..., bool lowPass)`** Core filtering logic: 1. Converts input `double[]` to `Complex[]` (imag part = 0). 2. Applies forward FFT. 3. Applies frequency-domain gain function (parallelized via `Parallel.For`). 4. Applies inverse FFT. 5. Scales result by `1/N`. 6. Extracts real parts as `double[]`. - *Note: DC component (`signal[0]`) is zeroed only for Chebyshev filter.* - **`private static Complex[] BesselFilter(...)`** Implements Bessel filter using precomputed denominator polynomial `B`. Gain: `numerator / sqrt(B(freq / centerFreq))` (low-pass) or `numerator / sqrt(B(centerFreq / freq))` (high-pass). - **`private static double BesselGain(...)`** Helper for Bessel gain computation. - **`private static Complex[] ButterworthFilter(...)`** Implements Butterworth filter. Gain: `DCGain / sqrt(1 + (freq / centerFreq)^(2*order))` (low-pass) or `DCGain / sqrt(1 + (centerFreq / freq)^(2*order))` (high-pass). - **`private static double ButterworthGain(...)`** Helper for Butterworth gain computation. - **`private static Complex[] ChebyshevFilter(...)`** Implements Chebyshev filter using precomputed Chebyshev polynomial `T`. Gain: `DCGain / sqrt(1 + ripple * T(freq / centerFreq)^(2*order))` (low-pass) or similar for high-pass. *Note: DC component zeroed before filtering.* - **`private static double ChebyshevGain(...)`** Helper for Chebyshev gain computation. - **`private static Polynomial ChebyshevPolynomial(int order)`** Returns `SimplePolynomial` instance for Chebyshev polynomial of order `0`–`8` (hardcoded coefficients). Throws `NotImplementedException` for other orders. - **`private static Polynomial BesselDenominatorPolynomial(int order)`** Returns `SimplePolynomial` instance for Bessel denominator polynomial (squared magnitude denominator) for orders `2`–`8` (hardcoded coefficients). Throws `NotImplementedException` for other orders. ### Enums #### `FourierDirection` - **`Forward = 1`** Indicates forward FFT (time → frequency). - **`Backward = -1`** Indicates inverse FFT (frequency → time). #### `PassFilterType` - **`Bessel`** Maximally flat group delay. - **`Butterworth`** Maximally flat magnitude response. - **`Chebyshev`** Equi-ripple in passband. - **`CriticalDamping`** Fastest non-oscillatory response. ## 3. Invariants - **`Polynomial.coefficients`** is always non-null after construction (deep copy of input array). - **`Polynomial.GetCoefficient(index)`** returns `double.NaN` for invalid indices (`null`, negative, or ≥ length). - **`Complex.Normalize()`** throws `DivideByZeroException` if modulus is zero. - **`ComplexStats.Variance`/`StdDev`** throw `DivideByZeroException` if input array length is zero. - **`ComplexStats.RMSError`** asserts (via `Debug.Assert`) that both input arrays are non-null and of equal length. - **`ComplexStats.Sum`/`SumOfSquares`** use recursion with base case size ≤1000 for performance. - **`PassFilter.RunFilter`** assumes FFT length `N` is even (uses `N/2` bins for symmetric spectrum). - **`PassFilter`** filters require `centerFrequency > 0`; if `centerFrequency <= 0`, no filtering is applied (original signal returned). - **`PassFilter`** filters assume input array length matches FFT size (`N`), and output is scaled by `1/N` after inverse FFT. ## 4. Dependencies ### Internal Dependencies (within `Exocortex.DSP`) - **`Complex`** is used by: - `ComplexMath` (operations on `Complex`) - `ComplexStats` (statistical operations on `Complex[]`) - `PassFilter` (filtering via FFT) - `Polynomial` (indirectly via `Complex[]` in `RunFilter`) - **`ComplexF`** is used by: - `ComplexMath` (single-precision operations) - `ComplexStats` (statistical operations on `ComplexF[]`) - **`Fourier`** is referenced in `PassFilter` (`Fourier.FFT(...)`), but its definition is not provided in the source files. - **`SimplePolynomial`** is used by `PassFilter` (Bessel/Chebyshev filter polynomials). ### External Dependencies - **`System`** (core types: `Math`, `Debug`, `String`, `Exception`, `Attribute`, `Runtime.InteropServices`) - **`System.Threading.Tasks`** (used for `Parallel.For` in `PassFilter`) - **`System.Collections.Generic`**, **`System.Linq`**, **`System.Text`**, **`System.Threading.Tasks`** (via `PassFilter.cs`) ### Inferred Usage - **`Fourier.FFT`** is a required dependency (not shown in source). Its behavior is assumed to be: - In-place transform of `Complex[]`. - Supports `FourierDirection.Forward`/`Backward`. - Output scaling is handled explicitly in `PassFilter` (`signal = signal.Select(n => n / N).ToArray()`). ## 5. Gotchas - **`ComplexStats.SumOfSquares`** computes `Σ(z_i * z_i)` (algebraic square), *not* `Σ|z_i|²` (squared magnitude). This is unconventional for complex statistics and may be a source of errors. - **`ComplexStats.Variance`** formula `SumOfSquares/n - Sum` is *incorrect* for complex numbers. Correct variance should be `Σ|z_i - μ|²/n`. The current implementation yields complex-valued variance (real part may be negative), which is non-standard. - **`ComplexStats.RMSError`** computes RMS error as `sqrt( Σ|Δ|² / n )`, but `SumOfSquaredErrorRecursion` uses `|Δ|² = Δ.Re² + Δ.Im²` (correct), while `SumOfSquares` in `Variance` does not. - **`Complex.Parse(string)`** is declared but throws `NotImplementedException`. No parsing support exists. - **`PassFilter`** uses hardcoded polynomial coefficients for orders `0`–`8` (Chebyshev) and `2`–`8` (Bessel). Filters for other orders are unsupported. - **`PassFilter`** filters assume even-length input arrays (due to `N/2` bin symmetry assumption). Behavior for odd lengths is undefined. - **`PassFilter`** filters zero DC component only for Chebyshev filters (`signal[0] = 0`), but not for Bessel/Butterworth. This may cause unintended DC offset differences. - **`Complex.GetModulus()`** and **`GetArgument()`** use `Math.Sqrt`/`Math.Atan2`, which may have performance implications in hot loops. - **`Complex`** struct is mutable (fields are public). Operations like `operator +`, `*`, `/` modify the *first operand in-place* before returning it (e.g., `a + b` mutates `a`). This violates typical expectations for value types and may cause side effects. - **`Complex.CompareTo`** compares by magnitude only, not lexicographically. Comparing complex numbers by magnitude may be semantically unclear. - **`Complex`** has no `IEquatable` implementation; `Equals`/`==` use exact equality (no tolerance). - **`ComplexStats`** methods use `Debug.Assert` for validation, which are *disabled in release builds*. Invalid inputs (e.g., null arrays) may cause runtime exceptions only at runtime (not compile-time). - **`PassFilter`** uses `Parallel.For` for frequency-domain filtering, but may not scale well for small arrays due to parallelization overhead.