/// <summary>
        /// Calculate the Haar forward fast wavelet transform in 1-dimension.
        /// </summary>
        /// <param name="signal">Signal to compute (must be power two)</param>
        public static void Haar_forward_FWT_1d(ref double[] signal)
        {
            int m;
            int npts;

            npts = (int)DSPUtilities.NextPowerOfTwo((int)signal.Length);
            for (m = signal.Length - 1; m >= 0; m--)
            {
                Wavelet.Haar_forward_pass_1d(m + 1, ref signal);
                //Wavelet.Haar_ip_FFWT_1d(m + 1, ref signal);
            }

            /*int i = 0;
             * int w = signal.Length;
             * double[] vecp = new double[signal.Length];
             * for (i = 0; i < signal.Length; i++)
             *  vecp[i] = 0;
             * //while (w > 1)
             * // {
             *  w /= 2;
             *  for (i = 0; i < w; i++)
             *  {
             *      vecp[i] = (signal[2 * i] + signal[2 * i + 1]) / Math.Sqrt(2.0);
             *      vecp[i + w] = (signal[2 * i] - signal[2 * i + 1]) / Math.Sqrt(2.0);
             *  }
             *  for (i = 0; i < (w * 2); i++)
             *      signal[i] = vecp[i];
             * // }*/
        }
        /// <summary>
        /// Calculate one iteration of the Haar inverse FWT in 2-dimensions.
        /// </summary>
        /// <param name="signal">Signal to compute (must be power two)</param>

        /* static void Haar_inverse_pass_2d(int n, ref double[][] signal)
         * {
         *   int i, j;
         *   int npts;
         *
         *   npts = (int) Utilities.NextPowerOfTwo((int) n);
         *   for (i = 0; i < npts; i++)
         *   {
         *       Wavelet.Haar_inverse_pass_1d(n, ref signal[i]);
         *   }
         *   double[] c = new double[npts];
         *   for (j = 0; j < npts; j++)
         *   {
         *       for (i = 0; i < npts; i++)
         *           c[i] = signal[i][j];
         *       Wavelet.Haar_inverse_pass_1d(n, ref c);
         *       for (i = 0; i < npts; i++)
         *           signal[i][j] = c[i];
         *   }
         * }*/
        /// <summary>
        /// Calculate the Haar inverse fast wavelet transform in 2-dimensions.
        /// </summary>
        /// <param name="signal">Signal to compute (must be power two)</param>
        public static void Haar_inverse_FWT_2d(int width, int height, ref double[] signal)
        {
            /*for (int m = 1; m <= signal.Length; m++)
             * {
             *  Haar_inverse_pass_2d(m, ref signal);
             * }*/
            double[] row    = new double[DSPUtilities.NextPowerOfTwo((int)width)];
            double[] column = new double[DSPUtilities.NextPowerOfTwo((int)height)];
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    column[y] = signal[x + (y * width)];
                }
                Wavelet.Haar_inverse_FWT_1d(ref column);
                for (int y = 0; y < height; y++)
                {
                    signal[x + (y * width)] = column[y];
                }
            }
            for (int y = 0; y < height; y++)
            {
                Array.Copy(signal, (int)(y * width), row, 0, (int)width);
                Wavelet.Haar_inverse_FWT_1d(ref row);
                Array.Copy(row, 0, signal, (int)(y * width), (int)width);
            }
        }
        /// <summary>
        /// Calculate Haar in-place inverse fast wavelet transform in 1-dimension.
        /// </summary>
        /// <param name="n">Elements to compute</param>
        /// <param name="signal">Signal to compute (must be power two)</param>
        static void Haar_ip_IFWT_1d(int n, ref double[] signal)
        {
            double a0;
            double a1;
            int    i;
            int    j;
            int    k;
            int    l;
            int    m;

            i = (int)DSPUtilities.NextPowerOfTwo((int)(n - 1));
            j = 2 * i;
            m = 1;
            for (l = 1; l <= n; l++)
            {
                //System.Diagnostics.Debug.WriteLine("l = " + l);
                for (k = 0; k < m; k++)
                {
                    a0                = signal[j * k] + signal[j * k + i];
                    a1                = signal[j * k] - signal[j * k + i];
                    signal[j * k]     = a0;
                    signal[j * k + i] = a1;
                }
                i /= 2;
                j /= 2;
                m *= 2;
            }
        }
        // Haar Wavelet

        /// <summary>
        /// Calculate Haar in-place forward fast wavelet transform in 1-dimension.
        /// </summary>
        /// <param name="n">Elements to compute</param>
        /// <param name="signal">Signal to compute</param>
        static void Haar_ip_FFWT_1d(int n, ref double[] signal)
        {
            double a;
            double c;
            int    i;
            int    j;
            int    k;
            int    l;
            int    m;

            i = 1;
            j = 2;
            m = (int)DSPUtilities.NextPowerOfTwo((int)n);
            for (l = n - 1; l >= 0; l--)
            {
                //System.Diagnostics.Debug.WriteLine("l = " + l);
                m /= 2;
                for (k = 0; k < m; k++)
                {
                    a                 = (signal[j * k] + signal[j * k + i]) / 2.0;
                    c                 = (signal[j * k] - signal[j * k + i]) / 2.0;
                    signal[j * k]     = a;
                    signal[j * k + i] = c;
                }
                i *= 2;
                j *= 2;
            }
        }
        /// <summary>
        /// Calculate one iteration of the Haar inverse FWT in 1-dimension.
        /// </summary>
        /// <param name="n">Elements to compute</param>
        /// <param name="signal">Signal to compute (must be power two)</param>
        static void Haar_inverse_pass_1d(int n, ref double[] signal)
        {
            int i;
            int npts = (int)DSPUtilities.NextPowerOfTwo((int)n);

            double[] r = new double[npts];
            for (i = 0; i < npts / 2; i++)
            {
                r[2 * i]     = signal[i] + signal[i + npts / 2];
                r[2 * i + 1] = signal[i] - signal[i + npts / 2];
            }
            for (i = 0; i < npts; i++)
            {
                signal[i] = r[i];
            }
        }
        /// <summary>
        /// Calculate one iteration of the Haar forward FWT in 1-dimension.
        /// </summary>
        /// <param name="n">Elements to compute</param>
        /// <param name="signal">Signal to compute (must be power two)</param>
        static void Haar_forward_pass_1d(int n, ref double[] signal)
        {
            int i;
            int npts;

            npts = (int)DSPUtilities.NextPowerOfTwo((int)n);
            double[] a = new double[npts / 2];
            double[] c = new double[npts / 2];
            for (i = 0; i < npts / 2; i++)
            {
                a[i] = (signal[2 * i] + signal[2 * i + 1]) / 2.0;
                c[i] = (signal[2 * i] - signal[2 * i + 1]) / 2.0;
            }
            for (i = 0; i < npts / 2; i++)
            {
                signal[i]            = a[i];
                signal[i + npts / 2] = c[i];
            }
        }
        /// <summary>
        /// Compute FFT
        /// </summary>
        /// <param name="NumSamples">NumSamples Number of samples (must be power two)</param>
        /// <param name="pRealIn">Real samples</param>
        /// <param name="pImagIn">Imaginary (optional, may be null)</param>
        /// <param name="pRealOut">Real coefficient output</param>
        /// <param name="pImagOut">Imaginary coefficient output</param>
        /// <param name="bInverseTransform">bInverseTransform when true, compute Inverse FFT</param>
        public static void Compute(int NumSamples, IEnumerable <double> pRealIn, Double[] pImagIn,
                                   Double[] pRealOut, Double[] pImagOut, Boolean bInverseTransform)
        {
            int    NumBits; /* Number of bits needed to store indices */
            int    i, j, k, n;
            int    BlockSize, BlockEnd;
            double angle_numerator = 2.0 * DSPUtilities.DDC_PI;
            double tr, ti;     /* temp real, temp imaginary */

            if (pRealIn == null || pRealOut == null || pImagOut == null)
            {
                // error
                throw new ArgumentNullException("Null argument");
            }
            if (!DSPUtilities.IsPowerOfTwo((int)NumSamples))
            {
                // error
                throw new ArgumentException("Number of samples must be power of 2");
            }
            if (pRealIn.Count() < NumSamples || (pImagIn != null && pImagIn.Length < NumSamples) ||
                pRealOut.Length < NumSamples || pImagOut.Length < NumSamples)
            {
                // error
                throw new ArgumentException("Invalid Array argument detected");
            }
            if (bInverseTransform)
            {
                angle_numerator = -angle_numerator;
            }
            NumBits = NumberOfBitsNeeded(NumSamples);

            /*
            **   Do simultaneous data copy and bit-reversal ordering into outputs...
            */
            for (i = 0; i < NumSamples; i++)
            {
                j           = ReverseBits(i, NumBits);
                pRealOut[j] = pRealIn.ElementAt(i);
                pImagOut[j] = (double)((pImagIn == null) ? 0.0 : pImagIn[i]);
            }

            /*
            **   Do the FFT itself...
            */
            BlockEnd = 1;
            for (BlockSize = 2; BlockSize <= NumSamples; BlockSize <<= 1)
            {
                double delta_angle = angle_numerator / (double)BlockSize;
                double sm2 = Math.Sin(-2 * delta_angle);
                double sm1 = Math.Sin(-delta_angle);
                double cm2 = Math.Cos(-2 * delta_angle);
                double cm1 = Math.Cos(-delta_angle);
                double w = 2 * cm1;
                double ar0, ar1, ar2;
                double ai0, ai1, ai2;
                for (i = 0; i < NumSamples; i += BlockSize)
                {
                    ar2 = cm2;
                    ar1 = cm1;
                    ai2 = sm2;
                    ai1 = sm1;
                    for (j = i, n = 0; n < BlockEnd; j++, n++)
                    {
                        ar0          = w * ar1 - ar2;
                        ar2          = ar1;
                        ar1          = ar0;
                        ai0          = w * ai1 - ai2;
                        ai2          = ai1;
                        ai1          = ai0;
                        k            = j + BlockEnd;
                        tr           = ar0 * pRealOut[k] - ai0 * pImagOut[k];
                        ti           = ar0 * pImagOut[k] + ai0 * pRealOut[k];
                        pRealOut[k]  = (pRealOut[j] - tr);
                        pImagOut[k]  = (pImagOut[j] - ti);
                        pRealOut[j] += (tr);
                        pImagOut[j] += (ti);
                    }
                }
                BlockEnd = BlockSize;
            }

            /*
            **   Need to normalize if inverse transform...
            */
            if (bInverseTransform)
            {
                double denom = (double)(NumSamples);
                for (i = 0; i < NumSamples; i++)
                {
                    pRealOut[i] /= denom;
                    pImagOut[i] /= denom;
                }
            }
        }