update
This commit is contained in:
@@ -213,12 +213,19 @@ void nr_unmute_rx_antenna(nr_antenna_state_t *state, uint8_t ant_id)
|
|||||||
|
|
||||||
int nr_get_effective_mimo_layers(const nr_antenna_state_t *state, int requested_layers)
|
int nr_get_effective_mimo_layers(const nr_antenna_state_t *state, int requested_layers)
|
||||||
{
|
{
|
||||||
// Don't reduce MIMO layers based on muted antennas.
|
if (state == NULL)
|
||||||
// Antenna muting happens at the RU level (in nr_feptx) after precoding,
|
return requested_layers;
|
||||||
// so we keep using full layer count to maintain proper precoding matrices.
|
|
||||||
// This avoids the identity matrix fallback which doesn't account for
|
// Reduce MIMO layers to match the number of active TX antennas.
|
||||||
// which specific antennas are muted.
|
// When antennas are muted, the RU blanks the corresponding TX buffers.
|
||||||
(void)state; // unused - muting is handled at RU level
|
// If the scheduler still uses full layer count, the precoded signal is
|
||||||
|
// distributed across all antenna ports (including muted ones), which
|
||||||
|
// corrupts the UE's MIMO reception. By reducing layers to match active
|
||||||
|
// antennas, the PMI fallback to identity precoding maps layers 1:1 to
|
||||||
|
// active ports, avoiding signal loss on muted ports.
|
||||||
|
int active = nr_get_active_tx_antenna_count(state);
|
||||||
|
if (active > 0 && active < requested_layers)
|
||||||
|
return active;
|
||||||
return requested_layers;
|
return requested_layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ static void nr_hermitian_eigenvalues(const int N, float A_re[4][4], float A_im[4
|
|||||||
|
|
||||||
// Multiply column q by e^{-j*phi} and row q by e^{+j*phi}
|
// Multiply column q by e^{-j*phi} and row q by e^{+j*phi}
|
||||||
for (int k = 0; k < N; k++) {
|
for (int k = 0; k < N; k++) {
|
||||||
|
if (k == q) continue;
|
||||||
float old_re = A_re[k][q], old_im = A_im[k][q];
|
float old_re = A_re[k][q], old_im = A_im[k][q];
|
||||||
A_re[k][q] = old_re * cos_phi + old_im * sin_phi;
|
A_re[k][q] = old_re * cos_phi + old_im * sin_phi;
|
||||||
A_im[k][q] = -old_re * sin_phi + old_im * cos_phi;
|
A_im[k][q] = -old_re * sin_phi + old_im * cos_phi;
|
||||||
@@ -201,7 +202,7 @@ static void nr_hermitian_eigenvalues(const int N, float A_re[4][4], float A_im[4
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < N; i++)
|
for (int i = 0; i < N; i++)
|
||||||
eigenvalues[i] = A_re[i][i];
|
eigenvalues[i] = A_re[i][i] > 0.0f ? A_re[i][i] : 0.0f;
|
||||||
|
|
||||||
// Sort descending
|
// Sort descending
|
||||||
for (int i = 0; i < N - 1; i++)
|
for (int i = 0; i < N - 1; i++)
|
||||||
@@ -651,14 +652,24 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ---- General path (N_ports > 2): eigenvalue-based rank estimation ----
|
// ---- General path (N_ports > 2): float Gram matrix + eigenvalue-based rank estimation ----
|
||||||
|
// Compute Gram matrix directly in float from channel estimates to avoid int16 saturation
|
||||||
for (int sc_idx = 0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) {
|
for (int sc_idx = 0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) {
|
||||||
float A_re[4][4] = {{0}}, A_im[4][4] = {{0}};
|
float A_re[4][4] = {{0}}, A_im[4][4] = {{0}};
|
||||||
for (int i = 0; i < N_ports; i++) {
|
// H^H * H: A[p1][p2] = sum_rx conj(H[rx][p1]) * H[rx][p2]
|
||||||
for (int j = 0; j < N_ports; j++) {
|
for (int rx = 0; rx < frame_parms->nb_antennas_rx; rx++) {
|
||||||
c16_t val = *((c16_t *)&csi_rs_estimated_A_MF[i][j][k_offset + sc_idx]);
|
for (int p1 = 0; p1 < N_ports; p1++) {
|
||||||
A_re[i][j] = (float)val.r;
|
c16_t h1 = csi_rs_estimated_channel_freq[rx][p1][k_offset + sc_idx];
|
||||||
A_im[i][j] = (float)val.i;
|
float h1_re = (float)h1.r;
|
||||||
|
float h1_im = (float)h1.i;
|
||||||
|
for (int p2 = 0; p2 < N_ports; p2++) {
|
||||||
|
c16_t h2 = csi_rs_estimated_channel_freq[rx][p2][k_offset + sc_idx];
|
||||||
|
float h2_re = (float)h2.r;
|
||||||
|
float h2_im = (float)h2.i;
|
||||||
|
// conj(h1) * h2 = (h1_re - j*h1_im) * (h2_re + j*h2_im)
|
||||||
|
A_re[p1][p2] += h1_re * h2_re + h1_im * h2_im;
|
||||||
|
A_im[p1][p2] += -h1_im * h2_re + h1_re * h2_im;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,8 +981,32 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue,
|
|||||||
*precoded_sinr_dB = dB_fixed((best_sinr / 2) / interference_plus_noise_power);
|
*precoded_sinr_dB = dB_fixed((best_sinr / 2) / interference_plus_noise_power);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i with 4 ports\n", rank_indicator+1);
|
// RI=3 or RI=4: Use identity-like precoder (i1=0, i2=0)
|
||||||
return -1;
|
// Compute SINR from per-layer effective channel power with identity precoding
|
||||||
|
// Each layer p sees channel H[:,p] across all RX antennas
|
||||||
|
int nlayers = rank_indicator + 1;
|
||||||
|
int64_t total_power = 0;
|
||||||
|
|
||||||
|
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) {
|
||||||
|
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2))
|
||||||
|
continue;
|
||||||
|
uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
|
||||||
|
uint16_t k_off = k + mem_offset;
|
||||||
|
|
||||||
|
for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
|
||||||
|
for (int p = 0; p < nlayers; p++) {
|
||||||
|
const c16_t h = csi_rs_estimated_channel_freq[ant_rx][p][k_off];
|
||||||
|
total_power += (int64_t)h.r * h.r + (int64_t)h.i * h.i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i1[0] = 0;
|
||||||
|
i1[1] = 0;
|
||||||
|
i1[2] = 0;
|
||||||
|
i2[0] = 0;
|
||||||
|
if (total_power > 0)
|
||||||
|
*precoded_sinr_dB = dB_fixed((total_power / nlayers) / interference_plus_noise_power);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_W(NR_PHY, "PMI computation is not implemented for %i ports\n", N_ports);
|
LOG_W(NR_PHY, "PMI computation is not implemented for %i ports\n", N_ports);
|
||||||
|
|||||||
@@ -285,16 +285,16 @@ void nr_feptx(void *arg)
|
|||||||
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
|
AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const c16_t *dst = (const c16_t *)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset];
|
/* const c16_t *dst = (const c16_t *)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset]; */
|
||||||
const int dst_nnz = count_nnz_c16(dst, numSamples);
|
/* const int dst_nnz = count_nnz_c16(dst, numSamples); */
|
||||||
if (startSymbol == 0 && ru->proc.frame_tx % 10 == 0 && dst_nnz != 0) {
|
/* if (startSymbol == 0 && ru->proc.frame_tx % 10 == 0 && dst_nnz != 0) { */
|
||||||
const int dst_pwr_db = dB_fixed(signal_energy_nodc((c16_t *)dst, 2 * numSamples));
|
/* const int dst_pwr_db = dB_fixed(signal_energy_nodc((c16_t *)dst, 2 * numSamples)); */
|
||||||
|
|
||||||
LOG_I(PHY,
|
/* LOG_I(PHY, */
|
||||||
"[TXF_PWR] frame=%d slot=%d beam=%d aa=%d tx_idx=%d "
|
/* "[TXF_PWR] frame=%d slot=%d beam=%d aa=%d tx_idx=%d " */
|
||||||
"DST pwr=%d dB nnz=%d\n",
|
/* "DST pwr=%d dB nnz=%d\n", */
|
||||||
ru->proc.frame_tx, slot, bb, aa, tx_idx, dst_pwr_db, dst_nnz);
|
/* ru->proc.frame_tx, slot, bb, aa, tx_idx, dst_pwr_db, dst_nnz); */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
if (tx_idx == 0)
|
if (tx_idx == 0)
|
||||||
|
|||||||
@@ -597,7 +597,6 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
|||||||
static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE)
|
static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE)
|
||||||
{
|
{
|
||||||
if (!UE->reconfigCellGroup) {
|
if (!UE->reconfigCellGroup) {
|
||||||
LOG_W(NR_MAC, "Received ACK for RRCReconfiguration, but nothing to apply!\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||||
|
|||||||
@@ -769,9 +769,7 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
|||||||
LOG_E(NR_MAC,
|
LOG_E(NR_MAC,
|
||||||
"RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n");
|
"RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n");
|
||||||
} else if (req->reconfig_compl) {
|
} else if (req->reconfig_compl) {
|
||||||
LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n");
|
|
||||||
if (UE->reconfigCellGroup) {
|
if (UE->reconfigCellGroup) {
|
||||||
LOG_W(NR_MAC, "reconfigCellGroup still present, did we miss ACK for RRCReconfiguration?\n");
|
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||||
UE->CellGroup = UE->reconfigCellGroup;
|
UE->CellGroup = UE->reconfigCellGroup;
|
||||||
UE->reconfigCellGroup = NULL;
|
UE->reconfigCellGroup = NULL;
|
||||||
|
|||||||
@@ -645,10 +645,10 @@ static void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcell
|
|||||||
pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1, sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers));
|
pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1, sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers));
|
||||||
|
|
||||||
long l = ue_supported_dl_layers(scc, uecap);
|
long l = ue_supported_dl_layers(scc, uecap);
|
||||||
long ue_supported_layers = l > 1 ? l : 2; // min UE supported layers = 2
|
long ue_supported_layers = l > 1 ? l : 2;
|
||||||
if (maxMIMO_layers == -1)
|
if (maxMIMO_layers == -1)
|
||||||
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(NR_MAX_SUPPORTED_DL_LAYERS, ue_supported_layers);
|
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(NR_MAX_SUPPORTED_DL_LAYERS, ue_supported_layers);
|
||||||
else
|
else
|
||||||
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(maxMIMO_layers, ue_supported_layers);
|
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(maxMIMO_layers, ue_supported_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1287,7 +1287,7 @@ static void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config,
|
|||||||
pucchfmt2->interslotFrequencyHopping = NULL;
|
pucchfmt2->interslotFrequencyHopping = NULL;
|
||||||
pucchfmt2->additionalDMRS = NULL;
|
pucchfmt2->additionalDMRS = NULL;
|
||||||
pucchfmt2->maxCodeRate = calloc(1,sizeof(*pucchfmt2->maxCodeRate));
|
pucchfmt2->maxCodeRate = calloc(1,sizeof(*pucchfmt2->maxCodeRate));
|
||||||
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot15;
|
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot25;
|
||||||
pucchfmt2->nrofSlots = NULL;
|
pucchfmt2->nrofSlots = NULL;
|
||||||
pucchfmt2->pi2BPSK = NULL;
|
pucchfmt2->pi2BPSK = NULL;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user