Initial PUCCH format 3 decoder

This commit is contained in:
Xavier Arteaga 2020-02-01 00:51:53 +01:00 committed by Xavier Arteaga
parent f935916e7c
commit 1f762844ee
7 changed files with 201 additions and 68 deletions

View File

@ -69,6 +69,7 @@ typedef struct SRSLTE_API {
uint16_t ue_rnti;
bool is_ue;
int16_t llr[SRSLTE_PUCCH3_NOF_BITS];
uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS];
cf_t d[SRSLTE_PUCCH_MAX_BITS / 2];
uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB];

View File

@ -76,6 +76,8 @@ SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q,
SRSLTE_API void srslte_uci_encode_ack_sr_pucch3(uint8_t* data, uint32_t nof_bits, uint8_t output[32]);
SRSLTE_API int16_t srslte_uci_decode_ack_sr_pucch3(const int16_t llr[48], uint8_t* data);
SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t* q);
SRSLTE_API void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t* q);

View File

@ -562,12 +562,12 @@ static int encode_signal_format3(srslte_pucch_t* q,
cf_t h;
if (n < N_sf_0) {
h = w_n_oc_0[n] * cexpf(I * M_PI * floorf(n_cs_cell / 64) / 2);
h = w_n_oc_0[n] * cexpf(I * M_PI * floorf(n_cs_cell / 64.0f) / 2);
for (uint32_t i = 0; i < SRSLTE_NRE; i++) {
y_n[i] = h * q->d[(i + n_cs_cell) % SRSLTE_NRE];
}
} else {
h = w_n_oc_1[n - N_sf_0] * cexpf(I * M_PI * floorf(n_cs_cell / 64) / 2);
h = w_n_oc_1[n - N_sf_0] * cexpf(I * M_PI * floorf(n_cs_cell / 64.0f) / 2);
for (uint32_t i = 0; i < SRSLTE_NRE; i++) {
y_n[i] = h * q->d[((i + n_cs_cell) % SRSLTE_NRE) + SRSLTE_NRE];
}
@ -585,6 +585,69 @@ static int encode_signal_format3(srslte_pucch_t* q,
return SRSLTE_SUCCESS;
}
static int decode_signal_format3(srslte_pucch_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_pucch_cfg_t* cfg,
uint8_t bits[SRSLTE_PUCCH_MAX_BITS],
cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS])
{
uint32_t N_sf_0 = get_N_sf(cfg->format, 0, sf->shortened);
uint32_t N_sf_1 = get_N_sf(cfg->format, 1, sf->shortened);
uint32_t n_oc_0 = cfg->n_pucch % N_sf_1;
uint32_t n_oc_1 = (N_sf_1 == 5) ? ((3 * cfg->n_pucch) % N_sf_1) : (n_oc_0 % N_sf_1);
cf_t* w_n_oc_0 = (cf_t*)pucch3_w_n_oc_5[n_oc_0];
cf_t* w_n_oc_1 = (cf_t*)((N_sf_1 == 5) ? pucch3_w_n_oc_5[n_oc_1] : pucch3_w_n_oc_4[n_oc_1]);
memset(q->d, 0, sizeof(cf_t) * 2 * SRSLTE_NRE);
for (uint32_t n = 0; n < N_sf_0 + N_sf_1; n++) {
uint32_t l = get_pucch_symbol(n, cfg->format, q->cell.cp);
uint32_t n_cs_cell = q->n_cs_cell[(2 * (sf->tti % 10) + ((n < N_sf_0) ? 0 : 1)) % SRSLTE_NSLOTS_X_FRAME][l];
cf_t y_n[SRSLTE_NRE];
bzero(y_n, sizeof(cf_t) * SRSLTE_NRE);
// Do FFT
for (int k = 0; k < SRSLTE_NRE; k++) {
cf_t acc = 0.0f;
for (int i = 0; i < SRSLTE_NRE; i++) {
acc += z[n * SRSLTE_NRE + i] * cexpf(I * 2.0 * M_PI * i * k / (float)SRSLTE_NRE);
}
y_n[k] = acc / sqrtf(SRSLTE_NRE);
}
if (n < N_sf_0) {
cf_t h = w_n_oc_0[n] * cexpf(-I * M_PI * floorf(n_cs_cell / 64.0f) / 2);
for (uint32_t i = 0; i < SRSLTE_NRE; i++) {
q->d[(i + n_cs_cell) % SRSLTE_NRE] += h * y_n[i];
}
} else {
cf_t h = w_n_oc_1[n - N_sf_0] * cexpf(-I * M_PI * floorf(n_cs_cell / 64.0f) / 2);
for (uint32_t i = 0; i < SRSLTE_NRE; i++) {
q->d[((i + n_cs_cell) % SRSLTE_NRE) + SRSLTE_NRE] += h * y_n[i];
}
}
}
srslte_vec_sc_prod_cfc(q->d, 2.0f / (N_sf_0 + N_sf_1), q->d, SRSLTE_NRE * 2);
srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
if (seq) {
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS);
srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
return (int)srslte_uci_decode_ack_sr_pucch3(q->llr, bits);
} else {
fprintf(stderr, "Error modulating PUCCH3 bits: rnti not set\n");
return -1;
}
return SRSLTE_SUCCESS;
}
static int encode_signal(srslte_pucch_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_pucch_cfg_t* cfg,
@ -732,6 +795,10 @@ static bool decode_signal(srslte_pucch_t* q,
return -1;
}
break;
case SRSLTE_PUCCH_FORMAT_3:
corr = (float)decode_signal_format3(q, sf, cfg, pucch_bits, q->z) / 4800.0f;
detected = true;
break;
default:
ERROR("PUCCH format %d not implemented\n", cfg->format);
return SRSLTE_ERROR;
@ -748,27 +815,33 @@ static void decode_bits(srslte_pucch_cfg_t* cfg,
uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS],
srslte_uci_value_t* uci_data)
{
// If was looking for scheduling request, update value
if (cfg->uci_cfg.is_scheduling_request_tti) {
uci_data->scheduling_request = pucch_found;
}
// Save ACK bits
for (uint32_t a = 0; a < srslte_pucch_nof_ack_format(cfg->format); a++) {
if (cfg->uci_cfg.cqi.data_enable || cfg->uci_cfg.cqi.ri_len) {
uci_data->ack.ack_value[a] = pucch2_bits[a];
} else {
uci_data->ack.ack_value[a] = pucch_bits[a];
if (cfg->format == SRSLTE_PUCCH_FORMAT_3) {
memcpy(uci_data->ack.ack_value, pucch_bits, srslte_uci_cfg_total_ack(&cfg->uci_cfg));
uci_data->scheduling_request = pucch_bits[srslte_uci_cfg_total_ack(&cfg->uci_cfg)] == 1;
uci_data->ack.valid = true;
} else {
// If was looking for scheduling request, update value
if (cfg->uci_cfg.is_scheduling_request_tti) {
uci_data->scheduling_request = pucch_found;
}
}
// PUCCH2 CQI bits are already decoded
if (cfg->uci_cfg.cqi.data_enable) {
srslte_cqi_value_unpack(&cfg->uci_cfg.cqi, pucch_bits, &uci_data->cqi);
}
// Save ACK bits
for (uint32_t a = 0; a < srslte_pucch_nof_ack_format(cfg->format); a++) {
if (cfg->uci_cfg.cqi.data_enable || cfg->uci_cfg.cqi.ri_len) {
uci_data->ack.ack_value[a] = pucch2_bits[a];
} else {
uci_data->ack.ack_value[a] = pucch_bits[a];
}
}
if (cfg->uci_cfg.cqi.ri_len) {
uci_data->ri = pucch_bits[0]; /* Assume only one bit of RI */
// PUCCH2 CQI bits are already decoded
if (cfg->uci_cfg.cqi.data_enable) {
srslte_cqi_value_unpack(&cfg->uci_cfg.cqi, pucch_bits, &uci_data->cqi);
}
if (cfg->uci_cfg.cqi.ri_len) {
uci_data->ri = pucch_bits[0]; /* Assume only one bit of RI */
}
}
}

View File

@ -52,6 +52,13 @@ static uint8_t M_basis_seq[32][11] = {
{1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0}, {1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0}, {1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
static const uint16_t M_basis_seq_b[32] = {
0b11000000001, 0b11100000011, 0b10010010111, 0b10110000101, 0b11110001001, 0b11001011101, 0b10101010111,
0b10011001101, 0b11011001011, 0b10111010011, 0b10100111011, 0b11100110101, 0b10010101111, 0b11010101011,
0b10001101001, 0b11001111011, 0b11101110010, 0b10011100100, 0b11011111000, 0b10000110000, 0b10100010001,
0b11010000011, 0b10001001101, 0b11101000111, 0b11111011110, 0b11000111001, 0b10110100110, 0b11110101110,
0b10101110100, 0b10111111100, 0b11111111111, 0b10000000000,
};
static uint8_t M_basis_seq_pucch[20][13] = {
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, {1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0},
@ -167,7 +174,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q,
}
}
void encode_cqi_pusch_block(uint8_t* data, uint32_t nof_bits, uint8_t output[32])
void encode_cqi_pusch_block(const uint8_t* data, uint32_t nof_bits, uint8_t output[32])
{
for (int i = 0; i < 32; i++) {
output[i] = 0;
@ -182,6 +189,69 @@ void srslte_uci_encode_ack_sr_pucch3(uint8_t* data, uint32_t nof_bits, uint8_t o
encode_cqi_pusch_block(data, nof_bits, output);
}
int16_t srslte_uci_decode_ack_sr_pucch3(const int16_t llr[48], uint8_t* data)
{
int16_t max_corr = 0;
int16_t max_data = 0;
// Brute force all sequences backwards
for (int16_t guess = 2047; guess >= 0; guess--) {
int16_t corr = 0;
for (uint8_t i = 0; i < 48; i++) {
//
uint16_t d = (uint16_t)guess & M_basis_seq_b[i % 32];
d ^= (uint16_t)(d >> 8U);
d ^= (uint16_t)(d >> 4U);
d &= 0xf;
d = (0x6996U >> d) & 1U;
corr += (d ? 1 : -1) * llr[i];
}
if (corr > max_corr) {
max_corr = corr;
max_data = guess;
}
}
for (int8_t i = 0; i < 11; i++) {
data[i] = (uint8_t)(max_data >> (10U - i)) & 1U;
}
return max_corr;
}
void srslte_uci_decode_ack_sr_pucch3x(const int16_t llr[48], uint8_t* data, uint32_t nof_bits)
{
// Limit maximum of bits
nof_bits = SRSLTE_MIN(nof_bits, 11);
nof_bits = SRSLTE_MAX(nof_bits, 1);
int16_t max_corr = 0;
uint16_t max_data = 0;
for (uint16_t guess = 0; guess < (1U << (nof_bits - 1)); guess++) {
int16_t corr = 0;
for (uint8_t i = 0; i < 48; i++) {
uint8_t d = 0;
for (uint8_t n = 0; n < nof_bits; n++) {
d ^= (uint8_t)((uint8_t)(guess >> n) & M_basis_seq[i % 32][n]);
}
corr += (d ? 1 : -1) * llr[i];
}
if (corr > max_corr) {
max_corr = corr;
max_data = guess;
}
}
for (uint8_t i = 0; i < nof_bits; i++) {
data[i] = (uint8_t)(max_data >> i) & 1U;
}
}
void cqi_pusch_pregen(srslte_uci_cqi_pusch_t* q)
{
uint8_t word[11];

View File

@ -832,28 +832,6 @@ void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell,
// Get PUCCH Resources
cfg->format = srslte_pucch_select_format(cfg, uci_cfg, cell->cp);
cfg->n_pucch = get_npucch(cfg, uci_cfg, uci_value, cell);
if (uci_value) {
if (cfg->format == SRSLTE_PUCCH_FORMAT_3) {
fprintf(stderr, "Warning: PUCCH3 under development\n");
uint8_t* b = uci_value->ack.ack_value;
uint8_t temp[SRSLTE_UCI_MAX_ACK_BITS + 1];
uint32_t k = uci_cfg->ack[0].nof_acks;
for (; k < uci_cfg->ack[0].nof_acks; k++) {
temp[k] = (uint8_t)((b[k] == 1) ? 1 : 0);
}
memcpy(temp, uci_value->ack.ack_value, uci_cfg->ack[0].nof_acks);
if (uci_cfg->is_scheduling_request_tti) {
temp[uci_cfg->ack[0].nof_acks] = (uint8_t)(uci_value->scheduling_request ? 1 : 0);
k++;
}
srslte_uci_encode_ack_sr_pucch3(temp, k, b);
for (k = 32; k < SRSLTE_PUCCH3_NOF_BITS; k++) {
b[k] = b[k % 32];
}
}
}
}
/* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal

View File

@ -66,7 +66,7 @@ foreach (cell_n_prb 6 15 25 50 75 100)
endforeach (allow_256 0 1)
endforeach (cell_n_prb)
add_executable(pucch_cs_test pucch_cs_test.c)
target_link_libraries(pucch_cs_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(pucch_cs_test pucch_cs_test)
add_executable(pucch_ca_test pucch_ca_test.c)
target_link_libraries(pucch_ca_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(pucch_ca_test pucch_ca_test)

View File

@ -30,7 +30,10 @@
#include "srslte/srslte.h"
static int test_pucch_cs(uint32_t nof_prb, uint32_t nof_tb[SRSLTE_MAX_CARRIERS], uint16_t nof_carriers)
static int test_pucch_cs(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode,
uint32_t nof_prb,
const uint32_t nof_tb[SRSLTE_MAX_CARRIERS],
uint16_t nof_carriers)
{
srslte_pucch_cfg_t pucch_cfg = {};
uint16_t rnti = 0x1234;
@ -54,11 +57,11 @@ static int test_pucch_cs(uint32_t nof_prb, uint32_t nof_tb[SRSLTE_MAX_CARRIERS],
srslte_pusch_data_t pusch_data = {};
// Basic default args
pucch_cfg.delta_pucch_shift = 1; // 1, 2, 3
pucch_cfg.n_rb_2 = 1; // 0, 1, ..., 98
pucch_cfg.N_cs = 1; // 0, 1, ..., 7
pucch_cfg.N_pucch_1 = 1; // 0, 1, ..., 2047
pucch_cfg.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS; // Normal, CS, PUCCH3
pucch_cfg.delta_pucch_shift = 1; // 1, 2, 3
pucch_cfg.n_rb_2 = 1; // 0, 1, ..., 98
pucch_cfg.N_cs = 1; // 0, 1, ..., 7
pucch_cfg.N_pucch_1 = 1; // 0, 1, ..., 2047
pucch_cfg.ack_nack_feedback_mode = ack_nack_feedback_mode; // Normal, CS, PUCCH3
// Set Channel Selection resources
for (uint32_t i = 0, k = 6; i < SRSLTE_PUCCH_SIZE_AN_CS; i++) {
@ -92,13 +95,13 @@ static int test_pucch_cs(uint32_t nof_prb, uint32_t nof_tb[SRSLTE_MAX_CARRIERS],
TESTASSERT(!srslte_enb_ul_add_rnti(&enb_ul, rnti));
// The test itself starts here
for (ul_sf.tti = 0; ul_sf.tti < (1U << (nof_carriers * 2)); ul_sf.tti++) {
for (ul_sf.tti = 0; ul_sf.tti < (1U << (nof_carriers * 2U)); ul_sf.tti++) {
// Generate new data
pusch_data.uci.ack.valid = true;
for (uint32_t i = 0, k = 0; i < nof_carriers; i++) {
for (uint32_t j = 0; j < nof_tb[i]; j++, k++) {
pusch_data.uci.ack.ack_value[k] = (ul_sf.tti >> k) & 0x01;
pusch_data.uci.ack.ack_value[k] = (ul_sf.tti >> k) & 1U;
}
}
@ -144,21 +147,27 @@ int main(int argc, char** argv)
uint32_t nof_tb_1[SRSLTE_MAX_CARRIERS] = {1, 1, 1, 1, 0};
uint32_t nof_tb_2[SRSLTE_MAX_CARRIERS] = {2, 1, 1, 0, 0};
uint32_t nof_tb_3[SRSLTE_MAX_CARRIERS] = {2, 2, 0, 0, 0};
uint32_t nof_tb_3[SRSLTE_MAX_CARRIERS] = {2, 2, 2, 2, 2};
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_3, 2));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_3, 2));
for (srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS;
ack_nack_feedback_mode < SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR;
ack_nack_feedback_mode++) {
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_3, 2));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_3, 2));
if (ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3) {
TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_3, 5));
}
}
printf("Ok\n");