/// <summary> /// Performs a complex-to-real inverse fast fourier transformation. /// </summary> /// <seealso cref="http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data"/> /// <seealso cref="http://www.fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html#Multi_002dDimensional-DFTs-of-Real-Data"/> public static void IFFT(IPinnedArray <Complex> input, IPinnedArray <double> output, PlannerFlags plannerFlags = PlannerFlags.Default, int nThreads = 1) { if ((plannerFlags & PlannerFlags.Estimate) == PlannerFlags.Estimate) { using (var plan = FftwPlanRC.Create(output, input, DftDirection.Backwards, plannerFlags, nThreads)) { plan.Execute(); return; } } using (var plan = FftwPlanRC.Create(output, input, DftDirection.Backwards, plannerFlags | PlannerFlags.WisdomOnly, nThreads)) { if (plan != null) { plan.Execute(); return; } } /// If with <see cref="PlannerFlags.WisdomOnly"/> no plan can be created /// and <see cref="PlannerFlags.Estimate"/> is not specified, we use /// a different buffer to avoid overwriting the input using (var bufferContainer = _bufferPool.RequestBuffer(input.Length * Marshal.SizeOf <Complex>() + MemoryAlignment)) using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer, MemoryAlignment, input.GetSize())) using (var plan = FftwPlanRC.Create(output, buffer, DftDirection.Backwards, plannerFlags, nThreads)) { input.CopyTo(plan.BufferComplex); plan.Execute(); } }
static void doBandPass(IPinnedArray <Complex> trans, int[] passIndexRange) { var j1 = passIndexRange[0]; var j2 = passIndexRange[1]; var lenPositive = trans.Length / 2 + trans.Length % 2; //positive freq for (int i = 0; i < j1; i++) { trans[i] = 0; } for (int i = j2 + 1; i < lenPositive; i++) { trans[i] = 0; } //negative freq j1 = trans.Length - j1; j2 = trans.Length - j2; for (int i = lenPositive; i < j2; i++) { trans[i] = 0; } for (int i = j1 + 1; i < trans.Length; i++) { trans[i] = 0; } }
public static void CopyTo <T>(this IPinnedArray <T> src, IPinnedArray <T> dst, int srcIndex, int dstIndex, int count) where T : struct { if (count < 0 || count > src.Length) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count > dst.Length) { throw new ArgumentException(nameof(dst), "Destination is not large enough."); } if (srcIndex + count > src.Length) { throw new ArgumentOutOfRangeException(nameof(srcIndex)); } if (dstIndex + count > src.Length) { throw new ArgumentOutOfRangeException(nameof(dstIndex)); } int sizeOfT = Marshal.SizeOf <T>(); unsafe { void *pSrc = new IntPtr(src.Pointer.ToInt64() + srcIndex * sizeOfT).ToPointer(); void *pDst = new IntPtr(dst.Pointer.ToInt64() + dstIndex * sizeOfT).ToPointer(); System.Buffer.MemoryCopy(pSrc, pDst, (long)dst.Length * sizeOfT, (long)count * sizeOfT); } }
protected override void VerifyMinSize(IPinnedArray <double> bufferReal, IPinnedArray <Complex> bufferComplex, int[] n) { int sizeComplex; int sizeReal = 1; checked { for (int i = 0; i < n.Length - 1; i++) { sizeReal *= n[i]; } sizeComplex = sizeReal * (n[n.Length - 1] / 2 + 1); sizeReal *= n[n.Length - 1]; } if (bufferReal.Length < sizeReal) { throw new ArgumentException($"{nameof(bufferReal)} is too small."); } if (bufferComplex.Length < sizeComplex) { throw new ArgumentException($"{nameof(bufferComplex)} is too small."); } }
/// <summary> /// Initializes a new plan using the provided input and output buffers. /// These buffers may be overwritten during initialization. /// </summary> public static FftwPlanRC Create(IPinnedArray <double> bufferReal, IPinnedArray <Complex> bufferComplex, DftDirection direction, PlannerFlags plannerFlags = PlannerFlags.Default, int nThreads = 1) { FftwPlanRC plan = new FftwPlanRC(bufferReal, bufferComplex, bufferReal.Rank, bufferReal.GetSize(), true, direction, plannerFlags, nThreads); if (plan.IsZero) { return(null); } return(plan); }
FftwPlanR2R(IPinnedArray <Double> input, IPinnedArray <Double> output, int rank, int[] n, bool verifyRankAndSize, DftDirection direction, PlannerFlags plannerFlags, int nThreads) : base(input, output, rank, n, verifyRankAndSize, direction, plannerFlags, 1) { //int[] ns = input.GetSize(); //lock (FftwInterop.Lock) //{ // //_plan = FftwInterop.fftw_plan_r2r(rank,ns,input.Pointer,output.Pointer,direction,plannerFlags); // _plan = GetPlan(rank, n, input.Pointer, output.Pointer, direction, plannerFlags); //} }
internal static FftwPlanRC Create(IPinnedArray <double> bufferReal, IPinnedArray <Complex> bufferComplex, int rank, int[] n, DftDirection direction, PlannerFlags plannerFlags, int nThreads) { FftwPlanRC plan = new FftwPlanRC(bufferReal, bufferComplex, rank, n, false, direction, plannerFlags, nThreads); if (plan.IsZero) { return(null); } return(plan); }
internal static FftwPlanC2C Create(IPinnedArray <Complex> input, IPinnedArray <Complex> output, int rank, int[] n, DftDirection direction, PlannerFlags plannerFlags, int nThreads) { FftwPlanC2C plan = new FftwPlanC2C(input, output, rank, n, false, direction, plannerFlags, nThreads); if (plan.IsZero) { return(null); } return(plan); }
/// <summary> /// Initializes a new plan using the provided input and output buffers. /// These buffers may be overwritten during initialization. /// </summary> public static FftwPlanC2C Create(IPinnedArray <Complex> input, IPinnedArray <Complex> output, DftDirection direction, PlannerFlags plannerFlags = PlannerFlags.Default, int nThreads = 1) { FftwPlanC2C plan = new FftwPlanC2C(input, output, input.Rank, input.GetSize(), true, direction, plannerFlags, nThreads); if (plan.IsZero) { return(null); } return(plan); }
protected override void VerifyMinSize(IPinnedArray <Complex> input, IPinnedArray <Complex> output, int[] n) { int size = Utils.GetTotalSize(n); if (input.Length < size) { throw new ArgumentException($"{nameof(input)} is too small."); } if (output.Length < size) { throw new ArgumentException($"{nameof(output)} is too small."); } }
protected override void VerifyRankAndSize(IPinnedArray <Complex> input, IPinnedArray <Complex> output) { if (input.Rank != output.Rank) { throw new ArgumentException($"{nameof(input)} and {nameof(output)} must have the same rank and size."); } for (int i = 0; i < input.Rank; i++) { if (input.GetLength(i) != output.GetLength(i)) { throw new ArgumentException($"{nameof(input)} and {nameof(output)} must have the same rank and size."); } } }
public static int GetIndex <T>(this IPinnedArray <T> array, int[] indices) where T : struct { if (indices.Length != array.Rank) { throw new ArgumentException($"Array of length {nameof(array.Rank)} = {array.Rank} expected.", nameof(indices)); } int index = indices[0]; for (int i = 1; i < indices.Length; i++) { index *= array.GetLength(i); index += indices[i]; } return(index); }
public static void CopyTo <T>(this IPinnedArray <T> src, IPinnedArray <T> dst, int[] srcIndices, int[] dstIndices, int count) where T : struct { if (srcIndices == null) { throw new ArgumentNullException(nameof(srcIndices)); } if (dstIndices == null) { throw new ArgumentNullException(nameof(dstIndices)); } int srcIndex = src.GetIndex(srcIndices); int dstIndex = dst.GetIndex(dstIndices); src.CopyTo(dst, srcIndex, dstIndex, count); }
static void doBandStop(IPinnedArray <Complex> trans, int[] passIndexRange) { var j1 = passIndexRange[0]; var j2 = passIndexRange[1]; var lenPositive = trans.Length / 2 + trans.Length % 2; for (int i = j1; i <= j2; i++) { trans[i] = 0; } j1 = trans.Length - j1; j2 = trans.Length - j2; for (int i = j2; i <= j1; i++) { trans[i] = 0; } }
protected override void VerifyRankAndSize(IPinnedArray <double> bufferReal, IPinnedArray <Complex> bufferComplex) { if (bufferReal.Rank != bufferComplex.Rank) { throw new ArgumentException($"{nameof(bufferReal)} and {nameof(bufferComplex)} must have the same rank and size."); } for (int i = 0; i < bufferReal.Rank - 1; i++) { if (bufferReal.GetLength(i) != bufferComplex.GetLength(i)) { throw new ArgumentException($"Lenght of {nameof(bufferComplex)} must be equal to n[0]*...*(n[n.Length - 1] / 2 + 1) with n being the size of {nameof(bufferReal)}."); } } if (bufferReal.GetLength(bufferReal.Rank - 1) / 2 + 1 != bufferComplex.GetLength(bufferReal.Rank - 1)) { throw new ArgumentException($"Lenght of {nameof(bufferComplex)} must be equal to n[0]*...*(n[n.Length - 1] / 2 + 1) with n being the size of {nameof(bufferReal)}."); } }
static void Transform(IPinnedArray <Complex> input, IPinnedArray <Complex> output, DftDirection direction, PlannerFlags plannerFlags, int nThreads) { if ((plannerFlags & PlannerFlags.Estimate) == PlannerFlags.Estimate) { using (var plan = FftwPlanC2C.Create(input, output, direction, plannerFlags, nThreads)) { plan.Execute(); return; } } using (var plan = FftwPlanC2C.Create(input, output, direction, plannerFlags | PlannerFlags.WisdomOnly, nThreads)) { if (plan != null) { plan.Execute(); return; } } /// If with <see cref="PlannerFlags.WisdomOnly"/> no plan can be created /// and <see cref="PlannerFlags.Estimate"/> is not specified, we use /// a different buffer to avoid overwriting the input if (input != output) { using (var plan = FftwPlanC2C.Create(output, output, input.Rank, input.GetSize(), direction, plannerFlags, nThreads)) { input.CopyTo(output); plan.Execute(); } } else { using (var bufferContainer = _bufferPool.RequestBuffer(input.Length * Marshal.SizeOf <Complex>() + MemoryAlignment)) using (var buffer = new AlignedArrayComplex(bufferContainer.Buffer, MemoryAlignment, input.GetSize())) using (var plan = FftwPlanC2C.Create(buffer, buffer, input.Rank, input.GetSize(), direction, plannerFlags, nThreads)) { input.CopyTo(plan.Input); plan.Execute(); plan.Output.CopyTo(output, 0, 0, input.Length); } } }
internal protected FftwPlan(IPinnedArray <T1> buffer1, IPinnedArray <T2> buffer2, int rank, int[] n, bool verifyRankAndSize, DftDirection direction, PlannerFlags plannerFlags, int nThreads) { if (!FftwInterop.IsAvailable) { throw new InvalidOperationException($"{nameof(FftwInterop.IsAvailable)} returns false."); } if (buffer1.IsDisposed) { throw new ObjectDisposedException(nameof(buffer1)); } if (buffer2.IsDisposed) { throw new ObjectDisposedException(nameof(buffer2)); } if (verifyRankAndSize) { VerifyRankAndSize(buffer1, buffer2); } else { VerifyMinSize(buffer1, buffer2, n); } if (nThreads < 1) { nThreads = Environment.ProcessorCount; } _buffer1 = buffer1; _buffer2 = buffer2; _plan = IntPtr.Zero; lock (FftwInterop.Lock) { FftwInterop.fftw_plan_with_nthreads(nThreads); _plan = GetPlan(rank, n, _buffer1.Pointer, _buffer2.Pointer, direction, plannerFlags); } }
FftwPlanC2C(IPinnedArray <Complex> input, IPinnedArray <Complex> output, int rank, int[] n, bool verifyRankAndSize, DftDirection direction, PlannerFlags plannerFlags, int nThreads) : base(input, output, rank, n, verifyRankAndSize, direction, plannerFlags, nThreads) { }
protected abstract void VerifyRankAndSize(IPinnedArray <T1> input, IPinnedArray <T2> output);
/// <summary> /// Performs a complex-to-complex inverse fast fourier transformation. The dimension is inferred from the input (<see cref="Array{T}.Rank"/>). /// </summary> /// <seealso cref="http://www.fftw.org/fftw3_doc/Complex-One_002dDimensional-DFTs.html#Complex-One_002dDimensional-DFTs"/> /// <seealso cref="http://www.fftw.org/fftw3_doc/Complex-Multi_002dDimensional-DFTs.html#Complex-Multi_002dDimensional-DFTs"/> public static void IFFT(IPinnedArray <Complex> input, IPinnedArray <Complex> output, PlannerFlags plannerFlags = PlannerFlags.Default, int nThreads = 1) => Transform(input, output, DftDirection.Backwards, plannerFlags, nThreads);
FftwPlanRC(IPinnedArray <double> bufferReal, IPinnedArray <Complex> bufferComplex, int rank, int[] n, bool verifyRankAndSize, DftDirection direction, PlannerFlags plannerFlags, int nThreads) : base(bufferReal, bufferComplex, rank, n, verifyRankAndSize, direction, plannerFlags, nThreads) { }
public static void CopyTo <T>(this IPinnedArray <T> src, IPinnedArray <T> dst) where T : struct { src.CopyTo(dst, 0, 0, dst.Length); }
protected abstract void VerifyMinSize(IPinnedArray <T1> ipput, IPinnedArray <T2> output, int[] n);