mirror of https://github.com/PentHertz/srsLTE.git
PHY: Initial PUCCH Format 1 frequency hopping
This commit is contained in:
parent
bb9eaf4390
commit
99d2cd068f
|
@ -111,43 +111,58 @@ int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t* q,
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
// First symbol index
|
||||||
if (n_pucch == 0) {
|
|
||||||
ERROR("Error getting number of symbols");
|
|
||||||
return SRSRAN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t l_prime = resource->start_symbol_idx;
|
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
|
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||||
|
// Get number of symbols carrying DMRS
|
||||||
// Get Alpha index
|
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime);
|
||||||
uint32_t alpha_idx = 0;
|
if (n_pucch == 0) {
|
||||||
if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
ERROR("Error getting number of symbols");
|
||||||
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;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get w_i_m
|
// Get the starting PRB
|
||||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||||
|
|
||||||
// Compute z(n) = w(i) * r_uv(n)
|
for (uint32_t m = 0; m < n_pucch; m++, l += 2) {
|
||||||
cf_t z[SRSRAN_NRE];
|
// Get start of the sequence in resource grid
|
||||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE];
|
||||||
|
|
||||||
// Put z in the grid
|
// Get Alpha index
|
||||||
srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE);
|
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;
|
return SRSRAN_SUCCESS;
|
||||||
|
@ -177,50 +192,71 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
uint32_t start_rb_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX];
|
||||||
if (n_pucch == 0) {
|
uint32_t symbol_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX];
|
||||||
ERROR("Error getting number of symbols");
|
cf_t ce[SRSRAN_PUCCH_NR_FORMAT1_N_MAX][SRSRAN_NRE];
|
||||||
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);
|
|
||||||
|
|
||||||
|
// First symbol index
|
||||||
uint32_t l_prime = resource->start_symbol_idx;
|
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
|
uint32_t n_pucch_sum = 0;
|
||||||
const cf_t* slot_symbols_ptr =
|
for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||||
&slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
// Get number of symbols carrying DMRS
|
||||||
|
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime);
|
||||||
// Get Alpha index
|
if (n_pucch == 0) {
|
||||||
uint32_t alpha_idx = 0;
|
ERROR("Error getting number of symbols");
|
||||||
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;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get w_i_m
|
// Prevent ce[m] overflow
|
||||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
assert(n_pucch <= SRSRAN_PUCCH_NR_FORMAT1_N_MAX);
|
||||||
|
|
||||||
// Compute z(n) = w(i) * r_uv(n)
|
// Get the starting PRB
|
||||||
cf_t z[SRSRAN_NRE];
|
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
start_rb_idx[n_pucch_sum] = starting_prb;
|
||||||
|
|
||||||
// TODO: can ce[m] overflow?
|
for (uint32_t m = 0; m < n_pucch; m++, l += 2) { // Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||||
// Calculate least square estimates for this symbol
|
symbol_idx[n_pucch_sum] = l + l_prime;
|
||||||
srsran_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[m], SRSRAN_NRE);
|
|
||||||
|
// 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
|
// Perform measurements
|
||||||
|
@ -228,7 +264,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
||||||
float epre = 0.0f;
|
float epre = 0.0f;
|
||||||
float ta_err = 0.0f;
|
float ta_err = 0.0f;
|
||||||
cf_t corr[SRSRAN_PUCCH_NR_FORMAT1_N_MAX] = {};
|
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;
|
corr[m] = srsran_vec_acc_cc(ce[m], SRSRAN_NRE) / SRSRAN_NRE;
|
||||||
rsrp += SRSRAN_CSQABS(corr[m]);
|
rsrp += SRSRAN_CSQABS(corr[m]);
|
||||||
epre += srsran_vec_avg_power_cf(ce[m], SRSRAN_NRE);
|
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
|
// Average measurements
|
||||||
rsrp /= n_pucch;
|
rsrp /= n_pucch_sum;
|
||||||
epre /= n_pucch;
|
epre /= n_pucch_sum;
|
||||||
ta_err /= n_pucch;
|
ta_err /= n_pucch_sum;
|
||||||
|
|
||||||
// Set power measures
|
// Set power measures
|
||||||
rsrp = SRSRAN_MIN(rsrp, epre);
|
rsrp = SRSRAN_MIN(rsrp, epre);
|
||||||
|
@ -262,16 +298,16 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Measure CFO
|
// Measure CFO
|
||||||
if (n_pucch > 1) {
|
if (n_pucch_sum > 1) {
|
||||||
float cfo_avg_hz = 0.0f;
|
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 l0 = resource->start_symbol_idx + m * 2;
|
||||||
uint32_t l1 = resource->start_symbol_idx + (m + 1) * 2;
|
uint32_t l1 = resource->start_symbol_idx + (m + 1) * 2;
|
||||||
float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs);
|
float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs);
|
||||||
float phase_diff = cargf(corr[m + 1] * conjf(corr[m]));
|
float phase_diff = cargf(corr[m + 1] * conjf(corr[m]));
|
||||||
|
|
||||||
if (isnormal(time_diff)) {
|
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;
|
res->cfo_hz = cfo_avg_hz;
|
||||||
|
@ -283,11 +319,10 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
||||||
// ... Not implemented
|
// ... Not implemented
|
||||||
|
|
||||||
// Interpolates between DMRS symbols
|
// Interpolates between DMRS symbols
|
||||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
for (uint32_t m = 0; m < n_pucch_sum; m++) {
|
||||||
uint32_t l = m * 2 + 1;
|
cf_t* ce_ptr = &res->ce[m * SRSRAN_NRE];
|
||||||
cf_t* ce_ptr = &res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
|
||||||
|
|
||||||
if (m != n_pucch - 1) {
|
if (m != n_pucch_sum - 1) {
|
||||||
// If it is not the last symbol with DMRS, average between
|
// 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_sum_ccc(ce[m], ce[m + 1], ce_ptr, SRSRAN_NRE);
|
||||||
srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, 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_sub_ccc(ce_ptr, ce[m - 1], ce_ptr, SRSRAN_NRE);
|
||||||
srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE);
|
srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE);
|
||||||
} else {
|
} else {
|
||||||
// Simply copy the
|
// Simply copy the estimated channel
|
||||||
srsran_vec_cf_copy(ce_ptr, ce[m], SRSRAN_NRE);
|
srsran_vec_cf_copy(ce_ptr, ce[m], SRSRAN_NRE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,8 @@ int srsran_pucch_nr_cfg_resource_valid(const srsran_pucch_nr_resource_t* resourc
|
||||||
return SRSRAN_ERROR;
|
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");
|
ERROR("Intra-slot hopping is not implemented");
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,6 +397,8 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q,
|
||||||
srsran_mod_modulate(&q->qpsk, b, d, 2);
|
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
|
// Get group sequence
|
||||||
uint32_t u = 0;
|
uint32_t u = 0;
|
||||||
uint32_t v = 0;
|
uint32_t v = 0;
|
||||||
|
@ -405,41 +407,60 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q,
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
// First symbol of this PUCCH transmission
|
||||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0);
|
|
||||||
|
|
||||||
uint32_t l_prime = resource->start_symbol_idx;
|
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
|
// For each hop
|
||||||
uint32_t alpha_idx = 0;
|
for (uint32_t m_prime = 0, l = 1; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||||
if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
// Calculate number of symbols carrying PUCCH (No DMRS)
|
||||||
SRSRAN_SUCCESS) {
|
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, m_prime);
|
||||||
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];
|
||||||
|
|
||||||
|
// 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;
|
return SRSRAN_SUCCESS;
|
||||||
|
@ -484,46 +505,79 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
// First symbol of this PUCCH transmission
|
||||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0);
|
|
||||||
|
|
||||||
uint32_t l_prime = resource->start_symbol_idx;
|
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)
|
// For each hop
|
||||||
cf_t x[SRSRAN_NRE];
|
uint32_t n_pucch_sum = 0;
|
||||||
srsran_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSRAN_NRE, 1.0f, chest_res->noise_estimate);
|
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
|
// Get the starting PRB
|
||||||
uint32_t alpha_idx = 0;
|
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||||
if (srsran_pucch_nr_alpha_idx(
|
|
||||||
&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSRAN_SUCCESS) {
|
// For each symbol carrying PUCCH data
|
||||||
return SRSRAN_ERROR;
|
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
|
// Demodulate d
|
||||||
float llr[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
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);
|
srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1);
|
||||||
|
|
|
@ -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,
|
static int test_pucch_format1(srsran_pucch_nr_t* pucch,
|
||||||
const srsran_pucch_nr_common_cfg_t* cfg,
|
const srsran_pucch_nr_common_cfg_t* cfg,
|
||||||
srsran_chest_ul_res_t* chest_res,
|
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_slot_cfg_t slot = {};
|
||||||
srsran_pucch_nr_resource_t resource = {};
|
srsran_pucch_nr_resource_t resource = {};
|
||||||
resource.format = SRSRAN_PUCCH_NR_FORMAT_1;
|
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 (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;
|
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
|
||||||
resource.starting_prb += starting_prb_stride) {
|
resource.starting_prb += starting_prb_stride) {
|
||||||
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB;
|
for (resource.second_hop_prb = 0; resource.second_hop_prb < (enable_intra_slot_hopping) ? carrier.nof_prb : 0;
|
||||||
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB;
|
resource.second_hop_prb += starting_prb_stride) {
|
||||||
resource.nof_symbols++) {
|
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB;
|
||||||
for (resource.start_symbol_idx = 0;
|
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB;
|
||||||
resource.start_symbol_idx <=
|
resource.nof_symbols++) {
|
||||||
SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols);
|
for (resource.start_symbol_idx = 0;
|
||||||
resource.start_symbol_idx += starting_symbol_stride) {
|
resource.start_symbol_idx <=
|
||||||
for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC;
|
SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols);
|
||||||
resource.time_domain_occ++) {
|
resource.start_symbol_idx += starting_symbol_stride) {
|
||||||
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS;
|
for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC;
|
||||||
resource.initial_cyclic_shift++) {
|
resource.time_domain_occ++) {
|
||||||
for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) {
|
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS;
|
||||||
for (uint32_t word = 0; word < (1U << nof_bits); word++) {
|
resource.initial_cyclic_shift++) {
|
||||||
// Generate bits
|
for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) {
|
||||||
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
|
for (uint32_t word = 0; word < (1U << nof_bits); word++) {
|
||||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
// Generate bits
|
||||||
b[i] = (word >> i) & 1U;
|
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
|
// Encode PUCCH
|
||||||
TESTASSERT(srsran_pucch_nr_format1_encode(pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) ==
|
TESTASSERT(srsran_pucch_nr_format1_encode(
|
||||||
SRSRAN_SUCCESS);
|
pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) == SRSRAN_SUCCESS);
|
||||||
|
|
||||||
// Put DMRS
|
// Put DMRS
|
||||||
TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
|
TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
|
||||||
SRSRAN_SUCCESS);
|
SRSRAN_SUCCESS);
|
||||||
|
|
||||||
// Apply AWGN
|
// Apply AWGN
|
||||||
srsran_channel_awgn_run_c(
|
srsran_channel_awgn_run_c(
|
||||||
&awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR);
|
&awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR);
|
||||||
|
|
||||||
// Estimate channel
|
// Estimate channel
|
||||||
TESTASSERT(srsran_dmrs_pucch_format1_estimate(
|
TESTASSERT(srsran_dmrs_pucch_format1_estimate(
|
||||||
pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS);
|
pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS);
|
||||||
|
|
||||||
TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.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->epre_dBfs - 0.0f) < 3.0f);
|
||||||
TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f);
|
TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f);
|
||||||
|
|
||||||
// Decode PUCCH
|
// Decode PUCCH
|
||||||
uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||||
TESTASSERT(srsran_pucch_nr_format1_decode(
|
TESTASSERT(srsran_pucch_nr_format1_decode(
|
||||||
pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) ==
|
pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) ==
|
||||||
SRSRAN_SUCCESS);
|
SRSRAN_SUCCESS);
|
||||||
|
|
||||||
// Check received bits
|
// Check received bits
|
||||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||||
TESTASSERT(b[i] == b_rx[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 (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");
|
ERROR("Failed PUCCH format 1");
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue