From aa5bd641fd56d19c087bd933696a1c6efd553743 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 15 Apr 2026 10:35:47 +0100 Subject: [PATCH] Fix EMA cold-start for noise and SNR/RSSI measurements Initialize n0_subband_power and power control avg_snr/avg_rssi directly from the first measurement instead of starting from zero --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 4 ++++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 5 +++++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a901f8dba1..13c828f129 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -162,6 +162,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy int32_t n0_subband_tot_perANT[frame_parms->nb_antennas_rx]; memset(n0_subband_tot_perANT, 0, sizeof(n0_subband_tot_perANT)); + bool init_meas = measurements->n0_subband_power == NULL; allocCast2D(n0_subband_power, unsigned int, measurements->n0_subband_power, @@ -174,6 +175,9 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy if (nb_symb[rb] > 0) { for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { tmp_n0_subband[aarx][rb] /= nb_symb[rb]; + // Initialize n0_subband_power from the first measurement before EMA + if (init_meas) + n0_subband_power[aarx][rb] = tmp_n0_subband[aarx][rb]; // apply exponential moving average to smooth noise measurements n0_subband_power[aarx][rb] = 0.9 * n0_subband_power[aarx][rb] + 0.1 * tmp_n0_subband[aarx][rb]; n0_subband_tot_perPRB += n0_subband_power[aarx][rb]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a6f66d738a..e85adc709d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -910,6 +910,11 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con NR_SCHED_UNLOCK(&nrmac->sched_lock); return; } + // Msg4 Ack: reset average with first measurement + if (uci_01->ul_cqi != 0xff) { + UE->UE_sched_ctrl.pucch_pc.avg_rssi = uci_01->rssi; + UE->UE_sched_ctrl.pucch_pc.avg_snr = (uci_01->ul_cqi * 5 - 640) * 0.1; + } } if (harq_confidence == 1) { UE->mac_stats.pucch0_DTX++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index be869d9de9..c3ae6eaedf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -763,7 +763,7 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, if (ul_cqi != 0xff) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - // Msg3: reset average. If this fails (e.g., ul_cqi == 0xff) + // Msg3: reset average with first measurement. If this fails (e.g., ul_cqi == 0xff) // everything starts from predetermined value sched_ctrl->pusch_pc.avg_snr = 0.1 * (ul_cqi * 5 - 640); sched_ctrl->pusch_pc.avg_rssi = rssi;