/// <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); }