/// <summary> /// Two dimensional Fast Fourier Transform. /// </summary> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <param name="stride">Image stride.</param> /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array /// is valid, but 15x15 is not.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public unsafe static void FFT2(ComplexF *data, int width, int height, int stride, Direction direction) { int k = height; int n = width; // check data size if ( (!AForge.Math.Tools.IsPowerOf2(k)) || (!AForge.Math.Tools.IsPowerOf2(n)) || (k < minLength) || (k > maxLength) || (n < minLength) || (n > maxLength) ) { throw new ArgumentException("Incorrect data length."); } // process rows ComplexF *dataPtr = data; //get row for (int i = 0; i < height; i++) { // transform it FourierTransform.FFT(dataPtr, n, direction); dataPtr += stride / sizeof(ComplexF); } // process columns dataPtr = data; //get column fixed(ComplexF *_col = new ComplexF[k]) { ComplexF *col = _col; for (int j = 0; j < height; j++) { // copy column ComplexF *dataColPtr = &dataPtr[j]; for (int i = 0; i < k; i++) { col[i] = *dataColPtr; dataColPtr += stride / sizeof(ComplexF); } // transform it FourierTransform.FFT(col, k, direction); // copy back dataColPtr = &dataPtr[j]; for (int i = 0; i < k; i++) { *dataColPtr = col[i]; dataColPtr += stride / sizeof(ComplexF); } } } }
public unsafe void AllOnes() { ComplexF *pThis = this.Data; var pThisfloat = (float *)pThis; int ComplexFSize = this.TotalSize * 2; for (int i = 0; i < ComplexFSize; i += 2) { pThisfloat[i] = 1f; } }
public unsafe static MatrixCF operator /(ComplexF val, MatrixCF mat) { var result = new MatrixCF(mat.NumRows, mat.NumCols); ComplexF *pResult = result.Data; ComplexF *pMat = mat.Data; for (int i = 0; i < result.TotalSize; i++) { pResult[i] = val / pMat[i]; } return(result); }
private unsafe static MatrixCF MultiplyByValue(MatrixCF mat, ComplexF val) { var result = new MatrixCF(mat.NumRows, mat.NumCols); ComplexF *pResult = result.Data; ComplexF *pMat = mat.Data; for (int i = 0; i < result.TotalSize; i++) { pResult[i] = pMat[i] * val; } return(result); }
public unsafe static MatrixCF operator /(MatrixCF mat1, MatrixCF mat2) { var result = new MatrixCF(mat1.NumRows, mat1.NumCols); ComplexF *pResult = result.Data; ComplexF *pMat1 = mat1.Data; ComplexF *pMat2 = mat2.Data; for (int i = 0; i < result.TotalSize; i++) { pResult[i] = pMat1[i] / pMat2[i]; } return(result); }
/// <summary> /// One dimensional Fast Fourier Transform. /// </summary> /// /// <param name="data">Data to transform.</param> /// <param name="length">Array length.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only, where <b>n</b> may vary in the [1, 14] range.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public unsafe static void FFT(ComplexF *data, int length, Direction direction) { int n = length; int m = AForge.Math.Tools.Log2(n); // reorder data first ReorderData(data, length); // compute FFT int tn = 1, tm; for (int k = 1; k <= m; k++) { ComplexF[] rotation = FourierTransform.GetComplexRotation(k, direction); tm = tn; tn <<= 1; for (int i = 0; i < tm; i++) { ComplexF t = rotation[i]; for (int even = i; even < n; even += tn) { int odd = even + tm; ComplexF *ce = &data[even]; ComplexF *co = &data[odd]; float tr = co->Re * t.Re - co->Im * t.Im; float ti = co->Re * t.Im + co->Im * t.Re; co->Re = ce->Re - tr; co->Im = ce->Im - ti; ce->Re += tr; ce->Im += ti; } } } if (direction == Direction.Backward) { for (int i = 0; i < n; i++) { data[i].Re /= n; data[i].Im /= n; } } }
/// <summary> /// Fills the current matrix with (pseudo-)random values from the specified interval. /// </summary> /// <param name="minReal">The minimum real value.</param> /// <param name="maxReal">The maximum real value.</param> /// <param name = "minImag">The minimum imaginary value.</param> /// <param name = "maxImag">The maximum imaginary value.</param> public unsafe void FillWithRandomValues(float minReal, float maxReal, float minImag, float maxImag) { var rnd = new Random(); float rangeReal = maxReal - minReal; float rangeImag = maxImag - minImag; ComplexF *pThis = this.Data; var pThisfloat = (float *)pThis; int ComplexFSize = this.TotalSize * 2; for (int i = 0; i < ComplexFSize; i += 2) { pThisfloat[i] = (float)(rnd.NextDouble() * rangeReal + minReal); pThisfloat[i + 1] = (float)(rnd.NextDouble() * rangeImag + minImag); } }
/// <summary> /// Computes the product of the current matrix and another matrix. /// </summary> /// <param name="mat">A matrix by which to multiply the current matrix.</param> /// <returns>A matrix that is the product of the input matrix and the other matrix.</returns> public unsafe MatrixCF Dot(MatrixCF mat) { var result = new MatrixCF(this.NumRows, mat.NumCols); ComplexF *pResult = result.Data; ComplexF *pThis = this.Data; ComplexF *pMat = mat.Data; for (int y = 0; y < this.NumRows; y++) { int i = y * this.NumCols; for (int x = 0; x < mat.NumCols; x++) { int j = x; var sum = new ComplexF(); for (int z = 0; z < this.NumCols; z++, j += mat.NumCols) { sum += pThis[i + z] * pMat[j]; } pResult[y * mat.NumCols + x] = sum; } } return(result); }
// Reorder data for FFT using private unsafe static void ReorderData(ComplexF *data, int length) { int len = length; // check data length if ((len < minLength) || (len > maxLength) || (!AForge.Math.Tools.IsPowerOf2(len))) { throw new ArgumentException("Incorrect data length."); } int[] rBits = GetReversedBits(AForge.Math.Tools.Log2(len)); for (int i = 0; i < len; i++) { int s = rBits[i]; if (s > i) { ComplexF t = data[i]; data[i] = data[s]; data[s] = t; } } }
/// <summary> /// Two dimensional Fast Fourier Transform. /// </summary> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <param name="stride">Image stride.</param> /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array /// is valid, but 15x15 is not.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public unsafe static void FFT2(ComplexF *data, int width, int height, int stride, Direction direction) { const int MIN_PATCH_SIZE = 32; //how much rows/columns should one thread process int k = height; int n = width; // check data size if ( (!AForge.Math.Tools.IsPowerOf2(k)) || (!AForge.Math.Tools.IsPowerOf2(n)) || (k < minLength) || (k > maxLength) || (n < minLength) || (n > maxLength) ) { throw new ArgumentException("Incorrect data length."); } // process rows var procRow = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, height), () => true, (_, __, area) => { ComplexF *dataPatchPtr = data + area.Y * stride / sizeof(ComplexF); //get row for (int i = 0; i < area.Height; i++) { // transform it FourierTransform.FFT(dataPatchPtr, n, direction); dataPatchPtr += stride / sizeof(ComplexF); } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true*/ } ); // process columns //(y and x are swaped => proc thinks it is diving horizontal pacthes but instead we are using them as vertical ones) var procCol = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, width), () => true, (_, __, area) => { ComplexF *dataPatchPtr = &data[area.Y]; //get column fixed(ComplexF * _col = new ComplexF[k]) { ComplexF *col = _col; for (int j = 0; j < area.Height; j++) { // copy column ComplexF *dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { col[i] = *dataColPtr; dataColPtr += stride / sizeof(ComplexF); } // transform it FourierTransform.FFT(col, k, direction); // copy back dataColPtr = &dataPatchPtr[j]; for (int i = 0; i < k; i++) { *dataColPtr = col[i]; dataColPtr += stride / sizeof(ComplexF); } } } }, new ParallelOptions2D { ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE /*,ForceSequential = true */ } ); procRow.Process(true); procCol.Process(true); }