/// <summary>
        /// Forward Weyl-Heisenberg transform.
        /// </summary>
        /// <param name="A">Array</param>
        /// <returns>Array</returns>
        public Complex32[] Forward(Complex32[] A)
        {
            float[]      g0           = WeylHeisenbergTransform.GetPacket(this.window, A.Length);
            ZakTransform zakTransform = new ZakTransform(m);

            return(FastWeylHeisenbergTransform.WHT(A, zakTransform.Forward(g0), m));
        }
        /// <summary>
        /// Fast backward Weyl-Heisenberg transform.
        /// </summary>
        /// <param name="input">Array</param>
        /// <param name="g0">Function</param>
        /// <param name="M">Number of frequency shifts</param>
        /// <returns>Array</returns>
        public static Complex32[] IWHT(Complex32[] input, float[] g0, int M)
        {
            // The function implements a fast Weil-Heisenberg direct transformation algorithm,
            // stated in the following articles:
            // A. Vahlin, "EFFICIENT ALGORITHMS FOR MODULATION AND DEMODULATION IN OFDM-SYSTEMS" [1].
            // V.M. Asiryan, V.P. Volchkov, "EFFECTIVE IMPLEMENTATION OF THE DIRECT TRANSFORMATION OF WEIL-HEISENBERG" [2].
            // The algorithm is computationally efficient for large M.

            int N = input.Length, L = N / M, M2 = M / 2, M4 = M2 / 2;

            Complex32[] output = new Complex32[N];
            Complex32[,] A1 = new Complex32[L, M];
            Complex32[,] B1 = new Complex32[L, M];
            Complex32[] exp    = FastWeylHeisenbergTransform.GetRotation(M);
            Complex32   s;
            int         n, k, l;

            for (k = 0; k < M; k++)
            {
                for (l = 0; l < L; l++)
                {
                    s = input[k + l * M];

                    A1[l, k] = s.Real;
                    B1[l, k] = s.Imag;
                }
            }

            Complex32[,] Za = new Complex32[L, M2];
            Complex32[,] Zb = new Complex32[L, M2];

            for (k = 0; k < M2; k++)
            {
                for (l = 0; l < L; l++)
                {
                    Za[l, k] = A1[l, k * 2] + Maths.I * A1[l, k * 2 + 1];
                    Zb[l, k] = B1[l, k * 2] + Maths.I * B1[l, k * 2 + 1];
                }
            }

            Za = Matrice.Conjugate(FFT.Backward(Za));
            Zb = Matrice.Conjugate(FFT.Backward(Zb));

            Complex32 a0, a1, b0, b1;
            Complex32 x, y, u, v;

            for (k = 0; k < M2; k++)
            {
                for (l = 0; l < L; l++)
                {
                    a0 = Za[l, k]; a1 = Za[l, Maths.Mod(M - k, M2)].Conjugate;

                    x  = 1.0 / (2) * (a0 + a1);
                    y  = 1.0 / (2 * Maths.I) * (a0 - a1);
                    y *= exp[k];

                    A1[l, k]      = x + y;
                    A1[l, k + M2] = x - y;

                    b0 = Zb[l, k]; b1 = Zb[l, Maths.Mod(M - k, M2)].Conjugate;

                    u  = 1.0 / (2) * (b0 + b1);
                    v  = 1.0 / (2 * Maths.I) * (b0 - b1);
                    v *= exp[k];

                    B1[l, k]      = u + v;
                    B1[l, k + M2] = u - v;
                }
            }

            for (l = 0; l < L; l++)
            {
                for (n = 0; n < N; n++)
                {
                    output[n] += A1[l, Maths.Mod(n - M4, M)] * g0[Maths.Mod(n - l * M, N)] - Maths.I
                                 * B1[l, Maths.Mod(n - M4, M)] * g0[Maths.Mod(n - l * M + M2, N)];
                }
            }

            return(output);
        }
        /// <summary>
        /// Fast forward Weyl-Heisenberg transform.
        /// </summary>
        /// <param name="input">Array</param>
        /// <param name="g0">Function</param>
        /// <param name="M">Number of frequency shifts</param>
        /// <returns>Array</returns>
        public static Complex32[] WHT(Complex32[] input, float[] g0, int M)
        {
            // The function implements a fast Weil-Heisenberg direct transformation algorithm,
            // stated in the following articles:
            // A. Vahlin, "EFFICIENT ALGORITHMS FOR MODULATION AND DEMODULATION IN OFDM-SYSTEMS" [1].
            // V.M. Asiryan, V.P. Volchkov, "EFFECTIVE IMPLEMENTATION OF THE DIRECT TRANSFORMATION OF WEIL-HEISENBERG" [2].
            // The algorithm is computationally efficient for large M.

            int N = input.Length, L = N / M, M2 = M / 2, M4 = M2 / 2;

            Complex32[] output = new Complex32[N];
            Complex32[] exp    = FastWeylHeisenbergTransform.GetRotation(M);

            Complex32[,] s0 = new Complex32[M, L];
            Complex32[,] a0 = new Complex32[M, L];
            Complex32[,] b0 = new Complex32[M, L];
            Complex32[,] A0 = new Complex32[L, M];
            Complex32[,] B0 = new Complex32[L, M];
            Complex32[,] A1 = new Complex32[L, M2];
            Complex32[,] B1 = new Complex32[L, M2];
            Complex32 c1re, c2re;
            Complex32 c1im, c2im;
            int       k, i, j, u, n, m, l;

            for (m = 0; m < M; m++)
            {
                for (n = 0; n < L; n++)
                {
                    u = n * M;
                    i = Maths.Mod(m + M4 + u, N);
                    j = Maths.Mod(m - M4 + u, N);
                    k = Maths.Mod(-m - M4 - u, N);

                    s0[m, n] = input[k];
                    a0[m, n] = g0[i];
                    b0[m, n] = g0[j];
                }
            }

            for (l = 0; l < L; l++)
            {
                for (n = 0; n < L; n++)
                {
                    k = Maths.Mod(n - l, L);

                    for (m = 0; m < M; m++)
                    {
                        A0[l, m] += a0[m, n] * s0[m, k];
                        B0[l, m] += b0[m, n] * s0[m, k];
                    }
                }
            }

            Complex32 x, y, z, w;

            for (l = 0; l < L; l++)
            {
                for (m = 0; m < M2; m++)
                {
                    x = A0[l, m];
                    y = A0[l, m + M2];
                    z = A0[l, M2 - m].Conjugate;
                    w = A0[l, Maths.Mod(M - m, M)].Conjugate;

                    c1re = x + y + z + w;
                    c2re = x - y - z + w;

                    x = B0[l, m];
                    y = B0[l, m + M2];
                    z = B0[l, M2 - m].Conjugate;
                    w = B0[l, Maths.Mod(M - m, M)].Conjugate;

                    c1im = x + y - z - w;
                    c2im = x - y + z - w;

                    A1[l, m] = 1.0 / (2) * (c1re + Maths.I * c2re * exp[m]);
                    B1[l, m] = 1.0 / (2 * Maths.I) * (c1im + Maths.I * c2im * exp[m]);
                }
            }

            A1 = FFT.Backward(Matrice.Conjugate(A1));
            B1 = FFT.Backward(Matrice.Conjugate(B1));

            for (k = 0; k < M2; k++)
            {
                for (l = 0; l < L; l++)
                {
                    i = l * M + 2 * k;
                    j = l * M + 2 * k + 1;

                    x = A1[l, k];
                    y = B1[l, k];

                    output[i] = x.Real + Maths.I * y.Real;
                    output[j] = x.Imag + Maths.I * y.Imag;
                }
            }

            return(output);
        }