/// <summary> /// Computes the auto-covariance for all lags. /// </summary> /// <param name="series">The data series.</param> /// <returns>An array of auto-covariance values, with the array index equal to the lag index.</returns> /// <remarks> /// <para>The computation of the auto-covariance for a given lag is an O(N) operation. /// Naively, the computation of the auto-covariance for all N possible lags is therefore an /// O(N^2) operation; this is in fact the cost of N invocations of /// <see cref="Autocovariance(IReadOnlyList{double},int)"/>. /// However, using Fourier techniques, it is possible to simultaneously compute /// the auto-covariance for all possible lags in O(N log N) operations. This method /// uses the Fourier technique and should be called if you require the auto-covariance /// for more than a handful of lag values.</para> /// </remarks> /// <seealso cref="Autocovariance(IReadOnlyList{double},int)"/> /// <see href="https://en.wikipedia.org/wiki/Autocovariance"/> public static double[] Autocovariance(this IReadOnlyList <double> series) { if (series == null) { throw new ArgumentNullException(nameof(series)); } // To avoid aliasing, we must zero-pad with n zeros. Complex[] s = new Complex[2 * series.Count]; for (int i = 0; i < series.Count; i++) { s[i] = series[i] - series.Mean(); } FourierTransformer fft = new FourierTransformer(s.Length); Complex[] t = fft.Transform(s); for (int i = 0; i < t.Length; i++) { t[i] = MoreMath.Sqr(t[i].Re) + MoreMath.Sqr(t[i].Im); } Complex[] u = fft.InverseTransform(t); double[] c = new double[series.Count]; for (int i = 0; i < c.Length; i++) { c[i] = u[i].Re / series.Count; } return(c); }
/// <summary> /// Computes the autocovariance for all lags. /// </summary> /// <returns>An array of autocovariance values, with the array index equal to the lag index.</returns> /// <remarks> /// <para>The computation of the autocovariance for a given lag is an O(N) operation. /// Naively, the computation of the autocovariance for all N possible lags is an /// O(N^2) operation; this is in fact the cost of N invoations of <see cref="Autocovariance(int)"/>. /// However, it is possible using Fourier techniques to simultaneously compute /// the autocovariance for all possible lags in O(N log N) operations. This method /// uses this Fourier technique and should be called if you require the autocovariance /// for more than a handfull of lag values.</para> /// </remarks> /// <seealso cref="Autocovariance(int)"/> public double[] Autocovariance() { // To avoid aliasing, we must zero-pad with n zeros. Complex[] s = new Complex[2 * data.Count]; for (int i = 0; i < data.Count; i++) { s[i] = data[i] - data.Mean; } FourierTransformer fft = new FourierTransformer(s.Length); Complex[] t = fft.Transform(s); for (int i = 0; i < t.Length; i++) { t[i] = MoreMath.Sqr(t[i].Re) + MoreMath.Sqr(t[i].Im); } Complex[] u = fft.InverseTransform(t); double[] c = new double[data.Count]; for (int i = 0; i < c.Length; i++) { c[i] = u[i].Re / data.Count; } return(c); }
public void FourierInverse() { foreach (int n in sizes) { Console.WriteLine(n); FourierTransformer ft = new FourierTransformer(n); Complex[] x = TestUtilities.GenerateComplexValues(0.1, 10.0, n); Complex[] y = ft.Transform(x); Complex[] z = ft.InverseTransform(y); for (int i = 0; i < n; i++) { Assert.IsTrue(TestUtilities.IsNearlyEqual(x[i], z[i])); } } }
public void TestMethod1() { int N = 49 * 2; FourierTransformer ft = new FourierTransformer(N); Complex[] x = new Complex[N]; x[1] = 1.0; Complex[] y = ft.Transform(x); Complex[] z = ft.InverseTransform(y); //Complex[] z = new Complex[N]; for (int i = 0; i < x.Length; i++) { double t = -2.0 * Math.PI / x.Length * i; Console.WriteLine("{0} -> {1} {2} -> {3}", x[i], y[i], new Complex(Math.Cos(t), Math.Sin(t)), z[i]); } }
public void FourierSpecialCases() { for (int n = 2; n <= 10; n++) { FourierTransformer ft = new FourierTransformer(n); Assert.IsTrue(ft.Length == n); // transform of uniform is zero frequency only Complex[] x1 = new Complex[n]; for (int i = 0; i < n; i++) { x1[i] = 1.0; } Complex[] y1 = ft.Transform(x1); Assert.IsTrue(TestUtilities.IsNearlyEqual(y1[0], n)); for (int i = 1; i < n; i++) { Assert.IsTrue(ComplexMath.Abs(y1[i]) < TestUtilities.TargetPrecision); } Complex[] z1 = ft.InverseTransform(y1); for (int i = 0; i < n; i++) { Assert.IsTrue(TestUtilities.IsNearlyEqual(z1[i], 1.0)); } // transform of pulse at 1 are nth roots of unity, read clockwise Complex[] x2 = new Complex[n]; x2[1] = 1.0; Complex[] y2 = ft.Transform(x2); for (int i = 0; i < n; i++) { double t = -2.0 * Math.PI / n * i; Assert.IsTrue(TestUtilities.IsNearlyEqual(y2[i], new Complex(Math.Cos(t), Math.Sin(t)))); } } }