This commit is contained in:
2026-09-19 23:28:08 +09:00
parent c50fe1af53
commit 67717ed5c1
43 changed files with 3145 additions and 294 deletions
+189
View File
@@ -13,10 +13,199 @@
#include "nr_common.h"
#include <limits.h>
#include <math.h>
#include <string.h>
#define C_SRS_NUMBER (64)
#define B_SRS_NUMBER (4)
void nr_pdsch_rank_capacity_scores(const float eigenvalues[NR_MAX_NB_LAYERS],
uint8_t max_rank,
float noise_power,
float scores[NR_MAX_NB_LAYERS])
{
AssertFatal(max_rank >= 1 && max_rank <= NR_MAX_NB_LAYERS,
"Invalid maximum PDSCH rank %u\n",
max_rank);
const float finite_noise = isfinite(noise_power) && noise_power > 0.0f ? noise_power : 1.0f;
for (int rank = 1; rank <= NR_MAX_NB_LAYERS; rank++) {
scores[rank - 1] = 0.0f;
if (rank > max_rank)
continue;
for (int layer = 0; layer < rank; layer++) {
const float eigenvalue = isfinite(eigenvalues[layer]) && eigenvalues[layer] > 0.0f
? eigenvalues[layer]
: 0.0f;
scores[rank - 1] += log2f(1.0f + eigenvalue / (rank * finite_noise));
}
}
}
uint8_t nr_pdsch_select_rank(const float scores[NR_MAX_NB_LAYERS],
uint8_t max_rank,
float relative_margin)
{
AssertFatal(max_rank >= 1 && max_rank <= NR_MAX_NB_LAYERS,
"Invalid maximum PDSCH rank %u\n",
max_rank);
const float margin = isfinite(relative_margin) && relative_margin > 0.0f ? relative_margin : 0.0f;
uint8_t best_rank = 1;
float best_score = isfinite(scores[0]) ? scores[0] : 0.0f;
for (uint8_t rank = 2; rank <= max_rank; rank++) {
const float candidate = isfinite(scores[rank - 1]) ? scores[rank - 1] : 0.0f;
if (candidate > best_score * (1.0f + margin)) {
best_rank = rank;
best_score = candidate;
}
}
return best_rank;
}
uint8_t nr_type1_sp_4x1_i11_count(uint8_t layers)
{
switch (layers) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
return 16;
case 7:
case 8:
return 8;
default:
return 0;
}
}
uint8_t nr_type1_sp_4x1_i13_count(uint8_t layers)
{
switch (layers) {
case 1:
case 5:
case 6:
case 7:
case 8:
return 1;
case 2:
return 4;
case 3:
case 4:
return 3;
default:
return 0;
}
}
uint8_t nr_type1_sp_4x1_i2_count(uint8_t layers)
{
if (layers == 1)
return 4;
return layers >= 2 && layers <= 8 ? 2 : 0;
}
bool nr_type1_sp_4x1_weights(uint8_t layers,
uint8_t i11,
uint8_t i13,
uint8_t i2,
c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS])
{
memset(weights, 0, NR_MAX_NB_LAYERS * NR_MAX_CSI_PORTS * sizeof(**weights));
const uint8_t i11_count = nr_type1_sp_4x1_i11_count(layers);
const uint8_t i13_count = nr_type1_sp_4x1_i13_count(layers);
const uint8_t i2_count = nr_type1_sp_4x1_i2_count(layers);
if (i11_count == 0 || i11 >= i11_count || i13 >= i13_count || i2 >= i2_count)
return false;
/* TS 38.214 Tables 5.2.2.2.1-5--12, specialized to the one-dimensional
* N1=4 panel. O1=4, so adjacent orthogonal DFT beams are four indices
* apart. Values 0..3 below encode 1, -1, phi, and -phi respectively. */
uint8_t beam_offset[NR_MAX_NB_LAYERS] = {0};
uint8_t polarization[NR_MAX_NB_LAYERS] = {0};
switch (layers) {
case 1:
polarization[0] = 2;
break;
case 2:
beam_offset[1] = 4 * i13;
polarization[0] = 2;
polarization[1] = 3;
break;
case 3:
case 4: {
const uint8_t offset = 4 * (i13 + 1);
beam_offset[1] = offset;
beam_offset[3] = offset;
polarization[0] = 2;
polarization[1] = 2;
polarization[2] = 3;
polarization[3] = 3;
break;
}
case 5: {
const uint8_t offsets[] = {0, 0, 4, 4, 8};
const uint8_t polarizations[] = {2, 3, 0, 1, 0};
memcpy(beam_offset, offsets, sizeof(offsets));
memcpy(polarization, polarizations, sizeof(polarizations));
break;
}
case 6: {
const uint8_t offsets[] = {0, 0, 4, 4, 8, 8};
const uint8_t polarizations[] = {2, 3, 2, 3, 0, 1};
memcpy(beam_offset, offsets, sizeof(offsets));
memcpy(polarization, polarizations, sizeof(polarizations));
break;
}
case 7: {
const uint8_t offsets[] = {0, 0, 4, 8, 8, 12, 12};
const uint8_t polarizations[] = {2, 3, 2, 0, 1, 0, 1};
memcpy(beam_offset, offsets, sizeof(offsets));
memcpy(polarization, polarizations, sizeof(polarizations));
break;
}
case 8: {
const uint8_t offsets[] = {0, 0, 4, 4, 8, 8, 12, 12};
const uint8_t polarizations[] = {2, 3, 2, 3, 0, 1, 0, 1};
memcpy(beam_offset, offsets, sizeof(offsets));
memcpy(polarization, polarizations, sizeof(polarizations));
break;
}
}
const float scale = 1.0f / sqrtf((float)layers);
const float phi_re = cosf((float)M_PI * i2 / 2.0f);
const float phi_im = sinf((float)M_PI * i2 / 2.0f);
for (int layer = 0; layer < layers; layer++) {
const int beam = i11 + beam_offset[layer];
float pol_re = 1.0f;
float pol_im = 0.0f;
switch (polarization[layer]) {
case 1:
pol_re = -1.0f;
break;
case 2:
pol_re = phi_re;
pol_im = phi_im;
break;
case 3:
pol_re = -phi_re;
pol_im = -phi_im;
break;
}
for (int element = 0; element < 4; element++) {
const float angle = 2.0f * (float)M_PI * element * beam / 16.0f;
const float beam_re = cosf(angle);
const float beam_im = sinf(angle);
weights[layer][element].r = lrintf(SHRT_MAX * scale * beam_re);
weights[layer][element].i = lrintf(SHRT_MAX * scale * beam_im);
weights[layer][element + 4].r = lrintf(SHRT_MAX * scale * (pol_re * beam_re - pol_im * beam_im));
weights[layer][element + 4].i = lrintf(SHRT_MAX * scale * (pol_re * beam_im + pol_im * beam_re));
}
}
return true;
}
/* TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration */
static const unsigned short srs_bandwidth_config[C_SRS_NUMBER][B_SRS_NUMBER][2] = {
/* B_SRS = 0 B_SRS = 1 B_SRS = 2 B_SRS = 3 */