From bbf7ffffa21050ed58b7778ab074132f6ae11cb8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 29 Aug 2017 09:59:06 +0200 Subject: [PATCH] Added Condition number calculation for Rank Indicator in TM3 (cherry picked from commit f8a4472) --- lib/examples/pdsch_ue.c | 8 +- lib/include/srslte/phy/mimo/precoding.h | 7 + lib/include/srslte/phy/phch/pdsch.h | 5 + lib/include/srslte/phy/ue/ue_dl.h | 4 + lib/include/srslte/phy/utils/algebra.h | 6 + lib/src/phy/mimo/precoding.c | 34 ++++ lib/src/phy/mimo/test/pmi_select_test.c | 14 ++ lib/src/phy/mimo/test/pmi_select_test.h | 232 ++++++++++++++---------- lib/src/phy/phch/pdsch.c | 5 + lib/src/phy/ue/ue_dl.c | 26 ++- lib/src/phy/utils/algebra.c | 23 +++ 11 files changed, 261 insertions(+), 103 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 7fc020118..be271049e 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -513,7 +513,7 @@ int main(int argc, char **argv) { uint32_t nframes=0; uint32_t ri = 0, pmi = 0; float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, - sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; + sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; bool decode_pdsch = false; for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) { @@ -678,11 +678,14 @@ int main(int argc, char **argv) { 100 * (1 - (float) ue_dl.nof_detected / nof_trials), (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); } else { + /* Compute condition number */ + srslte_ue_dl_ri_select(&ue_dl, NULL, &cn); + /* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */ srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL); for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) { for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb ++) { - sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.05f); + sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f); } } @@ -703,6 +706,7 @@ int main(int argc, char **argv) { printf("\033[K PDSCH-BLER: %5.2f%%\n", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); printf("\033[K TB 0: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); printf("\033[K TB 1: mcs=%d; tbs=%d\n", ue_dl.pdsch_cfg.grant.mcs[1].idx, ue_dl.pdsch_cfg.grant.mcs[1].tbs); + printf("\033[K κ: %.1f dB (Condition number, 0 dB => Best)\n", cn); printf("\033[K\n"); printf("\033[KSINR (dB) Vs RI and PMI (for TM4, close loop MIMO only):\n"); printf("\033[K | RI | 1 | 2 |\n"); diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index b32b975d2..58fe22a40 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -127,4 +127,11 @@ SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_ uint32_t *pmi, float sinr[SRSLTE_MAX_CODEBOOKS]); +SRSLTE_API int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas, + uint32_t nof_symbols, + float *cn); + + #endif /* PRECODING_H_ */ diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 7cfa1b616..ca6ce3478 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -156,6 +156,11 @@ SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]); +SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t nof_ce, + float *cn); + SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 97b2344f5..416d467f8 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -200,6 +200,10 @@ SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *pmi, float *current_sinr); +SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, + uint32_t *ri, + float *cn); + SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, diff --git a/lib/include/srslte/phy/utils/algebra.h b/lib/include/srslte/phy/utils/algebra.h index 8e731a29f..ee681d558 100644 --- a/lib/include/srslte/phy/utils/algebra.h +++ b/lib/include/srslte/phy/utils/algebra.h @@ -108,6 +108,12 @@ SRSLTE_API void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, float noise_estimate, float norm); +SRSLTE_API float srslte_algebra_2x2_cn(cf_t h00, + cf_t h01, + cf_t h10, + cf_t h11); + + #ifdef LV_HAVE_SSE /* SSE implementation for complex reciprocal */ diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index a79b75b0a..94b60c033 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -2517,3 +2517,37 @@ int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uin return ret; } + +/* PMI Select for 1 layer */ +float srslte_precoding_2x2_cn_gen(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols) { + uint32_t count = 0; + float cn_avg = 0.0f; + + for (uint32_t i = 0; i < nof_symbols; i += PMI_SEL_PRECISION) { + /* 0. Load channel matrix */ + cf_t h00 = h[0][0][i]; + cf_t h01 = h[1][0][i]; + cf_t h10 = h[0][1][i]; + cf_t h11 = h[1][1][i]; + + cn_avg += srslte_algebra_2x2_cn(h00, h01, h10, h11); + + count++; + } + + return cn_avg/count; +} + +/* Computes the condition number for a given number of antennas, + * stores in the parameter *cn the Condition Number in dB */ +int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_tx_antennas, + uint32_t nof_rx_antennas, uint32_t nof_symbols, float *cn) { + if (nof_tx_antennas == 2 && nof_rx_antennas == 2) { + *cn = srslte_precoding_2x2_cn_gen(h, nof_symbols); + return SRSLTE_SUCCESS; + } else { + ERROR("MIMO Condition Number calculation not implemented for %d×%d", nof_tx_antennas, nof_rx_antennas); + return SRSLTE_ERROR; + } +} + diff --git a/lib/src/phy/mimo/test/pmi_select_test.c b/lib/src/phy/mimo/test/pmi_select_test.c index 30d358e37..9ac45f008 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.c +++ b/lib/src/phy/mimo/test/pmi_select_test.c @@ -45,6 +45,7 @@ int main(int argc, char **argv) { float noise_estimate; float sinr_1l[SRSLTE_MAX_CODEBOOKS]; float sinr_2l[SRSLTE_MAX_CODEBOOKS]; + float cn; uint32_t pmi[2]; uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM); int ret = SRSLTE_ERROR; @@ -120,6 +121,19 @@ int main(int argc, char **argv) { ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]); goto clean; } + + /* Condition number */ + if (srslte_precoding_cn(h, 2, 2, nof_symbols, &cn)) { + ERROR("Test case %d condition number returned error\n"); + goto clean; + } + + /* Check condition number */ + if (fabsf(gold->k - cn) > 0.1) { + ERROR("Test case %d failed computing condition number (test=%.2f; gold=%.2f)\n", + c + 1, cn, gold->k); + goto clean; + } } /* Test passed */ diff --git a/lib/src/phy/mimo/test/pmi_select_test.h b/lib/src/phy/mimo/test/pmi_select_test.h index a55869a8b..14c72c266 100644 --- a/lib/src/phy/mimo/test/pmi_select_test.h +++ b/lib/src/phy/mimo/test/pmi_select_test.h @@ -30,173 +30,207 @@ #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]; + cf_t h[2][2]; /* Channel estimate */ + float n; /* Noise estimation */ + float snri_1l[4]; /* SINR Approximation for 1 layer (linear) */ + float snri_2l[2]; /* SINR Approximation for 2 layers (linear) */ + uint32_t pmi[2]; /* Precoding Matrix Indicator for 1 and 2 layers */ + uint32_t ri; /* Rank indicator */ + float k; /* Condition number (κ) in dB */ } 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} + {+0.861552f+0.205546f*_Complex_I, +0.955538f-0.052364f*_Complex_I}, + {-0.812807f-0.287487f*_Complex_I, +0.323470f-0.048843f*_Complex_I} }, - .n = 0.181048, - .snri_1l = {5.793827f, 2.505115f, 3.350922f, 4.948020f}, - .snri_2l = {2.015732f, 1.848130f}, - .pmi = {0, 0}, + .n = 0.671022, + .snri_1l = {1.233339f, 2.567786f, 2.065012f, 1.736113f}, + .snri_2l = {0.893739f, 0.841600f}, + .pmi = {1, 0}, + .ri = 2, + .k = 4.6758, }, { /* 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} + {+0.919290f+0.824394f*_Complex_I, -0.821831f-0.797741f*_Complex_I}, + {+0.595485f-0.413411f*_Complex_I, +0.181551f-0.896824f*_Complex_I} }, - .n = 0.935527, - .snri_1l = {0.475069f, 3.077055f, 1.078656f, 2.473467f}, - .snri_2l = {0.747362f, 0.594324f}, - .pmi = {1, 0}, + .n = 0.504128, + .snri_1l = {5.697916f, 2.631874f, 4.143253f, 4.186538f}, + .snri_2l = {1.897704f, 1.718554f}, + .pmi = {0, 0}, + .ri = 2, + .k = 4.8715, }, { /* 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} + {+0.536752f-0.093497f*_Complex_I, -0.434029f+0.474769f*_Complex_I}, + {-0.549280f+0.019771f*_Complex_I, -0.337421f-0.234972f*_Complex_I} }, - .n = 0.803842, - .snri_1l = {1.331730f, 1.164592f, 1.660155f, 0.836167f}, - .snri_2l = {0.554942f, 0.579321f}, - .pmi = {2, 1}, + .n = 0.905483, + .snri_1l = {0.363469f, 0.941684f, 0.408025f, 0.897129f}, + .snri_2l = {0.311544f, 0.307074f}, + .pmi = {1, 0}, + .ri = 1, + .k = 6.2219, }, { /* 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} + {+0.930515f-0.233960f*_Complex_I, +0.256535f+0.982387f*_Complex_I}, + {-0.735938f-0.426345f*_Complex_I, +0.236604f+0.412383f*_Complex_I} }, - .n = 0.529556, - .snri_1l = {5.128973f, 0.465969f, 2.812367f, 2.782574f}, - .snri_2l = {1.381190f, 0.818813f}, - .pmi = {0, 0}, + .n = 0.535206, + .snri_1l = {2.487298f, 2.932872f, 4.009672f, 1.410498f}, + .snri_2l = {1.082110f, 1.248639f}, + .pmi = {2, 1}, + .ri = 2, + .k = 5.9758, }, { /* 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} + {-0.613578f-0.908683f*_Complex_I, +0.378870f+0.770083f*_Complex_I}, + {-0.899090f+0.679589f*_Complex_I, -0.631132f-0.763690f*_Complex_I} }, - .n = 0.852921, - .snri_1l = {2.772684f, 3.261802f, 5.698031f, 0.336455f}, - .snri_2l = {0.768370f, 1.469069f}, + .n = 0.410415, + .snri_1l = {2.929140f, 7.281276f, 7.632612f, 2.577804f}, + .snri_2l = {2.045272f, 2.159393f}, .pmi = {2, 1}, + .ri = 2, + .k = 6.8485, }, { /* 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} + {-0.759543f+0.979731f*_Complex_I, +0.144185f-0.300384f*_Complex_I}, + {+0.898780f-0.582955f*_Complex_I, -0.487230f+0.331654f*_Complex_I} }, - .n = 0.711912, - .snri_1l = {2.998736f, 2.538860f, 5.099274f, 0.438323f}, - .snri_2l = {0.809381f, 1.371548f}, - .pmi = {2, 1}, + .n = 0.973345, + .snri_1l = {0.151784f, 3.077111f, 2.165454f, 1.063441f}, + .snri_2l = {0.755981f, 0.503361f}, + .pmi = {1, 0}, + .ri = 1, + .k = 18.0800, }, { /* 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} + {+0.245400f-0.537444f*_Complex_I, -0.872924f-0.895583f*_Complex_I}, + {-0.252981f+0.803513f*_Complex_I, -0.667497f+0.586583f*_Complex_I} }, - .n = 0.101944, - .snri_1l = {12.424177f, 24.940449f, 5.411339f, 31.953288f}, - .snri_2l = {4.610588f, 7.664146f}, - .pmi = {3, 1}, + .n = 0.373014, + .snri_1l = {3.403660f, 5.744504f, 7.385295f, 1.762868f}, + .snri_2l = {1.642126f, 2.130892f}, + .pmi = {2, 1}, + .ri = 2, + .k = 7.1484, }, { /* 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} + {+0.664109f-0.281444f*_Complex_I, +0.507669f-0.822295f*_Complex_I}, + {+0.243726f-0.316646f*_Complex_I, -0.211814f+0.097341f*_Complex_I} }, - .n = 0.255783, - .snri_1l = {3.345813f, 9.635433f, 6.767844f, 6.213402f}, - .snri_2l = {3.215386f, 2.640976f}, - .pmi = {1, 0}, + .n = 0.460547, + .snri_1l = {1.948731f, 1.673386f, 2.389606f, 1.232511f}, + .snri_2l = {0.623422f, 0.659548f}, + .pmi = {2, 1}, + .ri = 1, + .k = 9.8582, }, { /* 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} + {+0.290905f-0.072573f*_Complex_I, +0.027042f+0.179635f*_Complex_I}, + {+0.628853f-0.625656f*_Complex_I, -0.805634f+0.222660f*_Complex_I} }, - .n = 0.876456, - .snri_1l = {0.367264f, 1.965908f, 1.215674f, 1.117498f}, - .snri_2l = {0.579923f, 0.479609f}, - .pmi = {1, 0}, + .n = 0.051942, + .snri_1l = {20.229536f, 10.736104f, 15.206118f, 15.759523f}, + .snri_2l = {2.426844f, 2.175025f}, + .pmi = {0, 0}, + .ri = 1, + .k = 12.8396, }, { /* 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} + {+0.151454f-0.701886f*_Complex_I, +0.684689f-0.943441f*_Complex_I}, + {-0.000548f+0.513340f*_Complex_I, -0.121950f+0.592212f*_Complex_I} }, - .n = 0.739473, - .snri_1l = {1.104856f, 2.455074f, 2.920106f, 0.639825f}, - .snri_2l = {0.557672f, 0.658911f}, - .pmi = {2, 1}, + .n = 0.293556, + .snri_1l = {0.848833f, 7.679596f, 3.011330f, 5.517099f}, + .snri_2l = {1.442768f, 0.788147f}, + .pmi = {1, 0}, + .ri = 1, + .k = 22.0345, }, { /* 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} + {-0.769587f+0.330477f*_Complex_I, -0.249817f+0.920280f*_Complex_I}, + {+0.657787f+0.886236f*_Complex_I, +0.683553f-0.774601f*_Complex_I} }, - .n = 0.054295, - .snri_1l = {8.472397f, 10.480333f, 4.074631f, 14.878099f}, - .snri_2l = {2.121444f, 2.979095f}, - .pmi = {3, 1}, + .n = 0.648287, + .snri_1l = {1.312873f, 4.697041f, 5.064183f, 0.945731f}, + .snri_2l = {0.993660f, 1.125611f}, + .pmi = {2, 1}, + .ri = 1, + .k = 12.9593, }, { /* 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} + {-0.038392f+0.542607f*_Complex_I, -0.866959f-0.879276f*_Complex_I}, + {+0.795542f-0.475085f*_Complex_I, -0.005540f+0.302139f*_Complex_I} }, - .n = 0.966024, - .snri_1l = {0.612742f, 3.102514f, 1.227107f, 2.488149f}, - .snri_2l = {0.848010f, 0.701000f}, - .pmi = {1, 0}, + .n = 0.133604, + .snri_1l = {6.257962f, 14.479088f, 15.459994f, 5.277056f}, + .snri_2l = {3.523645f, 3.845011f}, + .pmi = {2, 1}, + .ri = 1, + .k = 7.6196, }, { /* 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} + {+0.277091f-0.237022f*_Complex_I, -0.230114f-0.399963f*_Complex_I}, + {+0.531396f-0.319721f*_Complex_I, +0.305831f+0.837853f*_Complex_I} }, - .n = 0.199335, - .snri_1l = {4.402551f, 8.656756f, 10.092319f, 2.966987f}, - .snri_2l = {2.048224f, 2.462759f}, - .pmi = {2, 1}, + .n = 0.456267, + .snri_1l = {1.272387f, 2.072182f, 1.744873f, 1.599696f}, + .snri_2l = {0.720254f, 0.700519f}, + .pmi = {1, 0}, + .ri = 2, + .k = 5.9972, }, { /* 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} + {-0.115006f+0.764806f*_Complex_I, -0.091628f-0.960249f*_Complex_I}, + {+0.890564f-0.316470f*_Complex_I, -0.561762f+0.532055f*_Complex_I} }, - .n = 0.180788, - .snri_1l = {10.671400f, 0.736020f, 3.584109f, 7.823311f}, - .snri_2l = {2.029078f, 0.914443f}, - .pmi = {0, 0}, + .n = 0.342804, + .snri_1l = {2.060602f, 6.750694f, 8.002153f, 0.809143f}, + .snri_2l = {1.036665f, 1.575640f}, + .pmi = {2, 1}, + .ri = 1, + .k = 18.9097, }, { /* 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} + {+0.237613f+0.203137f*_Complex_I, -0.093958f+0.298835f*_Complex_I}, + {-0.979675f-0.314559f*_Complex_I, +0.198162f-0.013401f*_Complex_I} }, - .n = 0.798189, - .snri_1l = {2.309797f, 0.356735f, 0.731443f, 1.935089f}, - .snri_2l = {0.577612f, 0.490806f}, - .pmi = {0, 0}, + .n = 0.701774, + .snri_1l = {0.466961f, 1.376956f, 0.827475f, 1.016442f}, + .snri_2l = {0.386935f, 0.354722f}, + .pmi = {1, 0}, + .ri = 1, + .k = 11.2469, }, { /* 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} + {+0.775605f+0.528142f*_Complex_I, -0.889884f+0.975918f*_Complex_I}, + {-0.803276f-0.749350f*_Complex_I, +0.299566f-0.271046f*_Complex_I} }, - .n = 0.365092, - .snri_1l = {2.942635f, 4.964827f, 4.761949f, 3.145513f}, - .snri_2l = {1.291431f, 1.267123f}, + .n = 0.676230, + .snri_1l = {0.661772f, 5.245671f, 3.261470f, 2.645973f}, + .snri_2l = {1.354145f, 0.857372f}, .pmi = {1, 0}, + .ri = 1, + .k = 10.7137, }, }; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 0e824aaa7..bf50cb6ec 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -700,6 +700,11 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, return SRSLTE_SUCCESS; } +int srslte_pdsch_cn_compute(srslte_pdsch_t *q, + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_ce, float *cn) { + return srslte_precoding_cn(ce, q->cell.nof_ports, q->nof_rx_antennas, nof_ce, cn); +} + int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 219325c1d..91116ab70 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -467,6 +467,8 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR } } +/* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus + * Noise Ratio (SINR), valid for TM4 */ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); float best_sinr = -INFINITY; @@ -484,8 +486,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ for (uint32_t nof_layers = 1; nof_layers <= q->pdsch_cfg.nof_layers; nof_layers++ ) { - if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr) { - best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]; + if (q->sinr[nof_layers][q->pmi[nof_layers]] > best_sinr + 0.1) { + best_sinr = q->sinr[nof_layers][q->pmi[nof_layers]]*nof_layers; best_pmi = q->pmi[nof_layers]; best_ri = nof_layers; } @@ -526,6 +528,26 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f return SRSLTE_SUCCESS; } + +/* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */ +int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) { + float _cn; + int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn); + + /* Set Condition number */ + if (cn) { + *cn = _cn; + } + + /* Set rank indicator */ + if (!ret && ri) { + *ri = (_cn > 3.0f)? 1:0; + } + + return ret; +} + + uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { return q->last_location.ncce; } diff --git a/lib/src/phy/utils/algebra.c b/lib/src/phy/utils/algebra.c index 3d1de2ffa..943ae57dd 100644 --- a/lib/src/phy/utils/algebra.c +++ b/lib/src/phy/utils/algebra.c @@ -26,6 +26,7 @@ #include #include +#include #include "srslte/phy/utils/algebra.h" @@ -92,6 +93,28 @@ inline void srslte_algebra_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf *x1 = (y0 * w10 + y1 * w11) * _norm; } +inline float srslte_algebra_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) { + /* 1. A = H * H' (A = A') */ + float a00 = + crealf(h00) * crealf(h00) + crealf(h01) * crealf(h01) + cimagf(h00) * cimagf(h00) + cimagf(h01) * cimagf(h01); + cf_t a01 = h00 * conjf(h10) + h01 * conjf(h11); + //cf_t a10 = h10*conjf(h00) + h11*conjf(h01) = conjf(a01); + float a11 = + crealf(h10) * crealf(h10) + crealf(h11) * crealf(h11) + cimagf(h10) * cimagf(h10) + cimagf(h11) * cimagf(h11); + + /* 2. |H * H' - {λ0, λ1}| = 0 -> aλ² + bλ + c = 0 */ + float b = a00 + a11; + float c = a00 * a11 - (crealf(a01) * crealf(a01) + cimagf(a01) * cimagf(a01)); + + /* 3. λ = (-b ± sqrt(b² - 4 * c))/2 */ + float sqr = sqrtf(b * b - 4.0f * c); + float xmax = b + sqr; + float xmin = b - sqr; + + /* 4. κ = sqrt(λ_max / λ_min) */ + return 10 * log10f(xmax / xmin); +} + #ifdef LV_HAVE_SSE /* SSE implementation for complex reciprocal */