--- 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-17T15:48:44.861058+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "df53e9f2f708d29c" --- # Documentation: Exocortex.DSP Namespace ## 1. Purpose The `Exocortex.DSP` namespace provides a library for Digital Signal Processing (DSP) utilities within the `DataPRO` system. It offers core data structures for representing double-precision and single-precision complex numbers, mathematical operations for complex arithmetic (roots, powers), statistical analysis tools for complex datasets, and frequency-domain filtering capabilities (Butterworth, Chebyshev, Bessel). It serves as the mathematical backbone for signal manipulation tasks, enabling transformations between time and frequency domains. ## 2. Public Interface ### Structs **`Complex`** A double-precision complex number representation. * `public double Re`: The real component. * `public double Im`: The imaginary component. * `public Complex(double real, double imaginary)`: Constructor. * `static public Complex FromRealImaginary(double real, double imaginary)`: Factory method. * `static public Complex FromModulusArgument(double modulus, double argument)`: Factory method creating a complex number from polar coordinates. * `public double GetModulus()`: Returns the magnitude $\sqrt{Re^2 + Im^2}$. * `public double GetModulusSquared()`: Returns $Re^2 + Im^2$. * `public double GetArgument()`: Returns the angle in radians. * `public Complex GetConjugate()`: Returns the complex conjugate. * `public void Normalize()`: Scales the number to a magnitude of 1. * `static public bool IsEqual(Complex a, Complex b, double tolerance)`: Compares two numbers within a tolerance. * `static public Complex Zero`: Represents $(0, 0)$. * `static public Complex I`: Represents $(0, 1)$. * Operators: `+`, `-`, `*`, `/` (supporting `Complex` and `double` operands), `==`, `!=`. ### Classes **`ComplexMath`** Static utility class for complex number mathematics. * `static public void Swap(ref Complex a, ref Complex b)`: Swaps two complex numbers. * `static public void Swap(ref ComplexF a, ref ComplexF b)`: Swaps two single-precision complex numbers. * `static public Complex Sqrt(Complex c)`: Calculates the square root. * `static public ComplexF Sqrt(ComplexF c)`: Calculates the square root (single-precision). * `static public Complex Pow(Complex c, double exponent)`: Raises a complex number to a power. * `static public ComplexF Pow(ComplexF c, double exponent)`: Raises a complex number to a power (single-precision). **`ComplexStats`** Static utility class for statistical operations on arrays of complex numbers. * `static public Complex Sum(Complex[] data)`: Calculates the sum. * `static public Complex SumOfSquares(Complex[] data)`: Calculates the sum of squares. * `static public Complex Mean(Complex[] data)`: Calculates the mean. * `static public Complex Variance(Complex[] data)`: Calculates the variance. * `static public Complex StdDev(Complex[] data)`: Calculates the standard deviation. * `static public double RMSError(Complex[] alpha, Complex[] beta)`: Calculates the Root Mean Squared Error between two datasets. * *Note: Overloads for `ComplexF[]` exist for all the above methods.* **`PassFilter`** Static class for applying frequency-domain filters. * `static public double[] HighPass(double[] values, double sampleRate, double centerFrequency, PassFilterType type, uint order)`: Applies a high-pass filter. * `static public double[] LowPass(double[] values, double sampleRate, double centerFrequency, PassFilterType type, uint order)`: Applies a low-pass filter. **`Polynomial` (Abstract)** Base class for polynomial representations. * `public Polynomial(params double[] coefficients)`: Constructor. * `public abstract double Evaluate(double value)`: Evaluates the polynomial at a specific value. * `public double GetCoefficient(int index)`: Retrieves a coefficient by index. **`SimplePolynomial`** A concrete implementation of `Polynomial`. * `public SimplePolynomial(params double[] coefficients)`: Constructor. * `public override double Evaluate(double value)`: Evaluates the polynomial using a loop (calculates $c_0 + c_1x + c_2x^2 + \dots$). ### Enums **`FourierDirection`** Specifies the direction of a Fourier Transform. * `Forward = 1`: Time to frequency domain. * `Backward = -1`: Frequency to time domain. **`PassFilterType`** Specifies the type of filter algorithm. * `Bessel`, `Butterworth`, `Chebyshev`, `CriticalDamping`. ## 3. Invariants * **Coefficient Storage**: In `Polynomial`, coefficients are stored in ascending order of power (index 0 is the constant term $c_0$). This is confirmed by `SimplePolynomial.Evaluate` where `coefficients[0]` is the starting value and subsequent coefficients are multiplied by increasing powers of `value`. * **Immutability of Inputs**: `PassFilter` methods (`HighPass`, `LowPass`) do not modify the input `values` array; they clone the internal complex representation before processing. * **FFT Scaling**: `PassFilter` methods scale the result of the inverse FFT by dividing by the signal length `N`. This is required to normalize the output of `Fourier.FFT` with `FourierDirection.Backward`. * **Index Bounds**: `Polynomial.GetCoefficient` returns `double.NaN` if the index is out of bounds or if the coefficient array is null, rather than throwing an exception. * **Comparison Logic**: `Complex.CompareTo` compares instances based on their `Modulus` (magnitude), not their real or imaginary components individually. ## 4. Dependencies **Internal Dependencies (within this namespace):** * `PassFilter` depends on `Complex`, `FourierDirection`, `Polynomial`, and `SimplePolynomial`. * `ComplexStats` depends on `Complex`, `ComplexF`, and `ComplexMath`. * `ComplexMath` depends on `Complex` and `ComplexF`. **External Dependencies:** * `System`: Basic types (`Math`, `Double`, `Array`, etc.). * `System.Linq`: Used heavily in `PassFilter` for projection (`.Select`) and in `ComplexStats`. * `System.Threading.Tasks`: Used in `PassFilter` for parallel processing of frequency bins (`Parallel.For`). * `System.Runtime.InteropServices`: Used in `Complex` for `StructLayout(LayoutKind.Sequential)`. **Missing/Inferred Dependencies:** * `ComplexF`: Referenced in `ComplexMath` and `ComplexStats` but the definition is **not present** in the provided source files. * `Fourier`: The static class `Fourier` is invoked in `PassFilter` (e.g., `Fourier.FFT(signal, N, FourierDirection.Forward)`), but the definition is **not present** in the provided source files. ## 5. Gotchas * **Missing Implementation (`Complex.Parse`)**: The `Complex.Parse(string s)` method exists in the signature but throws a `NotImplementedException` if called. * **Mutation in Math Methods**: The static methods `ComplexMath.Sqrt(Complex c)` and `ComplexMath.Pow(Complex c, double exponent)` mutate the passed-in struct `c` (modifying `c.Re` and `c.Im`) *and* return it. This is unusual for static math utilities which typically return a new instance. * **Precision Loss in Operator**: The subtraction operator `public static Complex operator -(double f, Complex a)` casts the result components to `float` before assigning them back to the `Complex` (double) struct: ```csharp a.Re = (float)(f - a.Re); // Precision loss here a.Im = (float)(0 - a.Im); // Precision loss here ``` This appears to be a bug or legacy artifact, as it reduces precision for double-precision math. * **Hardcoded Filter Parameters**: The public API for `PassFilter` does not expose ripple or DC gain parameters. `RunFilter` hardcodes `DCGain = 1D` for Butterworth/Chebyshev and `ripple = 0.005` for Chebyshev. * **Limited Polynomial Support**: `PassFilter.ChebyshevPolynomial` and `PassFilter.BesselDenominatorPolynomial` throw `NotImplementedException` for orders greater than 8 (Chebyshev) or outside the range 2-8 (Bessel). * **DC Offset Removal**: `PassFilter.ChebyshevFilter` explicitly sets `signal[0] = 0` (removing DC offset) inside the FFT domain. The Bessel and Butterworth implementations do **not** do this; they preserve the DC component (unless the gain function naturally attenuates it).