/// <summary> /// The internal method for calculating the auto-correlation. /// </summary> /// <param name="x">The data array to calculate auto-correlation for</param> /// <param name="kLow">Min lag to calculate ACF for (0 = no shift with acf=1) must be zero or positive and smaller than x.Length</param> /// <param name="kHigh">Max lag (EXCLUSIVE) to calculate ACF for must be positive and smaller than x.Length</param> /// <returns>An array with the ACF as a function of the lags k.</returns> private static double[] AutoCorrelationFft(double[] x, int kLow, int kHigh) { if (x == null) { throw new ArgumentNullException(nameof(x)); } int N = x.Length; // Sample size if (kLow < 0 || kLow >= N) { throw new ArgumentOutOfRangeException(nameof(kLow), "kMin must be zero or positive and smaller than x.Length"); } if (kHigh < 0 || kHigh >= N) { throw new ArgumentOutOfRangeException(nameof(kHigh), "kMax must be positive and smaller than x.Length"); } if (N < 1) { return(new double[0]); } int nFFT = Euclid.CeilingToPowerOfTwo(N) * 2; Complex[] xFFT = new Complex[nFFT]; Complex[] xFFT2 = new Complex[nFFT]; double xDash = ArrayStatistics.Mean(x); double xArrNow = 0.0d; // copy values in range and substract mean - all the remaining parts are padded with zero. for (int i = 0; i < x.Length; i++) { xFFT[i] = new Complex(x[i] - xDash, 0.0); // copy values in range and substract mean } Fourier.Forward(xFFT, FourierOptions.Matlab); // maybe a Vector<Complex> implementation here would be faster for (int i = 0; i < xFFT.Length; i++) { xFFT2[i] = Complex.Multiply(xFFT[i], Complex.Conjugate(xFFT[i])); } Fourier.Inverse(xFFT2, FourierOptions.Matlab); double dc = xFFT2[0].Real; double[] result = new double[kHigh - kLow + 1]; // normalize such that acf[0] would be 1.0 for (int i = 0; i < (kHigh - kLow + 1); i++) { result[i] = xFFT2[kLow + i].Real / dc; } return(result); }
public static Complex Conjugate(this Complex complex) { return(Complex.Conjugate(complex)); }
/// <summary> /// Reduces a complex hermitian matrix to a real symmetric tridiagonal matrix using unitary similarity transformations. /// </summary> /// <param name="matrixA">Source matrix to reduce</param> /// <param name="d">Output: Arrays for internal storage of real parts of eigenvalues</param> /// <param name="e">Output: Arrays for internal storage of imaginary parts of eigenvalues</param> /// <param name="tau">Output: Arrays that contains further information about the transformations.</param> /// <param name="order">Order of initial matrix</param> /// <remarks>This is derived from the Algol procedures HTRIDI by /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK.</remarks> internal static void SymmetricTridiagonalize(System.Numerics.Complex[] matrixA, double[] d, double[] e, System.Numerics.Complex[] tau, int order) { double hh; tau[order - 1] = System.Numerics.Complex.One; for (var i = 0; i < order; i++) { d[i] = matrixA[i * order + i].Real; } // Householder reduction to tridiagonal form. for (var i = order - 1; i > 0; i--) { // Scale to avoid under/overflow. var scale = 0.0; var h = 0.0; for (var k = 0; k < i; k++) { scale = scale + Math.Abs(matrixA[k * order + i].Real) + Math.Abs(matrixA[k * order + i].Imaginary); } if (scale == 0.0) { tau[i - 1] = System.Numerics.Complex.One; e[i] = 0.0; } else { for (var k = 0; k < i; k++) { matrixA[k * order + i] /= scale; h += matrixA[k * order + i].MagnitudeSquared(); } System.Numerics.Complex g = Math.Sqrt(h); e[i] = scale * g.Real; System.Numerics.Complex temp; var im1Oi = (i - 1) * order + i; var f = matrixA[im1Oi]; if (f.Magnitude != 0) { temp = -(matrixA[im1Oi].Conjugate() * tau[i].Conjugate()) / f.Magnitude; h += f.Magnitude * g.Real; g = 1.0 + (g / f.Magnitude); matrixA[im1Oi] *= g; } else { temp = -tau[i].Conjugate(); matrixA[im1Oi] = g; } if ((f.Magnitude == 0) || (i != 1)) { f = System.Numerics.Complex.Zero; for (var j = 0; j < i; j++) { var tmp = System.Numerics.Complex.Zero; var jO = j * order; // Form element of A*U. for (var k = 0; k <= j; k++) { tmp += matrixA[k * order + j] * matrixA[k * order + i].Conjugate(); } for (var k = j + 1; k <= i - 1; k++) { tmp += matrixA[jO + k].Conjugate() * matrixA[k * order + i].Conjugate(); } // Form element of P tau[j] = tmp / h; f += (tmp / h) * matrixA[jO + i]; } hh = f.Real / (h + h); // Form the reduced A. for (var j = 0; j < i; j++) { f = matrixA[j * order + i].Conjugate(); g = tau[j] - (hh * f); tau[j] = g.Conjugate(); for (var k = 0; k <= j; k++) { matrixA[k * order + j] -= (f * tau[k]) + (g * matrixA[k * order + i]); } } } for (var k = 0; k < i; k++) { matrixA[k * order + i] *= scale; } tau[i - 1] = temp.Conjugate(); } hh = d[i]; d[i] = matrixA[i * order + i].Real; matrixA[i * order + i] = new System.Numerics.Complex(hh, scale * Math.Sqrt(h)); } hh = d[0]; d[0] = matrixA[0].Real; matrixA[0] = hh; e[0] = 0.0; }