diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 37081d225..a79b75b0a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -25,7 +25,6 @@ */ #include -#include #include #include #include @@ -1985,7 +1984,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { /* 0. Load channel matrix */ - __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + __m256 h00 = _mm256_setr_ps(crealf(h[0][0][j]), cimagf(h[0][0][j]), crealf(h[0][0][j + PMI_SEL_PRECISION]), cimagf(h[0][0][j + PMI_SEL_PRECISION]), @@ -1993,7 +1992,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); - __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + __m256 h01 = _mm256_setr_ps(crealf(h[1][0][j]), cimagf(h[1][0][j]), crealf(h[1][0][j + PMI_SEL_PRECISION]), cimagf(h[1][0][j + PMI_SEL_PRECISION]), @@ -2001,7 +2000,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); - __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + __m256 h10 = _mm256_setr_ps(crealf(h[0][1][j]), cimagf(h[0][1][j]), crealf(h[0][1][j + PMI_SEL_PRECISION]), cimagf(h[0][1][j + PMI_SEL_PRECISION]), @@ -2009,7 +2008,7 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); - __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + __m256 h11 = _mm256_setr_ps(crealf(h[1][1][j]), cimagf(h[1][1][j]), crealf(h[1][1][j + PMI_SEL_PRECISION]), cimagf(h[1][1][j + PMI_SEL_PRECISION]), @@ -2030,13 +2029,13 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_CONJ_PS(h11)); break; case 2: - a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); - a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); - break; - default: a0 = _mm256_sub_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); a1 = _mm256_sub_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); break; + default: + a0 = _mm256_add_ps(_MM256_CONJ_PS(h00), _MM256_MULJ_PS(_MM256_CONJ_PS(h01))); + a1 = _mm256_add_ps(_MM256_CONJ_PS(h10), _MM256_MULJ_PS(_MM256_CONJ_PS(h11))); + break; } /* 2. B = W' * H' * H = A * H */ @@ -2058,10 +2057,10 @@ int srslte_precoding_pmi_select_1l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c = _mm256_sub_ps(b0, b1); break; case 2: - c = _mm256_sub_ps(b0, _MM256_MULJ_PS(b1)); + c = _mm256_add_ps(b0, _MM256_MULJ_PS(b1)); break; case 3: - c = _mm256_add_ps(b0, _MM256_MULJ_PS(b1)); + c = _mm256_sub_ps(b0, _MM256_MULJ_PS(b1)); break; default: return SRSLTE_ERROR; @@ -2216,7 +2215,9 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT float max_sinr = 0.0; uint32_t i, count; - __m128 sse_noise_estimate = (__m128) {noise_estimate, 0.0f, noise_estimate, 0.0f}; + __m128 sse_noise_estimate = _mm_setr_ps(noise_estimate, 0.0f, noise_estimate, 0.0f); + __m128 sse_norm = _mm_set1_ps(0.25f); + __m128 sse_ones = _mm_set1_ps(1.0f); for (i = 0; i < 2; i++) { sinr_list[i] = 0; @@ -2224,22 +2225,22 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 2 + 1; j += PMI_SEL_PRECISION * 2) { /* 0. Load channel matrix */ - __m128 h00 = _mm_set_ps(crealf(h[0][0][j]), - cimagf(h[0][0][j]), - crealf(h[0][0][j + PMI_SEL_PRECISION]), - cimagf(h[0][0][j + PMI_SEL_PRECISION])); - __m128 h01 = _mm_set_ps(crealf(h[1][0][j]), - cimagf(h[1][0][j]), - crealf(h[1][0][j + PMI_SEL_PRECISION]), - cimagf(h[1][0][j + PMI_SEL_PRECISION])); - __m128 h10 = _mm_set_ps(crealf(h[0][1][j]), - cimagf(h[0][1][j]), - crealf(h[0][1][j + PMI_SEL_PRECISION]), - cimagf(h[0][1][j + PMI_SEL_PRECISION])); - __m128 h11 = _mm_set_ps(crealf(h[1][1][j]), - cimagf(h[1][1][j]), - crealf(h[1][1][j + PMI_SEL_PRECISION]), - cimagf(h[1][1][j + PMI_SEL_PRECISION])); + __m128 h00 = _mm_setr_ps(crealf(h[0][0][j]), + cimagf(h[0][0][j]), + crealf(h[0][0][j + PMI_SEL_PRECISION]), + cimagf(h[0][0][j + PMI_SEL_PRECISION])); + __m128 h01 = _mm_setr_ps(crealf(h[1][0][j]), + cimagf(h[1][0][j]), + crealf(h[1][0][j + PMI_SEL_PRECISION]), + cimagf(h[1][0][j + PMI_SEL_PRECISION])); + __m128 h10 = _mm_setr_ps(crealf(h[0][1][j]), + cimagf(h[0][1][j]), + crealf(h[0][1][j + PMI_SEL_PRECISION]), + cimagf(h[0][1][j + PMI_SEL_PRECISION])); + __m128 h11 = _mm_setr_ps(crealf(h[1][1][j]), + cimagf(h[1][1][j]), + crealf(h[1][1][j + PMI_SEL_PRECISION]), + cimagf(h[1][1][j + PMI_SEL_PRECISION])); /* 1. B = W'* H' */ __m128 a00, a01, a10, a11; @@ -2284,38 +2285,38 @@ int srslte_precoding_pmi_select_2l_sse(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT default: return SRSLTE_ERROR; } - c00 = _mm_mul_ps(c00, _mm_set1_ps(0.25f)); - c01 = _mm_mul_ps(c01, _mm_set1_ps(0.25f)); - c10 = _mm_mul_ps(c10, _mm_set1_ps(0.25f)); - c11 = _mm_mul_ps(c11, _mm_set1_ps(0.25f)); + c00 = _mm_mul_ps(c00, sse_norm); + c01 = _mm_mul_ps(c01, sse_norm); + c10 = _mm_mul_ps(c10, sse_norm); + c11 = _mm_mul_ps(c11, sse_norm); /* 4. C += noise * I */ c00 = _mm_add_ps(c00, sse_noise_estimate); c11 = _mm_add_ps(c11, sse_noise_estimate); /* 5. detC */ - __m128 detC = _mm_sub_ps(_MM_PROD_PS(c00, c11), _MM_PROD_PS(c01, c10)); + __m128 detC = srslte_algebra_2x2_det_sse(c00, c01, c10, c11); __m128 inv_detC = srslte_algebra_cf_recip_sse(detC); + inv_detC = _mm_mul_ps(sse_noise_estimate, inv_detC); __m128 den0 = _MM_PROD_PS(c00, inv_detC); __m128 den1 = _MM_PROD_PS(c11, inv_detC); - __m128 gamma0 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den0), _mm_set1_ps(1.0f)); - __m128 gamma1 = _mm_sub_ps(srslte_algebra_cf_recip_sse(den1), _mm_set1_ps(1.0f)); + __m128 gamma0 = _mm_sub_ps(_mm_rcp_ps(den0), sse_ones); + __m128 gamma1 = _mm_sub_ps(_mm_rcp_ps(den1), sse_ones); /* Add for averaging */ - __m128 sum = _MM_SWAP(_mm_add_ps(gamma0, gamma1)); - __m128 sinr_sse = _mm_hadd_ps(sum, sum); + __m128 sinr_sse = _mm_add_ps(gamma0, gamma1); __attribute__((aligned(128))) float sinr[4]; _mm_store_ps(sinr, sinr_sse); - sinr_list[i] += sinr[0]; + sinr_list[i] += sinr[0] + sinr[2]; count += 2; } /* Divide average by noise */ - sinr_list[i] /= (2 * count * noise_estimate); + sinr_list[i] /= 2 * count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; @@ -2339,7 +2340,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT __m256 avx_noise_estimate = _mm256_setr_ps(noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f, noise_estimate, 0.0f); - __m256 avx_norm = _mm256_set1_ps(0.5f); + __m256 avx_norm = _mm256_set1_ps(0.25f); __m256 avx_ones = _mm256_set1_ps(1.0f); for (i = 0; i < 2; i++) { @@ -2348,7 +2349,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT for (uint32_t j = 0; j < nof_symbols - PMI_SEL_PRECISION * 4 + 1; j += PMI_SEL_PRECISION * 4) { /* 0. Load channel matrix */ - __m256 h00 = _mm256_set_ps(crealf(h[0][0][j]), + __m256 h00 = _mm256_setr_ps(crealf(h[0][0][j]), cimagf(h[0][0][j]), crealf(h[0][0][j + PMI_SEL_PRECISION]), cimagf(h[0][0][j + PMI_SEL_PRECISION]), @@ -2356,7 +2357,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][0][j + PMI_SEL_PRECISION * 2]), crealf(h[0][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][0][j + PMI_SEL_PRECISION * 3])); - __m256 h01 = _mm256_set_ps(crealf(h[1][0][j]), + __m256 h01 = _mm256_setr_ps(crealf(h[1][0][j]), cimagf(h[1][0][j]), crealf(h[1][0][j + PMI_SEL_PRECISION]), cimagf(h[1][0][j + PMI_SEL_PRECISION]), @@ -2364,7 +2365,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[1][0][j + PMI_SEL_PRECISION * 2]), crealf(h[1][0][j + PMI_SEL_PRECISION * 3]), cimagf(h[1][0][j + PMI_SEL_PRECISION * 3])); - __m256 h10 = _mm256_set_ps(crealf(h[0][1][j]), + __m256 h10 = _mm256_setr_ps(crealf(h[0][1][j]), cimagf(h[0][1][j]), crealf(h[0][1][j + PMI_SEL_PRECISION]), cimagf(h[0][1][j + PMI_SEL_PRECISION]), @@ -2372,7 +2373,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT cimagf(h[0][1][j + PMI_SEL_PRECISION * 2]), crealf(h[0][1][j + PMI_SEL_PRECISION * 3]), cimagf(h[0][1][j + PMI_SEL_PRECISION * 3])); - __m256 h11 = _mm256_set_ps(crealf(h[1][1][j]), + __m256 h11 = _mm256_setr_ps(crealf(h[1][1][j]), cimagf(h[1][1][j]), crealf(h[1][1][j + PMI_SEL_PRECISION]), cimagf(h[1][1][j + PMI_SEL_PRECISION]), @@ -2399,10 +2400,6 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT default: return SRSLTE_ERROR; } - a00 = _mm256_mul_ps(a00, avx_norm); - a01 = _mm256_mul_ps(a01, avx_norm); - a10 = _mm256_mul_ps(a10, avx_norm); - a11 = _mm256_mul_ps(a11, avx_norm); /* 2. B = W' * H' * H = A * H */ #ifdef LV_HAVE_FMA @@ -2445,18 +2442,15 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT c11 = _mm256_add_ps(c11, avx_noise_estimate); /* 5. detC */ -#ifdef LV_HAVE_FMA - __m256 detC = _MM256_PROD_SUB_PS(c00, c11, _MM256_PROD_PS(c01, c10)); -#else - __m256 detC = _mm256_sub_ps(_MM256_PROD_PS(c00, c11), _MM256_PROD_PS(c01, c10)); -#endif /* LV_HAVE_FMA */ + __m256 detC = srslte_algebra_2x2_det_avx(c00, c01, c10, c11); __m256 inv_detC = srslte_algebra_cf_recip_avx(detC); + inv_detC = _mm256_mul_ps(avx_noise_estimate, inv_detC); __m256 den0 = _MM256_PROD_PS(c00, inv_detC); __m256 den1 = _MM256_PROD_PS(c11, inv_detC); - __m256 gamma0 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den0), avx_ones); - __m256 gamma1 = _mm256_sub_ps(srslte_algebra_cf_recip_avx(den1), avx_ones); + __m256 gamma0 = _mm256_sub_ps(_mm256_rcp_ps(den0), avx_ones); + __m256 gamma1 = _mm256_sub_ps(_mm256_rcp_ps(den1), avx_ones); /* Add for averaging */ __m256 sinr_avx = _mm256_permute_ps(_mm256_add_ps(gamma0, gamma1), 0b00101000); @@ -2469,7 +2463,7 @@ int srslte_precoding_pmi_select_2l_avx(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORT } /* Divide average by noise */ - sinr_list[i] /= 2 * count * noise_estimate; + sinr_list[i] /= 2 * count; if (sinr_list[i] > max_sinr) { max_sinr = sinr_list[i]; diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index 2397bfc49..cae668d9e 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -69,4 +69,13 @@ add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 - add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse) add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse) +######################################################################## +# PMI SELECT TEST +######################################################################## + +add_executable(pmi_select_test pmi_select_test.c) +target_link_libraries(pmi_select_test srslte_phy) + +add_test(pmi_select_test pmi_select_test) + diff --git a/lib/src/phy/mimo/test/pmi_select_test.c b/lib/src/phy/mimo/test/pmi_select_test.c new file mode 100644 index 000000000..30d358e37 --- /dev/null +++ b/lib/src/phy/mimo/test/pmi_select_test.c @@ -0,0 +1,144 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/mimo/precoding.h" +#include "pmi_select_test.h" +#include "srslte/phy/utils/debug.h" + +int main(int argc, char **argv) { + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + float noise_estimate; + float sinr_1l[SRSLTE_MAX_CODEBOOKS]; + float sinr_2l[SRSLTE_MAX_CODEBOOKS]; + uint32_t pmi[2]; + uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM); + int ret = SRSLTE_ERROR; + + /* Allocate channels */ + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); + if (!h[i][j]) { + goto clean; + } + bzero(h[i][j], sizeof(cf_t) * nof_symbols); + } + } + + for (int c = 0; c < PMI_SELECT_TEST_NOF_CASES; c++) { + pmi_select_test_case_gold_t *gold = &pmi_select_test_case_gold[c]; + + /* Set channel */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + cf_t hij = gold->h[i][j]; + + for (int k = 0; k < nof_symbols; k++) { + h[i][j][k] = hij; + } + } + } + + /* Set noise estimate */ + noise_estimate = gold->n; + + /* PMI select for 1 layer */ + ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 1, &pmi[0], sinr_1l); + if (ret < 0) { + ERROR("During PMI selection for 1 layer"); + goto clean; + } + + /* Check SINR for 1 layer */ + for (int i = 0; i < ret; i++) { + if (fabsf(gold->snri_1l[i] - sinr_1l[i]) > 0.1) { + ERROR("Test case %d failed computing 1 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n", + c + 1, i, sinr_1l[i], gold->snri_1l[i]); + goto clean; + } + } + + /* Check PMI select for 1 layer*/ + if (pmi[0] != gold->pmi[0]) { + ERROR("Test case %d failed computing 1 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[0], gold->pmi[0]); + goto clean; + } + + /* PMI select for 2 layer */ + ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 2, &pmi[1], sinr_2l); + if (ret < 0) { + ERROR("During PMI selection for 2 layer"); + goto clean; + } + + /* Check SINR for 2 layer */ + for (int i = 0; i < ret; i++) { + if (fabsf(gold->snri_2l[i] - sinr_2l[i]) > 0.1) { + ERROR("Test case %d failed computing 2 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n", + c + 1, i, sinr_2l[i], gold->snri_2l[i]); + goto clean; + } + } + + /* Check PMI select for 2 layer*/ + if (pmi[1] != gold->pmi[1]) { + ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]); + goto clean; + } + } + + /* Test passed */ + ret = SRSLTE_SUCCESS; + + clean: + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + if (h[i][j]) { + free(h[i][j]); + } + } + } + + if (ret) { + printf("Failed!\n"); + } else { + printf("Passed!\n"); + } + + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/mimo/test/pmi_select_test.h b/lib/src/phy/mimo/test/pmi_select_test.h new file mode 100644 index 000000000..a55869a8b --- /dev/null +++ b/lib/src/phy/mimo/test/pmi_select_test.h @@ -0,0 +1,203 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef PMI_SELECT_TEST_H +#define PMI_SELECT_TEST_H + +#define PMI_SELECT_TEST_NOF_CASES 16 + +typedef struct { + cf_t h[2][2]; + float n; + float snri_1l[4]; + float snri_2l[2]; + uint32_t pmi[2]; +} pmi_select_test_case_gold_t; + +static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = { + { /* Test case 1 */ + .h = { + {+0.103430f+0.455920f*_Complex_I, +0.042050f+0.751883f*_Complex_I}, + {-0.641951f-0.053356f*_Complex_I, +0.217847f+0.504428f*_Complex_I} + }, + .n = 0.181048, + .snri_1l = {5.793827f, 2.505115f, 3.350922f, 4.948020f}, + .snri_2l = {2.015732f, 1.848130f}, + .pmi = {0, 0}, + }, + { /* Test case 2 */ + .h = { + {-0.957328f-0.624816f*_Complex_I, -0.741457f-0.657570f*_Complex_I}, + {+0.720104f+0.351137f*_Complex_I, +0.593419f-0.200211f*_Complex_I} + }, + .n = 0.935527, + .snri_1l = {0.475069f, 3.077055f, 1.078656f, 2.473467f}, + .snri_2l = {0.747362f, 0.594324f}, + .pmi = {1, 0}, + }, + { /* Test case 3 */ + .h = { + {-0.047530f-0.118039f*_Complex_I, -0.195528f-0.724032f*_Complex_I}, + {-0.619953f+0.960678f*_Complex_I, -0.325868f-0.120700f*_Complex_I} + }, + .n = 0.803842, + .snri_1l = {1.331730f, 1.164592f, 1.660155f, 0.836167f}, + .snri_2l = {0.554942f, 0.579321f}, + .pmi = {2, 1}, + }, + { /* Test case 4 */ + .h = { + {+0.635330f-0.751786f*_Complex_I, -0.536944f-0.185884f*_Complex_I}, + {+0.282517f-0.864615f*_Complex_I, -0.484380f-0.780479f*_Complex_I} + }, + .n = 0.529556, + .snri_1l = {5.128973f, 0.465969f, 2.812367f, 2.782574f}, + .snri_2l = {1.381190f, 0.818813f}, + .pmi = {0, 0}, + }, + { /* Test case 5 */ + .h = { + {-0.576996f+0.964470f*_Complex_I, -0.948065f+0.902764f*_Complex_I}, + {+0.988240f-0.056784f*_Complex_I, +0.489282f+0.975071f*_Complex_I} + }, + .n = 0.852921, + .snri_1l = {2.772684f, 3.261802f, 5.698031f, 0.336455f}, + .snri_2l = {0.768370f, 1.469069f}, + .pmi = {2, 1}, + }, + { /* Test case 6 */ + .h = { + {-0.381846f-0.998609f*_Complex_I, +0.903472f-0.393687f*_Complex_I}, + {-0.772703f-0.261637f*_Complex_I, -0.765452f-0.759318f*_Complex_I} + }, + .n = 0.711912, + .snri_1l = {2.998736f, 2.538860f, 5.099274f, 0.438323f}, + .snri_2l = {0.809381f, 1.371548f}, + .pmi = {2, 1}, + }, + { /* Test case 7 */ + .h = { + {+0.915028f-0.780771f*_Complex_I, -0.355424f+0.447925f*_Complex_I}, + {+0.577968f+0.765204f*_Complex_I, +0.342972f-0.999014f*_Complex_I} + }, + .n = 0.101944, + .snri_1l = {12.424177f, 24.940449f, 5.411339f, 31.953288f}, + .snri_2l = {4.610588f, 7.664146f}, + .pmi = {3, 1}, + }, + { /* Test case 8 */ + .h = { + {-0.259232f-0.654765f*_Complex_I, +0.829378f-0.793859f*_Complex_I}, + {+0.997978f+0.212295f*_Complex_I, -0.659012f-0.176220f*_Complex_I} + }, + .n = 0.255783, + .snri_1l = {3.345813f, 9.635433f, 6.767844f, 6.213402f}, + .snri_2l = {3.215386f, 2.640976f}, + .pmi = {1, 0}, + }, + { /* Test case 9 */ + .h = { + {-0.596630f+0.244853f*_Complex_I, -0.624622f+0.316537f*_Complex_I}, + {+0.767545f-0.645831f*_Complex_I, +0.262828f+0.251697f*_Complex_I} + }, + .n = 0.876456, + .snri_1l = {0.367264f, 1.965908f, 1.215674f, 1.117498f}, + .snri_2l = {0.579923f, 0.479609f}, + .pmi = {1, 0}, + }, + { /* Test case 10 */ + .h = { + {-0.643594f+0.172442f*_Complex_I, +0.291148f-0.026254f*_Complex_I}, + {+0.768244f+0.678173f*_Complex_I, -0.498968f-0.896649f*_Complex_I} + }, + .n = 0.739473, + .snri_1l = {1.104856f, 2.455074f, 2.920106f, 0.639825f}, + .snri_2l = {0.557672f, 0.658911f}, + .pmi = {2, 1}, + }, + { /* Test case 11 */ + .h = { + {+0.109032f-0.285542f*_Complex_I, -0.141055f+0.318945f*_Complex_I}, + {+0.559445f-0.211656f*_Complex_I, -0.206665f-0.643045f*_Complex_I} + }, + .n = 0.054295, + .snri_1l = {8.472397f, 10.480333f, 4.074631f, 14.878099f}, + .snri_2l = {2.121444f, 2.979095f}, + .pmi = {3, 1}, + }, + { /* Test case 12 */ + .h = { + {-0.505758f-0.710501f*_Complex_I, +0.803627f+0.023333f*_Complex_I}, + {+0.964886f+0.987055f*_Complex_I, -0.031782f+0.525138f*_Complex_I} + }, + .n = 0.966024, + .snri_1l = {0.612742f, 3.102514f, 1.227107f, 2.488149f}, + .snri_2l = {0.848010f, 0.701000f}, + .pmi = {1, 0}, + }, + { /* Test case 13 */ + .h = { + {+0.859761f-0.737655f*_Complex_I, -0.527019f+0.509133f*_Complex_I}, + {-0.804956f-0.303794f*_Complex_I, -0.180451f-0.100433f*_Complex_I} + }, + .n = 0.199335, + .snri_1l = {4.402551f, 8.656756f, 10.092319f, 2.966987f}, + .snri_2l = {2.048224f, 2.462759f}, + .pmi = {2, 1}, + }, + { /* Test case 14 */ + .h = { + {+0.473036f+0.227467f*_Complex_I, -0.593265f-0.308456f*_Complex_I}, + {+0.536321f+0.445264f*_Complex_I, -0.517440f-0.765554f*_Complex_I} + }, + .n = 0.180788, + .snri_1l = {10.671400f, 0.736020f, 3.584109f, 7.823311f}, + .snri_2l = {2.029078f, 0.914443f}, + .pmi = {0, 0}, + }, + { /* Test case 15 */ + .h = { + {-0.612271f+0.338114f*_Complex_I, -0.278903f+0.914426f*_Complex_I}, + {-0.191213f-0.136670f*_Complex_I, -0.548440f+0.607628f*_Complex_I} + }, + .n = 0.798189, + .snri_1l = {2.309797f, 0.356735f, 0.731443f, 1.935089f}, + .snri_2l = {0.577612f, 0.490806f}, + .pmi = {0, 0}, + }, + { /* Test case 16 */ + .h = { + {+0.990482f+0.513519f*_Complex_I, -0.576391f+0.922553f*_Complex_I}, + {-0.341962f+0.139785f*_Complex_I, +0.524684f+0.217012f*_Complex_I} + }, + .n = 0.365092, + .snri_1l = {2.942635f, 4.964827f, 4.761949f, 3.145513f}, + .snri_2l = {1.291431f, 1.267123f}, + .pmi = {1, 0}, + }, +}; + +#endif /* PMI_SELECT_TEST_H */