diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index cc8dc5e11..49c34e962 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -111,43 +111,58 @@ int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0); - if (n_pucch == 0) { - ERROR("Error getting number of symbols"); - return SRSRAN_ERROR; - } - + // First symbol index uint32_t l_prime = resource->start_symbol_idx; - for (uint32_t m = 0; m < n_pucch; m++) { - // Clause 6.4.1.3.1.2 specifies l=0,2,4... - uint32_t l = m * 2; - // Get start of the sequence in resource grid - cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; - - // Get Alpha index - uint32_t alpha_idx = 0; - if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < - SRSRAN_SUCCESS) { - ERROR("Calculating alpha"); - } - - // get r_uv sequence from LUT object - const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); - if (r_uv == NULL) { - ERROR("Getting r_uv sequence"); + // Clause 6.4.1.3.1.2 specifies l=0,2,4... + for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) { + // Get number of symbols carrying DMRS + uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime); + if (n_pucch == 0) { + ERROR("Error getting number of symbols"); return SRSRAN_ERROR; } - // Get w_i_m - cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + // Get the starting PRB + uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb; - // Compute z(n) = w(i) * r_uv(n) - cf_t z[SRSRAN_NRE]; - srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + for (uint32_t m = 0; m < n_pucch; m++, l += 2) { + // Get start of the sequence in resource grid + cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE]; - // Put z in the grid - srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE); + // Get Alpha index + uint32_t alpha_idx = 0; + if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < + SRSRAN_SUCCESS) { + ERROR("Calculating alpha"); + } + + // get r_uv sequence from LUT object + const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); + if (r_uv == NULL) { + ERROR("Getting r_uv sequence"); + return SRSRAN_ERROR; + } + + // Get w_i_m + cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + + // Compute z(n) = w(i) * r_uv(n) + cf_t z[SRSRAN_NRE]; + srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 DMRS TX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f; z=", + m_prime, + m, + __real__ w_i_m, + __imag__ w_i_m); + srsran_vec_fprint_c(stdout, z, SRSRAN_NRE); + } + + // Put z in the grid + srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE); + } } return SRSRAN_SUCCESS; @@ -177,50 +192,71 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0); - if (n_pucch == 0) { - ERROR("Error getting number of symbols"); - return SRSRAN_ERROR; - } - - cf_t ce[SRSRAN_PUCCH_NR_FORMAT1_N_MAX][SRSRAN_NRE]; - - // Prevent ce[m] overflow - assert(n_pucch <= SRSRAN_PUCCH_NR_FORMAT1_N_MAX); + uint32_t start_rb_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX]; + uint32_t symbol_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX]; + cf_t ce[SRSRAN_PUCCH_NR_FORMAT1_N_MAX][SRSRAN_NRE]; + // First symbol index uint32_t l_prime = resource->start_symbol_idx; - for (uint32_t m = 0; m < n_pucch; m++) { - // Clause 6.4.1.3.1.2 specifies l=0,2,4... - uint32_t l = m * 2; - // Get start of the sequence in resource grid - const cf_t* slot_symbols_ptr = - &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; - - // Get Alpha index - uint32_t alpha_idx = 0; - if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < - SRSRAN_SUCCESS) { - ERROR("Calculating alpha"); - } - - // get r_uv sequence from LUT object - const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); - if (r_uv == NULL) { - ERROR("Getting r_uv sequence"); + uint32_t n_pucch_sum = 0; + for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) { + // Get number of symbols carrying DMRS + uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime); + if (n_pucch == 0) { + ERROR("Error getting number of symbols"); return SRSRAN_ERROR; } - // Get w_i_m - cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + // Prevent ce[m] overflow + assert(n_pucch <= SRSRAN_PUCCH_NR_FORMAT1_N_MAX); - // Compute z(n) = w(i) * r_uv(n) - cf_t z[SRSRAN_NRE]; - srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + // Get the starting PRB + uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb; + start_rb_idx[n_pucch_sum] = starting_prb; - // TODO: can ce[m] overflow? - // Calculate least square estimates for this symbol - srsran_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[m], SRSRAN_NRE); + for (uint32_t m = 0; m < n_pucch; m++, l += 2) { // Clause 6.4.1.3.1.2 specifies l=0,2,4... + symbol_idx[n_pucch_sum] = l + l_prime; + + // Get start of the sequence in resource grid + const cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE]; + + // Get Alpha index + uint32_t alpha_idx = 0; + if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < + SRSRAN_SUCCESS) { + ERROR("Calculating alpha"); + } + + // get r_uv sequence from LUT object + const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); + if (r_uv == NULL) { + ERROR("Getting r_uv sequence"); + return SRSRAN_ERROR; + } + + // Get w_i_m + cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + + // Compute z(n) = w(i) * r_uv(n) + cf_t z[SRSRAN_NRE]; + srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + INFO("[PUCCH Format 1 DMRS RX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f", m_prime, m, __real__ w_i_m, __imag__ w_i_m); + srsran_vec_fprint_c(stdout, z, SRSRAN_NRE); + } + + // TODO: can ce[m] overflow? + // Calculate least square estimates for this symbol + srsran_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[n_pucch_sum], SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 DMRS RX] ce[%d]=", n_pucch_sum); + srsran_vec_fprint_c(stdout, ce[n_pucch_sum], SRSRAN_NRE); + } + n_pucch_sum++; + } } // Perform measurements @@ -228,7 +264,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, float epre = 0.0f; float ta_err = 0.0f; cf_t corr[SRSRAN_PUCCH_NR_FORMAT1_N_MAX] = {}; - for (uint32_t m = 0; m < n_pucch; m++) { + for (uint32_t m = 0; m < n_pucch_sum; m++) { corr[m] = srsran_vec_acc_cc(ce[m], SRSRAN_NRE) / SRSRAN_NRE; rsrp += SRSRAN_CSQABS(corr[m]); epre += srsran_vec_avg_power_cf(ce[m], SRSRAN_NRE); @@ -236,9 +272,9 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, } // Average measurements - rsrp /= n_pucch; - epre /= n_pucch; - ta_err /= n_pucch; + rsrp /= n_pucch_sum; + epre /= n_pucch_sum; + ta_err /= n_pucch_sum; // Set power measures rsrp = SRSRAN_MIN(rsrp, epre); @@ -262,16 +298,16 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, } // Measure CFO - if (n_pucch > 1) { + if (n_pucch_sum > 1) { float cfo_avg_hz = 0.0f; - for (uint32_t m = 0; m < n_pucch - 1; m++) { + for (uint32_t m = 0; m < n_pucch_sum - 1; m++) { uint32_t l0 = resource->start_symbol_idx + m * 2; uint32_t l1 = resource->start_symbol_idx + (m + 1) * 2; float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs); float phase_diff = cargf(corr[m + 1] * conjf(corr[m])); if (isnormal(time_diff)) { - cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (n_pucch - 1)); + cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (n_pucch_sum - 1)); } } res->cfo_hz = cfo_avg_hz; @@ -283,11 +319,10 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, // ... Not implemented // Interpolates between DMRS symbols - for (uint32_t m = 0; m < n_pucch; m++) { - uint32_t l = m * 2 + 1; - cf_t* ce_ptr = &res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; + for (uint32_t m = 0; m < n_pucch_sum; m++) { + cf_t* ce_ptr = &res->ce[m * SRSRAN_NRE]; - if (m != n_pucch - 1) { + if (m != n_pucch_sum - 1) { // If it is not the last symbol with DMRS, average between srsran_vec_sum_ccc(ce[m], ce[m + 1], ce_ptr, SRSRAN_NRE); srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE); @@ -297,7 +332,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, srsran_vec_sub_ccc(ce_ptr, ce[m - 1], ce_ptr, SRSRAN_NRE); srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE); } else { - // Simply copy the + // Simply copy the estimated channel srsran_vec_cf_copy(ce_ptr, ce[m], SRSRAN_NRE); } } diff --git a/lib/src/phy/phch/pucch_cfg_nr.c b/lib/src/phy/phch/pucch_cfg_nr.c index 3e79902cb..1f9675538 100644 --- a/lib/src/phy/phch/pucch_cfg_nr.c +++ b/lib/src/phy/phch/pucch_cfg_nr.c @@ -160,7 +160,8 @@ int srsran_pucch_nr_cfg_resource_valid(const srsran_pucch_nr_resource_t* resourc return SRSRAN_ERROR; } - if (resource->intra_slot_hopping) { + // Frequency hopping is only possible with Format 1 + if (resource->intra_slot_hopping && resource->format != SRSRAN_PUCCH_NR_FORMAT_1) { ERROR("Intra-slot hopping is not implemented"); return SRSRAN_ERROR; } diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 9c0472d38..72e74d816 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -397,6 +397,8 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q, srsran_mod_modulate(&q->qpsk, b, d, 2); } + INFO("[PUCCH Format 1 Data TX] d=%+.3f%+.3f", __real__ d[0], __imag__ d[0]); + // Get group sequence uint32_t u = 0; uint32_t v = 0; @@ -405,41 +407,60 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - // Calculate number of symbols carrying PUCCH (No DMRS) - uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0); - + // First symbol of this PUCCH transmission uint32_t l_prime = resource->start_symbol_idx; - for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) { - // Get start of the sequence in resource grid - cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; - // Get Alpha index - uint32_t alpha_idx = 0; - if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < - SRSRAN_SUCCESS) { - return SRSRAN_ERROR; + // For each hop + for (uint32_t m_prime = 0, l = 1; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) { + // Calculate number of symbols carrying PUCCH (No DMRS) + uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, m_prime); + + // Get the starting PRB + uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb; + + // For each symbol carrying PUCCH data + for (uint32_t m = 0; m < n_pucch; m++, l += 2) { + // Get start of the sequence in resource grid + cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE]; + + // Get Alpha index + uint32_t alpha_idx = 0; + if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < + SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // get r_uv sequence from LUT object + const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); + if (r_uv == NULL) { + ERROR("Getting r_uv sequence"); + return SRSRAN_ERROR; + } + + // Get w_i_m + cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + + // Compute z(n) = w(i) * r_uv(n) + cf_t z[SRSRAN_NRE]; + srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 Data TX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f z=", + m_prime, + m, + __real__ w_i_m, + __imag__ w_i_m); + srsran_vec_fprint_c(stdout, z, SRSRAN_NRE); + } + + // Put z in the grid + srsran_vec_sc_prod_ccc(z, d[0], slot_symbols_ptr, SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 TX] l=%d; x=", l + l_prime); + srsran_vec_fprint_c(stdout, slot_symbols_ptr, SRSRAN_NRE); + } } - - // get r_uv sequence from LUT object - const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); - if (r_uv == NULL) { - ERROR("Getting r_uv sequence"); - return SRSRAN_ERROR; - } - - // Compute y = d(0) * r_uv - cf_t y[SRSRAN_NRE]; - srsran_vec_sc_prod_ccc(r_uv, d[0], y, SRSRAN_NRE); - - // Get w_i_m - cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); - - // Compute z(n) = w(i) * y(n) - cf_t z[SRSRAN_NRE]; - srsran_vec_sc_prod_ccc(y, w_i_m, z, SRSRAN_NRE); - - // Put z in the grid - srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE); } return SRSRAN_SUCCESS; @@ -484,46 +505,79 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - // Calculate number of symbols carrying PUCCH (No DMRS) - uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0); - + // First symbol of this PUCCH transmission uint32_t l_prime = resource->start_symbol_idx; - for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) { - // Get start of the sequence in resource grid - cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; - cf_t* ce_ptr = &chest_res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; - // Equalise x = w(i) * d' * r_uv(n) - cf_t x[SRSRAN_NRE]; - srsran_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSRAN_NRE, 1.0f, chest_res->noise_estimate); + // For each hop + uint32_t n_pucch_sum = 0; + for (uint32_t m_prime = 0, l = 1; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) { + // Calculate number of symbols carrying PUCCH (No DMRS) + uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, m_prime); - // Get Alpha index - uint32_t alpha_idx = 0; - if (srsran_pucch_nr_alpha_idx( - &q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; + // Get the starting PRB + uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb; + + // For each symbol carrying PUCCH data + for (uint32_t m = 0; m < n_pucch; m++, l += 2) { + // Get start of the sequence in resource grid + cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE]; + cf_t* ce_ptr = &chest_res->ce[SRSRAN_NRE * n_pucch_sum]; + n_pucch_sum++; + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 CE RX] ce="); + srsran_vec_fprint_c(stdout, ce_ptr, SRSRAN_NRE); + } + + // Equalise x = w(i) * d' * r_uv(n) + cf_t x[SRSRAN_NRE]; + srsran_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSRAN_NRE, 1.0f, chest_res->noise_estimate); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 RX] l=%d; x=", l + l_prime); + srsran_vec_fprint_c(stdout, x, SRSRAN_NRE); + } + + // Get Alpha index + uint32_t alpha_idx = 0; + if (srsran_pucch_nr_alpha_idx( + &q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // get r_uv sequence from LUT object + const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); + if (r_uv == NULL) { + ERROR("Getting r_uv sequence"); + return SRSRAN_ERROR; + } + + // Get w_i_m + cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); + + // Compute z(n) = w(i) * r_uv(n) + cf_t z[SRSRAN_NRE]; + srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); + + if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) { + printf("[PUCCH Format 1 Data RX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f z=", + m_prime, + m, + __real__ w_i_m, + __imag__ w_i_m); + srsran_vec_fprint_c(stdout, z, SRSRAN_NRE); + } + + // Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d' + d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE) / SRSRAN_NRE; + + // Compute and accumulate average symbol power + pwr_acc += srsran_vec_avg_power_cf(x, SRSRAN_NRE); } - - // get r_uv sequence from LUT object - const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx); - if (r_uv == NULL) { - ERROR("Getting r_uv sequence"); - return SRSRAN_ERROR; - } - // Get w_i_m - cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m); - - // Compute z(n) = w(i) * r_uv(n) - cf_t z[SRSRAN_NRE]; - srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); - - // Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d' - d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE) / SRSRAN_NRE; - - // Compute and accumulate average symbol power - pwr_acc += srsran_vec_avg_power_cf(x, SRSRAN_NRE); } + INFO("[PUCCH Format 1 Data RX] d=%+.3f%+.3f", __real__ d, __imag__ d); + // Demodulate d float llr[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1); diff --git a/lib/src/phy/phch/test/pucch_nr_test.c b/lib/src/phy/phch/test/pucch_nr_test.c index 6779549de..d485b8099 100644 --- a/lib/src/phy/phch/test/pucch_nr_test.c +++ b/lib/src/phy/phch/test/pucch_nr_test.c @@ -79,63 +79,71 @@ static int test_pucch_format0(srsran_pucch_nr_t* pucch, const srsran_pucch_nr_co static int test_pucch_format1(srsran_pucch_nr_t* pucch, const srsran_pucch_nr_common_cfg_t* cfg, srsran_chest_ul_res_t* chest_res, - cf_t* slot_symbols) + cf_t* slot_symbols, + bool enable_intra_slot_hopping) { srsran_slot_cfg_t slot = {}; srsran_pucch_nr_resource_t resource = {}; resource.format = SRSRAN_PUCCH_NR_FORMAT_1; + resource.intra_slot_hopping = enable_intra_slot_hopping; for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) { for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb; resource.starting_prb += starting_prb_stride) { - for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB; - resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB; - resource.nof_symbols++) { - for (resource.start_symbol_idx = 0; - resource.start_symbol_idx <= - SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols); - resource.start_symbol_idx += starting_symbol_stride) { - for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC; - resource.time_domain_occ++) { - for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS; - resource.initial_cyclic_shift++) { - for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) { - for (uint32_t word = 0; word < (1U << nof_bits); word++) { - // Generate bits - uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {}; - for (uint32_t i = 0; i < nof_bits; i++) { - b[i] = (word >> i) & 1U; - } + for (resource.second_hop_prb = 0; resource.second_hop_prb < (enable_intra_slot_hopping) ? carrier.nof_prb : 0; + resource.second_hop_prb += starting_prb_stride) { + for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB; + resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB; + resource.nof_symbols++) { + for (resource.start_symbol_idx = 0; + resource.start_symbol_idx <= + SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols); + resource.start_symbol_idx += starting_symbol_stride) { + for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC; + resource.time_domain_occ++) { + for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS; + resource.initial_cyclic_shift++) { + for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) { + for (uint32_t word = 0; word < (1U << nof_bits); word++) { + // Generate bits + uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {}; + for (uint32_t i = 0; i < nof_bits; i++) { + b[i] = (word >> i) & 1U; + } - // Encode PUCCH - TESTASSERT(srsran_pucch_nr_format1_encode(pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) == - SRSRAN_SUCCESS); + // Encode PUCCH + TESTASSERT(srsran_pucch_nr_format1_encode( + pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) == SRSRAN_SUCCESS); - // Put DMRS - TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) == - SRSRAN_SUCCESS); + // Put DMRS + TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) == + SRSRAN_SUCCESS); - // Apply AWGN - srsran_channel_awgn_run_c( - &awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR); + // Apply AWGN + srsran_channel_awgn_run_c( + &awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR); - // Estimate channel - TESTASSERT(srsran_dmrs_pucch_format1_estimate( - pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS); + // Estimate channel + TESTASSERT(srsran_dmrs_pucch_format1_estimate( + pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS); - TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f); - TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f); - TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f); + TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f); + TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f); + TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f); - // Decode PUCCH - uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; - TESTASSERT(srsran_pucch_nr_format1_decode( - pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) == - SRSRAN_SUCCESS); + // Decode PUCCH + uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; + TESTASSERT(srsran_pucch_nr_format1_decode( + pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) == + SRSRAN_SUCCESS); - // Check received bits - for (uint32_t i = 0; i < nof_bits; i++) { - TESTASSERT(b[i] == b_rx[i]); + // Check received bits + for (uint32_t i = 0; i < nof_bits; i++) { + if (b[i] != b_rx[i]) { + printf("aaa"); + } + TESTASSERT(b[i] == b_rx[i]); + } } } } @@ -336,9 +344,13 @@ int main(int argc, char** argv) } } - // Test Format 1 + // Test Format 1 with and without intra slot frequency hopping if (format < 0 || format == 1) { - if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSRAN_SUCCESS) { + if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb, false) < SRSRAN_SUCCESS) { + ERROR("Failed PUCCH format 1"); + goto clean_exit; + } + if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb, true) < SRSRAN_SUCCESS) { ERROR("Failed PUCCH format 1"); goto clean_exit; }