Пример #1
0
        /// <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);
                    }
                }
            }
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        /// <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;
                }
            }
        }
Пример #7
0
        /// <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);
            }
        }
Пример #8
0
        /// <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);
        }
Пример #9
0
        // 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;
                }
            }
        }
Пример #10
0
        /// <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);
        }