TransformBackward( Complex[] samples, params int[] dimensionLengths ) { for (int i = 0; i < dimensionLengths.Length; i++) { if (Fn.CeilingToPowerOf2(dimensionLengths[i]) != dimensionLengths[i]) { throw new ArgumentException(Resources.ArgumentPowerOfTwoEveryDimension, "dimensionLengths"); } } double[] samplePairs = new double[samples.Length << 1]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samplePairs[j] = samples[i].Real; samplePairs[j + 1] = samples[i].Imag; } _fft.DiscreteFourierTransformMultiDim(samplePairs, dimensionLengths, false, _convention); for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samples[i].Real = samplePairs[j]; samples[i].Imag = samplePairs[j + 1]; } }
TransformForward( double[] samples, out double[] fftReal, out double[] fftImag, params int[] dimensionLengths) { for (int i = 0; i < dimensionLengths.Length; i++) { if (Fn.CeilingToPowerOf2(dimensionLengths[i]) != dimensionLengths[i]) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwoEveryDimension, "dimensionLengths"); } } /* TODO: Implement real version (at the moment this is just a wrapper to the complex version)! */ double[] samplePairs = new double[samples.Length << 1]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samplePairs[j] = samples[i]; } _fft.DiscreteFourierTransformMultiDim(samplePairs, dimensionLengths, true, _convention); fftReal = new double[samples.Length]; fftImag = new double[samples.Length]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { fftReal[i] = samplePairs[j]; fftImag[i] = samplePairs[j + 1]; } }
/// <summary> /// Outplace Backward Transformation in multiple dimensions. /// Size must be Power of Two in each dimension. /// The Data is expected to be ordered such that the last index changes most rapidly (in 2D this means row-by-row when indexing as [y,x]). /// </summary> public void TransformBackward(double[] fftReal, double[] fftImag, out double[] samples, params int[] dimensionLengths) { if (fftReal.Length != fftImag.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLengths); } for (int i = 0; i < dimensionLengths.Length; i++) { if (Fn.CeilingToPowerOf2(dimensionLengths[i]) != dimensionLengths[i]) { throw new ArgumentException(Resources.ArgumentPowerOfTwoEveryDimension, "dimensionLengths"); } } // TODO: Implement real version (at the moment this is just a wrapper to the complex version)! double[] samplePairs = new double[fftReal.Length << 1]; for (int i = 0, j = 0; i < fftReal.Length; i++, j += 2) { samplePairs[j] = fftReal[i]; samplePairs[j + 1] = fftImag[i]; } _fft.DiscreteFourierTransformMultiDim(samplePairs, dimensionLengths, false, _convention); samples = new double[fftReal.Length]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samples[i] = samplePairs[j]; } }
/// <summary> /// Inplace Forward Transformation in one dimension. Size must be Power of Two. /// </summary> /// <param name="samplePairs">Complex samples (even = real, odd = imaginary). Length must be a power of two.</param> public void TransformForward(double[] samplePairs) { if (Fn.CeilingToPowerOf2(samplePairs.Length) != samplePairs.Length) { throw new ArgumentException(Resources.ArgumentPowerOfTwo, "samplePairs"); } _fft.DiscreteFourierTransform(samplePairs, true, _convention); }
/// <summary> /// Outplace Forward Transformation in one dimension for two vectors with the same length. /// Size must be Power of Two. /// </summary> /// <param name="samples1">Real samples. Length must be a power of two.</param> /// <param name="samples2">Real samples. Length must be a power of two.</param> public void TransformForward(double[] samples1, double[] samples2, out double[] fftReal1, out double[] fftImag1, out double[] fftReal2, out double[] fftImag2) { if (samples1.Length != samples2.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLengths, "samples2"); } if (Fn.CeilingToPowerOf2(samples1.Length) != samples1.Length) { throw new ArgumentException(Resources.ArgumentPowerOfTwo, "samples1"); } int numSamples = samples1.Length; int length = numSamples << 1; // Pack together to one complex vector double[] complex = new double[length]; for (int i = 0, j = 0; i < numSamples; i++, j += 2) { complex[j] = samples1[i]; complex[j + 1] = samples2[i]; } // Transform complex vector _fft.DiscreteFourierTransform(complex, true, _convention); // Reconstruct data for the two vectors by using symmetries fftReal1 = new double[numSamples]; fftImag1 = new double[numSamples]; fftReal2 = new double[numSamples]; fftImag2 = new double[numSamples]; double h1r, h2i, h2r, h1i; fftReal1[0] = complex[0]; fftReal2[0] = complex[1]; fftImag1[0] = fftImag2[0] = 0d; for (int i = 1, j = 2; j <= numSamples; i++, j += 2) { h1r = 0.5 * (complex[j] + complex[length - j]); h1i = 0.5 * (complex[j + 1] - complex[length + 1 - j]); h2r = 0.5 * (complex[j + 1] + complex[length + 1 - j]); h2i = -0.5 * (complex[j] - complex[length - j]); fftReal1[i] = h1r; fftImag1[i] = h1i; fftReal1[numSamples - i] = h1r; fftImag1[numSamples - i] = -h1i; fftReal2[i] = h2r; fftImag2[i] = h2i; fftReal2[numSamples - i] = h2r; fftImag2[numSamples - i] = -h2i; } }
TransformBackward(double[] samplePairs) { if (Fn.CeilingToPowerOf2(samplePairs.Length) != samplePairs.Length) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwo, "samplePairs"); } _fft.DiscreteFourierTransform(samplePairs, false, _convention); }
TransformBackward( double[] fftReal, double[] fftImag, out double[] samples ) { if (fftReal.Length != fftImag.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLengths); } if (Fn.CeilingToPowerOf2(fftReal.Length) != fftReal.Length) { throw new ArgumentException(Resources.ArgumentPowerOfTwo, "samples"); } int length = fftReal.Length; int numSamples = length >> 1; double expSignConvention = (_convention & TransformationConvention.InverseExponent) > 0 ? -1d : 1d; double theta = -Constants.Pi / numSamples; double wtemp = Trig.Sine(0.5 * theta); double wpr = -2.0 * wtemp * wtemp; double wpi = expSignConvention * Trig.Sine(theta); double wr = 1.0 + wpr; double wi = wpi; samples = new double[length]; double h1r, h2i, h2r, h1i; // TODO: may be 1 <--> 0 swapped? samples[1] = 0.5 * (fftReal[0] - fftReal[numSamples]); samples[0] = 0.5 * (fftReal[0] + fftReal[numSamples]); for (int i = 1, j = 2; j <= numSamples; i++, j += 2) { h1r = 0.5 * (fftReal[i] + fftReal[numSamples - i]); h1i = 0.5 * (fftImag[i] - fftImag[numSamples - i]); h2r = -0.5 * (fftImag[i] + fftImag[numSamples - i]); h2i = 0.5 * (fftReal[i] - fftReal[numSamples - i]); samples[j] = h1r + wr * h2r + wi * h2i; samples[j + 1] = h1i + wr * h2i - wi * h2r; samples[length - j] = h1r - wr * h2r - wi * h2i; samples[length + 1 - j] = -h1i + wr * h2i - wi * h2r; wr = (wtemp = wr) * wpr - wi * wpi + wr; wi = wi * wpr + wtemp * wpi + wi; } // Transform odd and even vectors (packed as one complex vector) _fft.DiscreteFourierTransform(samples, false, _convention); }
/// <summary> /// Inplace Backward Transformation in multiple dimensions. /// Size must be Power of Two in each dimension. /// The Data is expected to be ordered such that the last index changes most rapidly (in 2D this means row-by-row when indexing as [y,x]). /// </summary> /// <param name="samplePairs">Complex samples (even = real, odd = imaginary). Length must be a power of two in each dimension.</param> public void TransformBackward(double[] samplePairs, params int[] dimensionLengths) { for (int i = 0; i < dimensionLengths.Length; i++) { if (Fn.CeilingToPowerOf2(dimensionLengths[i]) != dimensionLengths[i]) { throw new ArgumentException(Resources.ArgumentPowerOfTwoEveryDimension, "dimensionLengths"); } } _fft.DiscreteFourierTransformMultiDim(samplePairs, dimensionLengths, false, _convention); }
public double[] ExtendToPowerOf2Length(double[] samples) { int newlen = Fn.CeilingToPowerOf2(samples.Length); double[] ret = new double[newlen]; for (int i = 0; i < samples.Length; i++) { ret[i] = samples[i]; } // rest is padded with zero. return(ret); }
TransformForward( double[] samplePairs, params int[] dimensionLengths) { for (int i = 0; i < dimensionLengths.Length; i++) { if (Fn.CeilingToPowerOf2(dimensionLengths[i]) != dimensionLengths[i]) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwoEveryDimension, "dimensionLengths"); } } _fft.DiscreteFourierTransformMultiDim(samplePairs, dimensionLengths, true, _convention); }
TransformBackward( double[] fftReal1, double[] fftImag1, double[] fftReal2, double[] fftImag2, out double[] samples1, out double[] samples2 ) { if (fftReal1.Length != fftImag1.Length || fftReal2.Length != fftImag2.Length || fftReal1.Length != fftReal2.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLengths); } if (Fn.CeilingToPowerOf2(fftReal1.Length) != fftReal1.Length) { throw new ArgumentException(Resources.ArgumentPowerOfTwo, "fftReal1"); } int numSamples = fftReal1.Length; int length = numSamples << 1; // Pack together to one complex vector double[] complex = new double[length]; for (int i = 0, j = 0; i < numSamples; i++, j += 2) { complex[j] = fftReal1[i] - fftImag2[i]; complex[j + 1] = fftImag1[i] + fftReal2[i]; } // Transform complex vector _fft.DiscreteFourierTransform(complex, false, _convention); // Reconstruct data for the two vectors samples1 = new double[numSamples]; samples2 = new double[numSamples]; for (int i = 0, j = 0; i < numSamples; i++, j += 2) { samples1[i] = complex[j]; samples2[i] = complex[j + 1]; } }
public void TestSpecialFunctions_CeilingToPowerOf2() { Assert.That(Fn.CeilingToPowerOf2(0), Is.EqualTo(0), "A"); Assert.That(Fn.CeilingToPowerOf2(1), Is.EqualTo(1), "B"); Assert.That(Fn.CeilingToPowerOf2(2), Is.EqualTo(2), "C"); Assert.That(Fn.CeilingToPowerOf2(3), Is.EqualTo(4), "D"); Assert.That(Fn.CeilingToPowerOf2(4), Is.EqualTo(4), "E"); for (int i = 2; i < 31; i++) { int pow = (int)Math.Pow(2.0, i); Assert.That(Fn.CeilingToPowerOf2(pow), Is.EqualTo(pow), pow.ToString()); Assert.That(Fn.CeilingToPowerOf2(pow - 1), Is.EqualTo(pow), pow.ToString() + "-1"); } Assert.That(Fn.CeilingToPowerOf2((int.MaxValue >> 1) + 1), Is.EqualTo((int.MaxValue >> 1) + 1), "Y"); Assert.That(Fn.CeilingToPowerOf2((int.MaxValue >> 1)), Is.EqualTo((int.MaxValue >> 1) + 1), "Z"); }
/// <summary> /// Inplace Backward Transformation in one dimension. Size must be Power of Two. /// </summary> /// <param name="samples">Complex samples. Length must be a power of two.</param> /// <remarks> /// This method provides a simple shortcut if your data is already available as /// <see cref="Complex"/> type instances. However, if not, consider using the /// overloaded method with double pairs instead, it requires less internal copying. /// </remarks> public void TransformBackward(Complex[] samples) { if (Fn.CeilingToPowerOf2(samples.Length) != samples.Length) { throw new ArgumentException(Resources.ArgumentPowerOfTwo, "samplePairs"); } double[] samplePairs = new double[samples.Length << 1]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samplePairs[j] = samples[i].Real; samplePairs[j + 1] = samples[i].Imag; } _fft.DiscreteFourierTransform(samplePairs, false, _convention); for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samples[i].Real = samplePairs[j]; samples[i].Imag = samplePairs[j + 1]; } }
TransformForward(Complex[] samples) { if (Fn.CeilingToPowerOf2(samples.Length) != samples.Length) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwo, "samples"); } double[] samplePairs = new double[samples.Length << 1]; for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samplePairs[j] = samples[i].Real; samplePairs[j + 1] = samples[i].Imag; } _fft.DiscreteFourierTransform(samplePairs, true, _convention); for (int i = 0, j = 0; i < samples.Length; i++, j += 2) { samples[i].Real = samplePairs[j]; samples[i].Imag = samplePairs[j + 1]; } }
TransformForward( double[] samples, out double[] fftReal, out double[] fftImag) { if (Fn.CeilingToPowerOf2(samples.Length) != samples.Length) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwo, "samples"); } int length = samples.Length; int numSamples = length >> 1; double expSignConvention = (_convention & TransformationConvention.InverseExponent) > 0 ? -1d : 1d; // Transform odd and even vectors (packed as one complex vector) // We work on a copy so the original array is not changed. double[] complex = new double[length]; for (int i = 0; i < complex.Length; i++) { complex[i] = samples[i]; } _fft.DiscreteFourierTransform(complex, true, _convention); /* Reconstruct data for the two vectors by using symmetries */ double theta = Constants.Pi / numSamples; double wtemp = Trig.Sine(0.5 * theta); double wpr = -2.0 * wtemp * wtemp; double wpi = expSignConvention * Trig.Sine(theta); double wr = 1.0 + wpr; double wi = wpi; fftReal = new double[length]; fftImag = new double[length]; fftImag[0] = fftImag[numSamples] = 0d; fftReal[0] = complex[0] + complex[1]; fftReal[numSamples] = complex[0] - complex[1]; for (int i = 1, j = 2; j <= numSamples; i++, j += 2) { double h1Real = 0.5 * (complex[j] + complex[length - j]); double h1Imag = 0.5 * (complex[j + 1] - complex[length + 1 - j]); double h2Real = 0.5 * (complex[j + 1] + complex[length + 1 - j]); double h2Imag = -0.5 * (complex[j] - complex[length - j]); fftReal[i] = h1Real + (wr * h2Real) + (wi * h2Imag); fftImag[i] = h1Imag + (wr * h2Imag) - (wi * h2Real); fftReal[numSamples - i] = h1Real - (wr * h2Real) - (wi * h2Imag); fftImag[numSamples - i] = -h1Imag + (wr * h2Imag) - (wi * h2Real); // For consistency and completeness we also provide the // negative spectrum, even though it's redundant in the real case. fftReal[numSamples + i] = fftReal[numSamples - i]; fftImag[numSamples + i] = -fftImag[numSamples - i]; fftReal[length - i] = fftReal[i]; fftImag[length - i] = -fftImag[i]; wr = ((wtemp = wr) * wpr) - (wi * wpi) + wr; wi = (wi * wpr) + (wtemp * wpi) + wi; } }
TransformForward( double[] samples1, double[] samples2, out double[] fftReal1, out double[] fftImag1, out double[] fftReal2, out double[] fftImag2) { if (samples1.Length != samples2.Length) { throw new ArgumentException(Properties.LocalStrings.ArgumentVectorsSameLengths, "samples2"); } if (Fn.CeilingToPowerOf2(samples1.Length) != samples1.Length) { throw new ArgumentException(Properties.LocalStrings.ArgumentPowerOfTwo, "samples1"); } int numSamples = samples1.Length; int length = numSamples << 1; /* Pack together to one complex vector */ double[] complex = new double[length]; for (int i = 0, j = 0; i < numSamples; i++, j += 2) { complex[j] = samples1[i]; complex[j + 1] = samples2[i]; } /* Transform complex vector */ _fft.DiscreteFourierTransform(complex, true, _convention); /* Reconstruct data for the two vectors by using symmetries */ fftReal1 = new double[numSamples]; fftImag1 = new double[numSamples]; fftReal2 = new double[numSamples]; fftImag2 = new double[numSamples]; fftReal1[0] = complex[0]; fftReal2[0] = complex[1]; fftImag1[0] = fftImag2[0] = 0d; for (int i = 1, j = 2; j <= numSamples; i++, j += 2) { double h1Real = 0.5 * (complex[j] + complex[length - j]); double h1Imag = 0.5 * (complex[j + 1] - complex[length + 1 - j]); double h2Real = 0.5 * (complex[j + 1] + complex[length + 1 - j]); double h2Imag = -0.5 * (complex[j] - complex[length - j]); fftReal1[i] = h1Real; fftImag1[i] = h1Imag; fftReal1[numSamples - i] = h1Real; fftImag1[numSamples - i] = -h1Imag; fftReal2[i] = h2Real; fftImag2[i] = h2Imag; fftReal2[numSamples - i] = h2Real; fftImag2[numSamples - i] = -h2Imag; } }