Added PMI select C test and solved bugs (golden vectors generated from reference script)

This commit is contained in:
Xavier Arteaga 2017-08-17 16:23:43 +02:00
parent 801b210511
commit f2db2db81b
4 changed files with 406 additions and 56 deletions

View File

@ -25,7 +25,6 @@
*/
#include <stdlib.h>
#include <assert.h>
#include <complex.h>
#include <string.h>
#include <math.h>
@ -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];

View File

@ -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)

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#include <complex.h>
#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;
}

View File

@ -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 */