diff --git a/lib/include/srsran/phy/ch_estimation/csi_rs.h b/lib/include/srsran/phy/ch_estimation/csi_rs.h index 1dae8fb52..fc87326bb 100644 --- a/lib/include/srsran/phy/ch_estimation/csi_rs.h +++ b/lib/include/srsran/phy/ch_estimation/csi_rs.h @@ -42,7 +42,7 @@ /** * @brief Describes a measurement for NZP-CSI-RS * @note Used for fine tracking RSRP, SNR, CFO, SFO, and so on - * @note srsran_csi_measurements_t is used for CSI report generation + * @note srsran_csi_channel_measurements_t is used for CSI report generation */ typedef struct SRSRAN_API { float rsrp; ///< Linear scale RSRP @@ -57,7 +57,7 @@ typedef struct SRSRAN_API { float delay_us; ///< Average measured delay in microseconds uint32_t nof_re; ///< Number of available RE for the measurement, it can be used for weighting among different ///< measurements -} srsran_csi_rs_nzp_measure_t; +} srsran_csi_trs_measurements_t; /** * @brief Calculates if the given periodicity implies a CSI-RS transmission in the given slot @@ -118,7 +118,7 @@ SRSRAN_API int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* car const srsran_slot_cfg_t* slot_cfg, const srsran_csi_rs_nzp_resource_t* resource, const cf_t* grid, - srsran_csi_rs_nzp_measure_t* measure); + srsran_csi_trs_measurements_t* measure); /** * @brief Performs measurements of NZP-CSI-RS resource set flagged as TRS @@ -150,9 +150,11 @@ SRSRAN_API int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carr const srsran_slot_cfg_t* slot_cfg, const srsran_csi_rs_nzp_set_t* set, const cf_t* grid, - srsran_csi_rs_nzp_measure_t* measure); + srsran_csi_trs_measurements_t* measure); -SRSRAN_API uint32_t srsran_csi_rs_measure_info(const srsran_csi_rs_nzp_measure_t* measure, char* str, uint32_t str_len); +SRSRAN_API uint32_t srsran_csi_rs_measure_info(const srsran_csi_trs_measurements_t* measure, + char* str, + uint32_t str_len); /** * @brief Performs channel measurements of NZP-CSI-RS resource set for CSI reports @@ -172,11 +174,11 @@ SRSRAN_API uint32_t srsran_csi_rs_measure_info(const srsran_csi_rs_nzp_measure_t * @return The number of NZP-CSI-RS resources scheduled for this slot if the configuration is right, SRSLTE_ERROR code * if the configuration is invalid */ -SRSRAN_API int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* carrier, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_nzp_set_t* set, - const cf_t* grid, - srsran_csi_measurements_t* measure); +SRSRAN_API int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* carrier, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* set, + const cf_t* grid, + srsran_csi_channel_measurements_t* measure); /** * @brief Performs measurements of ZP-CSI-RS resource set for CSI reports @@ -194,10 +196,10 @@ SRSRAN_API int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* * @return The number of ZP-CSI-RS resources scheduled for this slot if the configuration is right, SRSLTE_ERROR code if * the configuration is invalid */ -SRSRAN_API int srsran_csi_rs_zp_measure_channel(const srsran_carrier_nr_t* carrier, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_zp_set_t* set, - const cf_t* grid, - srsran_csi_measurements_t* measure); +SRSRAN_API int srsran_csi_rs_zp_measure_channel(const srsran_carrier_nr_t* carrier, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_zp_set_t* set, + const cf_t* grid, + srsran_csi_channel_measurements_t* measure); #endif // SRSRAN_CSI_RS_H_ diff --git a/lib/include/srsran/phy/phch/csi.h b/lib/include/srsran/phy/phch/csi.h index eaca13393..c59e48b5b 100644 --- a/lib/include/srsran/phy/phch/csi.h +++ b/lib/include/srsran/phy/phch/csi.h @@ -15,11 +15,20 @@ #include "uci_cfg_nr.h" +/** + * @brief Processes a new NZP-CSI-RS channel measurement, it maps the given measurement into the current measurements + * applying an exponential moving average filter + * @param csi_resources CSI Resource configuration, links NZP-CSI-RS resources with CSI Measurements + * @param measurements Current CSI measurements + * @param new_measure New NZP-CSI-RS channel measurement + * @param nzp_csi_rs_id NZP-CSI-RS resource set identifier + * @return SRSLTE_SUCCESS if the provided information is valid, SRSLTE_ERROR code otherwise + */ SRSRAN_API int srsran_csi_new_nzp_csi_rs_measurement(const srsran_csi_hl_resource_cfg_t csi_resources[SRSRAN_CSI_MAX_NOF_RESOURCES], - srsran_csi_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], - const srsran_csi_measurements_t* new_measure, - uint32_t nzp_csi_rs_id); + srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], + const srsran_csi_channel_measurements_t* new_measure, + uint32_t nzp_csi_rs_id); /** * @brief Generates CSI report configuration and values from the higher layer configuration and a list of measurements @@ -29,11 +38,12 @@ srsran_csi_new_nzp_csi_rs_measurement(const srsran_csi_hl_resource_cfg_t csi_res * @param[out] report_cfg Report configuration re * @return The number CSI reports for transmission if the provided data is valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, - uint32_t slot_idx, - const srsran_csi_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], - srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT], - srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]); +SRSRAN_API int +srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], + srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT], + srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]); /** * @brief Compute number of CSI bits necessary to transmit all the CSI reports for a PUCCH transmission diff --git a/lib/include/srsran/phy/phch/csi_cfg.h b/lib/include/srsran/phy/phch/csi_cfg.h index 73382e9b6..5fb4e3b84 100644 --- a/lib/include/srsran/phy/phch/csi_cfg.h +++ b/lib/include/srsran/phy/phch/csi_cfg.h @@ -147,7 +147,7 @@ typedef struct SRSRAN_API { } srsran_csi_hl_cfg_t; /** - * @brief Generic CSI measurement structure + * @brief Generic CSI measurement structure, used for generating CSI reports */ typedef struct SRSRAN_API { uint32_t cri; ///< CSI-RS Resource Indicator @@ -158,7 +158,7 @@ typedef struct SRSRAN_API { // Resource set context uint32_t nof_ports; ///< Number of antenna ports uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set -} srsran_csi_measurements_t; +} srsran_csi_channel_measurements_t; /** * @brief CSI report configuration diff --git a/lib/include/srsran/phy/ue/ue_dl_nr.h b/lib/include/srsran/phy/ue/ue_dl_nr.h index 380538d98..ded651383 100644 --- a/lib/include/srsran/phy/ue/ue_dl_nr.h +++ b/lib/include/srsran/phy/ue/ue_dl_nr.h @@ -174,9 +174,15 @@ SRSRAN_API int srsran_ue_dl_nr_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, srs SRSRAN_API uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len); SRSRAN_API -int srsran_ue_dl_nr_csi_measure(const srsran_ue_dl_nr_t* q, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, - srsran_csi_measurements_t* measurement); +int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, + srsran_csi_trs_measurements_t* measurement); + +SRSRAN_API +int srsran_ue_dl_nr_csi_measure_channel(const srsran_ue_dl_nr_t* q, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, + srsran_csi_channel_measurements_t* measurement); #endif // SRSRAN_UE_DL_NR_H diff --git a/lib/src/phy/ch_estimation/csi_rs.c b/lib/src/phy/ch_estimation/csi_rs.c index df6cdc166..e604ae5ee 100644 --- a/lib/src/phy/ch_estimation/csi_rs.c +++ b/lib/src/phy/ch_estimation/csi_rs.c @@ -177,7 +177,7 @@ static uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier, uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot_cfg->idx); uint32_t n_id = resource->scrambling_id; - return SRSRAN_SEQUENCE_MOD(((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id); + return SRSRAN_SEQUENCE_MOD((((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 10UL) + n_id); } bool srsran_csi_rs_send(const srsran_csi_rs_period_and_offset_t* periodicity, const srsran_slot_cfg_t* slot_cfg) @@ -538,16 +538,22 @@ static int csi_rs_nzp_measure_resource(const srsran_carrier_nr_t* carri } // Compute LSE - srsran_sequence_state_apply_f(&sequence_state, (float*)lse, (float*)lse, 2 * count_re); + cf_t r[CSI_RS_MAX_SUBC_PRB * SRSRAN_MAX_PRB_NR]; + srsran_sequence_state_gen_f(&sequence_state, M_SQRT1_2, (float*)r, 2 * count_re); + srsran_vec_prod_conj_ccc(lse, r, lse, count_re); + + // Compute average delay + float delay = srsran_vec_estimate_frequency(lse, (int)count_re); + delay_acc += delay; + + // Pre-compensate delay to avoid RSRP measurements get affected by average delay + srsran_vec_apply_cfo(lse, delay, lse, (int)count_re); // Compute EPRE epre_acc += srsran_vec_avg_power_cf(lse, count_re); // Compute correlation corr_acc += srsran_vec_acc_cc(lse, count_re) / (float)count_re; - - // Compute average delay - delay_acc += srsran_vec_estimate_frequency(lse, count_re); } // Set measure fields @@ -591,7 +597,7 @@ int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* carrier, const srsran_slot_cfg_t* slot_cfg, const srsran_csi_rs_nzp_resource_t* resource, const cf_t* grid, - srsran_csi_rs_nzp_measure_t* measure) + srsran_csi_trs_measurements_t* measure) { if (carrier == NULL || slot_cfg == NULL || resource == NULL || grid == NULL || measure == NULL) { return SRSRAN_ERROR; @@ -605,7 +611,7 @@ int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* carrier, // Copy measurements measure->epre = m.epre; - measure->rsrp = (__real__ m.corr * __real__ m.corr + __imag__ m.corr * __imag__ m.corr); + measure->rsrp = SRSRAN_CSQABS(m.corr); measure->delay_us = m.delay_us; measure->nof_re = m.nof_re; @@ -616,7 +622,7 @@ int srsran_csi_rs_nzp_measure(const srsran_carrier_nr_t* carrier, measure->n0 = 0.0f; } - // CFo cannot be estimated with a single resource + // CFO cannot be estimated with a single resource measure->cfo_hz = 0.0f; measure->cfo_hz_max = 0.0f; @@ -633,7 +639,7 @@ int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carrier, const srsran_slot_cfg_t* slot_cfg, const srsran_csi_rs_nzp_set_t* set, const cf_t* grid, - srsran_csi_rs_nzp_measure_t* measure) + srsran_csi_trs_measurements_t* measure) { // Verify inputs if (carrier == NULL || slot_cfg == NULL || set == NULL || grid == NULL || measure == NULL) { @@ -680,9 +686,7 @@ int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carrier, uint32_t nof_re = 0; for (uint32_t i = 0; i < count; i++) { epre_sum += measurements[i].epre / (float)count; - rsrp_sum += (__real__ measurements[i].corr * __real__ measurements[i].corr + - __imag__ measurements[i].corr * __imag__ measurements[i].corr) / - (float)count; + rsrp_sum += SRSRAN_CSQABS(measurements[i].corr) / (float)count; delay_sum += measurements[i].delay_us / (float)count; nof_re += measurements[i].nof_re; } @@ -732,11 +736,11 @@ int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carrier, return count; } -int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* carrier, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_nzp_set_t* set, - const cf_t* grid, - srsran_csi_measurements_t* measure) +int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* carrier, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* set, + const cf_t* grid, + srsran_csi_channel_measurements_t* measure) { // Verify inputs if (carrier == NULL || slot_cfg == NULL || set == NULL || grid == NULL || measure == NULL) { @@ -761,9 +765,7 @@ int srsran_csi_rs_nzp_measure_channel(const srsran_carrier_nr_t* carrier, float rsrp_sum = 0.0f; for (uint32_t i = 0; i < count; i++) { epre_sum += measurements[i].epre / (float)count; - rsrp_sum += (__real__ measurements[i].corr * __real__ measurements[i].corr + - __imag__ measurements[i].corr * __imag__ measurements[i].corr) / - (float)count; + rsrp_sum += SRSRAN_CSQABS(measurements[i].corr) / (float)count; } // Estimate noise from EPRE and RSPR @@ -909,11 +911,11 @@ static int csi_rs_zp_measure_set(const srsran_carrier_nr_t* carrier, return count; } -int srsran_csi_rs_zp_measure_channel(const srsran_carrier_nr_t* carrier, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_zp_set_t* set, - const cf_t* grid, - srsran_csi_measurements_t* measure) +int srsran_csi_rs_zp_measure_channel(const srsran_carrier_nr_t* carrier, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_zp_set_t* set, + const cf_t* grid, + srsran_csi_channel_measurements_t* measure) { // Verify inputs if (carrier == NULL || slot_cfg == NULL || set == NULL || grid == NULL || measure == NULL) { @@ -953,7 +955,7 @@ int srsran_csi_rs_zp_measure_channel(const srsran_carrier_nr_t* carrier, return count; } -uint32_t srsran_csi_rs_measure_info(const srsran_csi_rs_nzp_measure_t* measure, char* str, uint32_t str_len) +uint32_t srsran_csi_rs_measure_info(const srsran_csi_trs_measurements_t* measure, char* str, uint32_t str_len) { uint32_t len = 0; @@ -972,4 +974,4 @@ uint32_t srsran_csi_rs_measure_info(const srsran_csi_rs_nzp_measure_t* measure, } return len; -} \ No newline at end of file +} diff --git a/lib/src/phy/ch_estimation/test/csi_rs_test.c b/lib/src/phy/ch_estimation/test/csi_rs_test.c index 095b0774e..ea96b06d1 100644 --- a/lib/src/phy/ch_estimation/test/csi_rs_test.c +++ b/lib/src/phy/ch_estimation/test/csi_rs_test.c @@ -39,7 +39,7 @@ static int nzp_test_case(const srsran_slot_cfg_t* slot_cfg, srsran_channel_awgn_t* awgn, cf_t* grid) { - srsran_csi_rs_nzp_measure_t measure = {}; + srsran_csi_trs_measurements_t measure = {}; // Put NZP-CSI-RS TESTASSERT(srsran_csi_rs_nzp_put_resource(&carrier, slot_cfg, resource, grid) == SRSRAN_SUCCESS); @@ -316,8 +316,8 @@ static int nzp_test_trs(srsran_channel_awgn_t* awgn, cf_t* grid) srsran_channel_awgn_run_c(awgn, grid, grid, SRSRAN_SLOT_LEN_RE_NR(carrier.nof_prb)); // Measure - srsran_csi_rs_nzp_measure_t measure = {}; - ret = srsran_csi_rs_nzp_measure_trs(&carrier, &slot_cfg, &set, grid, &measure); + srsran_csi_trs_measurements_t measure = {}; + ret = srsran_csi_rs_nzp_measure_trs(&carrier, &slot_cfg, &set, grid, &measure); // Check return and assert measurement if (slot_cfg.idx == 11 || slot_cfg.idx == 12) { diff --git a/lib/src/phy/phch/csi.c b/lib/src/phy/phch/csi.c index 9d87134a5..d7d7a1704 100644 --- a/lib/src/phy/phch/csi.c +++ b/lib/src/phy/phch/csi.c @@ -36,11 +36,11 @@ static bool csi_report_trigger(const srsran_csi_hl_report_cfg_t* cfg, uint32_t s return false; } -static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_t* cfg, - const srsran_csi_measurements_t* channel_meas, - const srsran_csi_measurements_t* interf_meas, - srsran_csi_report_cfg_t* report_cfg, - srsran_csi_report_value_t* report_value) +static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_t* cfg, + const srsran_csi_channel_measurements_t* channel_meas, + const srsran_csi_channel_measurements_t* interf_meas, + srsran_csi_report_cfg_t* report_cfg, + srsran_csi_report_value_t* report_value) { // Take SNR by default float wideband_sinr_db = channel_meas->wideband_snr_db; @@ -145,10 +145,10 @@ csi_none_unpack(const srsran_csi_report_cfg_t* cfg, const uint8_t* o_csi1, srsra } int srsran_csi_new_nzp_csi_rs_measurement( - const srsran_csi_hl_resource_cfg_t csi_resources[SRSRAN_CSI_MAX_NOF_RESOURCES], - srsran_csi_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], - const srsran_csi_measurements_t* new_measure, - uint32_t nzp_csi_rs_id) + const srsran_csi_hl_resource_cfg_t csi_resources[SRSRAN_CSI_MAX_NOF_RESOURCES], + srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], + const srsran_csi_channel_measurements_t* new_measure, + uint32_t nzp_csi_rs_id) { if (csi_resources == NULL || measurements == NULL || new_measure == NULL) { return SRSRAN_ERROR_INVALID_INPUTS; @@ -190,11 +190,11 @@ int srsran_csi_new_nzp_csi_rs_measurement( return SRSRAN_SUCCESS; } -int srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, - uint32_t slot_idx, - const srsran_csi_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], - srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT], - srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]) +int srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], + srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT], + srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]) { uint32_t count = 0; @@ -215,10 +215,10 @@ int srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, ERROR("Channel measurement ID (%d) is out of range", cfg->reports->channel_meas_id); return SRSRAN_ERROR; } - const srsran_csi_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id]; + const srsran_csi_channel_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id]; // Select interference measurement - const srsran_csi_measurements_t* interf_meas = NULL; + const srsran_csi_channel_measurements_t* interf_meas = NULL; if (cfg->reports->interf_meas_present) { if (cfg->reports->interf_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) { ERROR("Interference measurement ID (%d) is out of range", cfg->reports->interf_meas_id); diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index 8c6105078..fab77bdf7 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -839,14 +839,26 @@ uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* s return len; } -int srsran_ue_dl_nr_csi_measure(const srsran_ue_dl_nr_t* q, - const srsran_slot_cfg_t* slot_cfg, - const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, - srsran_csi_measurements_t* measurement) +int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, + srsran_csi_trs_measurements_t* measurement) +{ + if (q == NULL || slot_cfg == NULL || csi_rs_nzp_set == NULL || measurement == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + return srsran_csi_rs_nzp_measure_trs(&q->carrier, slot_cfg, csi_rs_nzp_set, q->sf_symbols[0], measurement); +} + +int srsran_ue_dl_nr_csi_measure_channel(const srsran_ue_dl_nr_t* q, + const srsran_slot_cfg_t* slot_cfg, + const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, + srsran_csi_channel_measurements_t* measurement) { if (q == NULL || slot_cfg == NULL || csi_rs_nzp_set == NULL || measurement == NULL) { return SRSRAN_ERROR_INVALID_INPUTS; } return srsran_csi_rs_nzp_measure_channel(&q->carrier, slot_cfg, csi_rs_nzp_set, q->sf_symbols[0], measurement); -} \ No newline at end of file +} diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 4c95702f4..1688117ce 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -58,11 +58,17 @@ private: void decode_pdcch_ul(); void decode_pdcch_dl(); - // Method for decode PDSCH + /** + * @brief Decodes PDSCH in the current processing slot + * @return true if current configuration is valid and no error occur, false otherwise + */ bool decode_pdsch_dl(); - // Method for measurements - bool measure(); + /** + * @brief Performs Channel State Information (CSI) measurements + * @return true if current configuration is valid and no error occur, false otherwise + */ + bool measure_csi(); }; } // namespace nr diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 0cc50622d..fbac9a8e8 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -57,8 +57,8 @@ private: mutable std::mutex metrics_mutex; /// CSI-RS measurements - std::mutex csi_measurements_mutex; - std::array csi_measurements = {}; + std::mutex csi_measurements_mutex; + std::array csi_measurements = {}; /** * @brief Resets all metrics (unprotected) @@ -278,6 +278,7 @@ public: { clear_pending_grants(); reset_metrics(); + reset_measurements(); } bool has_valid_sr_resource(uint32_t sr_id) @@ -424,7 +425,22 @@ public: reset_metrics_(); } - void new_nzp_csi_rs_channel_measurement(const srsran_csi_measurements_t& new_measure, uint32_t resource_set_id) + /** + * @brief Resets all PHY measurements (protected) + */ + void reset_measurements() + { + std::lock_guard lock(csi_measurements_mutex); + csi_measurements = {}; + } + + /** + * @brief Processes a new NZP-CSI-RS channel measurement + * @param new_measure New measurement + * @param resource_set_id NZP-CSI-RS resource set identifier used for the channel measurement + */ + void new_nzp_csi_rs_channel_measurement(const srsran_csi_channel_measurements_t& new_measure, + uint32_t resource_set_id) { std::lock_guard lock(csi_measurements_mutex); diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index e0025a0ec..b1b1d1c68 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -200,7 +200,7 @@ bool cc_worker::decode_pdsch_dl() srsran_pdsch_ack_resource_nr_t ack_resource = {}; if (not phy->get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) { // Early return if no grant was available - return false; + return true; } // Notify MAC about PDSCH grant mac_interface_phy_nr::tb_action_dl_t dl_action = {}; @@ -291,42 +291,101 @@ bool cc_worker::decode_pdsch_dl() dl_m.fec_iters = pdsch_res.tb[0].avg_iter; dl_m.evm = pdsch_res.evm[0]; phy->set_dl_metrics(dl_m); - - // Generate Synch metrics - sync_metrics_t sync_m = {}; - sync_m.cfo = ue_dl.chest.cfo; - phy->set_sync_metrics(sync_m); - - // Generate channel metrics - ch_metrics_t ch_m = {}; - ch_m.n = ue_dl.chest.noise_estimate; - ch_m.sinr = ue_dl.chest.snr_db; - ch_m.rsrp = ue_dl.chest.rsrp_dbm; - ch_m.sync_err = ue_dl.chest.sync_error; - phy->set_channel_metrics(ch_m); } return true; } -bool cc_worker::measure() +bool cc_worker::measure_csi() { - // Iterate all NZP-CSI-RS and perform channel measurements + // Iterate all NZP-CSI-RS marked as TRS and perform channel measurements for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) { // Select NZP-CSI-RS set const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; - srsran_csi_measurements_t measurements = {}; - int n = srsran_ue_dl_nr_csi_measure(&ue_dl, &dl_slot_cfg, &nzp_set, &measurements); + // Skip set if not set as TRS (it will be processed later) + if (not nzp_set.trs_info) { + continue; + } + + // Perform measurement, n > 0 is any measurement is performed, n = 0 otherwise + srsran_csi_trs_measurements_t trs_measurements = {}; + int n = srsran_ue_dl_nr_csi_measure_trs(&ue_dl, &dl_slot_cfg, &nzp_set, &trs_measurements); if (n < SRSRAN_SUCCESS) { logger.error("Error measuring CSI-RS"); return false; } - // Report new measurement to the PHY state - if (n > 0) { - phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); + // If no measurement performed, skip + if (n == 0) { + continue; } + + logger.info("NZP-CSI-RS (TRS): id=%d rsrp=%+.1f epre=%+.1f snr=%+.1f cfo=%+.1f delay=%.1f", + resource_set_id, + trs_measurements.rsrp_dB, + trs_measurements.epre_dB, + trs_measurements.snr_dB, + trs_measurements.cfo_hz, + trs_measurements.delay_us); + + // Compute channel metrics and push it + ch_metrics_t ch_metrics = {}; + ch_metrics.sinr = trs_measurements.snr_dB; + ch_metrics.rsrp = trs_measurements.rsrp_dB; + ch_metrics.rsrq = 0.0f; // Not supported + ch_metrics.rssi = 0.0f; // Not supported + ch_metrics.sync_err = + trs_measurements.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs)); + phy->set_channel_metrics(ch_metrics); + + // Compute synch metrics and report it to the PHY state + sync_metrics_t sync_metrics = {}; + sync_metrics.cfo = trs_measurements.cfo_hz; + phy->set_sync_metrics(sync_metrics); + + // Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state + srsran_csi_channel_measurements_t measurements = {}; + measurements.cri = 0; + measurements.wideband_rsrp_dBm = trs_measurements.rsrp_dB; + measurements.wideband_epre_dBm = trs_measurements.epre_dB; + measurements.wideband_snr_db = trs_measurements.snr_dB; + measurements.nof_ports = 1; // Other values are not supported + measurements.K_csi_rs = (uint32_t)n; + phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); + } + + // Iterate all NZP-CSI-RS not marked as TRS and perform channel measurements + for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) { + // Select NZP-CSI-RS set + const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; + + // Skip set if set as TRS (it was processed previously) + if (nzp_set.trs_info) { + continue; + } + + // Perform channel measurement, n > 0 is any measurement is performed, n = 0 otherwise + srsran_csi_channel_measurements_t measurements = {}; + int n = srsran_ue_dl_nr_csi_measure_channel(&ue_dl, &dl_slot_cfg, &nzp_set, &measurements); + if (n < SRSRAN_SUCCESS) { + logger.error("Error measuring CSI-RS"); + return false; + } + + // If no measurement performed, skip + if (n == 0) { + continue; + } + + logger.info("NZP-CSI-RS: id=%d, rsrp=%+.1f epre=%+.1f snr=%+.1f", + resource_set_id, + measurements.wideband_rsrp_dBm, + measurements.wideband_epre_dBm, + measurements.wideband_snr_db); + + // Report new measurement to the PHY state + phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); } return true; @@ -360,8 +419,8 @@ bool cc_worker::work_dl() } // Measure CSI-RS - if (not measure()) { - logger.error("Error measuring CSI-RS, aborting work DL"); + if (not measure_csi()) { + logger.error("Error measuring, aborting work DL"); return false; }