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)
|
||||
{
|
||||
// Don't reduce MIMO layers based on muted antennas.
|
||||
// Antenna muting happens at the RU level (in nr_feptx) after precoding,
|
||||
// so we keep using full layer count to maintain proper precoding matrices.
|
||||
// This avoids the identity matrix fallback which doesn't account for
|
||||
// which specific antennas are muted.
|
||||
(void)state; // unused - muting is handled at RU level
|
||||
if (state == NULL)
|
||||
return requested_layers;
|
||||
|
||||
// Reduce MIMO layers to match the number of active TX antennas.
|
||||
// When antennas are muted, the RU blanks the corresponding TX buffers.
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
for (int k = 0; k < N; k++) {
|
||||
if (k == q) continue;
|
||||
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_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++)
|
||||
eigenvalues[i] = A_re[i][i];
|
||||
eigenvalues[i] = A_re[i][i] > 0.0f ? A_re[i][i] : 0.0f;
|
||||
|
||||
// Sort descending
|
||||
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 {
|
||||
// ---- 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++) {
|
||||
float A_re[4][4] = {{0}}, A_im[4][4] = {{0}};
|
||||
for (int i = 0; i < N_ports; i++) {
|
||||
for (int j = 0; j < N_ports; j++) {
|
||||
c16_t val = *((c16_t *)&csi_rs_estimated_A_MF[i][j][k_offset + sc_idx]);
|
||||
A_re[i][j] = (float)val.r;
|
||||
A_im[i][j] = (float)val.i;
|
||||
// H^H * H: A[p1][p2] = sum_rx conj(H[rx][p1]) * H[rx][p2]
|
||||
for (int rx = 0; rx < frame_parms->nb_antennas_rx; rx++) {
|
||||
for (int p1 = 0; p1 < N_ports; p1++) {
|
||||
c16_t h1 = csi_rs_estimated_channel_freq[rx][p1][k_offset + sc_idx];
|
||||
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);
|
||||
|
||||
} else {
|
||||
LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i with 4 ports\n", rank_indicator+1);
|
||||
return -1;
|
||||
// RI=3 or RI=4: Use identity-like precoder (i1=0, i2=0)
|
||||
// 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 {
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
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 c16_t *dst = (const c16_t *)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset]; */
|
||||
/* const int dst_nnz = count_nnz_c16(dst, numSamples); */
|
||||
/* 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)); */
|
||||
|
||||
LOG_I(PHY,
|
||||
"[TXF_PWR] frame=%d slot=%d beam=%d aa=%d tx_idx=%d "
|
||||
"DST pwr=%d dB nnz=%d\n",
|
||||
ru->proc.frame_tx, slot, bb, aa, tx_idx, dst_pwr_db, dst_nnz);
|
||||
}
|
||||
/* LOG_I(PHY, */
|
||||
/* "[TXF_PWR] frame=%d slot=%d beam=%d aa=%d tx_idx=%d " */
|
||||
/* "DST pwr=%d dB nnz=%d\n", */
|
||||
/* ru->proc.frame_tx, slot, bb, aa, tx_idx, dst_pwr_db, dst_nnz); */
|
||||
/* } */
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (!UE->reconfigCellGroup) {
|
||||
LOG_W(NR_MAC, "Received ACK for RRCReconfiguration, but nothing to apply!\n");
|
||||
return;
|
||||
}
|
||||
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,
|
||||
"RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n");
|
||||
} else if (req->reconfig_compl) {
|
||||
LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n");
|
||||
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);
|
||||
UE->CellGroup = UE->reconfigCellGroup;
|
||||
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));
|
||||
|
||||
long l = ue_supported_dl_layers(scc, uecap);
|
||||
long ue_supported_layers = l > 1 ? l : 2; // min UE supported layers = 2
|
||||
if (maxMIMO_layers == -1)
|
||||
long ue_supported_layers = l > 1 ? l : 2;
|
||||
if (maxMIMO_layers == -1)
|
||||
*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);
|
||||
}
|
||||
|
||||
@@ -1287,7 +1287,7 @@ static void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config,
|
||||
pucchfmt2->interslotFrequencyHopping = NULL;
|
||||
pucchfmt2->additionalDMRS = NULL;
|
||||
pucchfmt2->maxCodeRate = calloc(1,sizeof(*pucchfmt2->maxCodeRate));
|
||||
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot15;
|
||||
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot25;
|
||||
pucchfmt2->nrofSlots = NULL;
|
||||
pucchfmt2->pi2BPSK = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user