Initial moved block coding to FEC

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 13c594651e
commit be6cb666e2

@ -32,7 +32,6 @@
#define SRSLTE_UCI_MAX_CQI_LEN_PUCCH 13 #define SRSLTE_UCI_MAX_CQI_LEN_PUCCH 13
#define SRSLTE_UCI_CQI_CODED_PUCCH_B 20 #define SRSLTE_UCI_CQI_CODED_PUCCH_B 20
#define SRSLTE_UCI_STR_MAX_CHAR 32 #define SRSLTE_UCI_STR_MAX_CHAR 32
#define SRSLTE_UCI_M_BASIS_SEQ_LEN 32
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_crc_t crc; srslte_crc_t crc;
@ -65,30 +64,6 @@ SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q,
int16_t b_bits[SRSLTE_CQI_MAX_BITS], // aligned for simd int16_t b_bits[SRSLTE_CQI_MAX_BITS], // aligned for simd
uint8_t* cqi_data, uint8_t* cqi_data,
uint32_t cqi_len); uint32_t cqi_len);
/**
* Encodes Uplink Control Information using M-basis code block channel coding.
*
* @param input points to the bit to encode, one word per bit
* @param input_len number of bits to encode, the maximum number of bits is 11
* @param output points to the encoded data, one word per bit
* @param output_len number of bits of encoded bits
*/
SRSLTE_API void
srslte_uci_encode_m_basis_bits(const uint8_t* input, uint32_t input_len, uint8_t* output, uint32_t output_len);
/**
* Decodes Uplink Control Information using M-basis code block channel coding.
*
* @param llr points soft-bits
* @param nof_llr number of soft-bits, requires a minimum of 32 soft-bits
* @param data points to receice data, one word per bit
* @param data_len number of bits to decode, the maximum number of bits is 11
* @return maximum correlation value
*/
SRSLTE_API int32_t srslte_uci_decode_m_basis_bits(const int16_t* llr,
uint32_t nof_llr,
uint8_t* data,
uint32_t data_len);
SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t* q); SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t* q);

@ -11,6 +11,7 @@ set(FEC_SOURCES
crc.c crc.c
softbuffer.c) softbuffer.c)
add_subdirectory(block)
add_subdirectory(convolutional) add_subdirectory(convolutional)
add_subdirectory(ldpc) add_subdirectory(ldpc)
add_subdirectory(polar) add_subdirectory(polar)

@ -0,0 +1,13 @@
#
# Copyright 2013-2020 Software Radio Systems Limited
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the distribution.
#
set(FEC_SOURCES ${FEC_SOURCES}
block/block.c
PARENT_SCOPE)
add_subdirectory(test)

@ -0,0 +1,198 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/phy/fec/block/block.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
// Use carry-less multiplication for parity check calculation only if AVX2 is available
#ifdef LV_HAVE_AVX2
#include <immintrin.h>
#define USE_CARRYLESS_MULT 1
#else
#define USE_CARRYLESS_MULT 0
#endif // LV_HAVE_AVX2
// The following MACRO enables/disables LUT for the decoder
#define USE_LUT 1
// The following type is used for selecting the algorithm precision
typedef int16_t block_llr_t;
/// Table 5.2.2.6.4-1: Basis sequence for (32, O) code compressed in uint16_t types
static const uint64_t M_basis_seq_b[SRSLTE_FEC_BLOCK_SIZE] = {
0b10000000011, 0b11000000111, 0b11101001001, 0b10100001101, 0b10010001111, 0b10111010011, 0b11101010101,
0b10110011001, 0b11010011011, 0b11001011101, 0b11011100101, 0b10101100111, 0b11110101001, 0b11010101011,
0b10010110001, 0b11011110011, 0b01001110111, 0b00100111001, 0b00011111011, 0b00001100001, 0b10001000101,
0b11000001011, 0b10110010001, 0b11100010111, 0b01111011111, 0b10011100011, 0b01100101101, 0b01110101111,
0b00101110101, 0b00111111101, 0b11111111111, 0b00000000001,
};
static inline uint8_t encode_M_basis_seq_u16(uint16_t w, uint32_t bit_idx)
{
// Apply mask
uint64_t d = w & M_basis_seq_b[bit_idx % SRSLTE_FEC_BLOCK_SIZE];
#if USE_CARRYLESS_MULT
// Compute parity using carry-less multiplication
const __m128i temp = _mm_clmulepi64_si128(_mm_set_epi64x(0, d), _mm_set_epi64x(0, 0xffffUL << 17UL), 0);
d = _mm_extract_epi32(temp, 1);
#else
// Compute parity using Bit Twiddling
d ^= d >> 8UL;
d ^= d >> 4UL;
d &= 0xFUL;
d = (0x6996U >> d);
#endif
return (uint8_t)(d & 1UL);
}
#if USE_LUT
static block_llr_t M_basis_seq_b_lut[1U << SRSLTE_FEC_BLOCK_MAX_NOF_BITS][SRSLTE_FEC_BLOCK_SIZE];
// Initialization function, as the table does not change, it can be initialised as constructor
__attribute__((constructor)) static void srslte_block_init()
{
for (uint32_t word = 0; word < (1U << SRSLTE_FEC_BLOCK_MAX_NOF_BITS); word++) {
for (uint32_t i = 0; i < SRSLTE_FEC_BLOCK_SIZE; i++) {
// Encode guess word
M_basis_seq_b_lut[word][i] = encode_M_basis_seq_u16(word, i) * 2 - 1;
}
}
}
#endif
void srslte_block_encode(const uint8_t* input, uint32_t input_len, uint8_t* output, uint32_t output_len)
{
// Limit number of input bits
input_len = SRSLTE_MIN(input_len, SRSLTE_FEC_BLOCK_MAX_NOF_BITS);
// Pack input bits
uint16_t w = 0;
for (uint32_t i = 0; i < input_len; i++) {
w |= (input[i] & 1U) << i;
}
// Encode bits
for (uint32_t i = 0; i < SRSLTE_MIN(output_len, SRSLTE_FEC_BLOCK_SIZE); i++) {
output[i] = encode_M_basis_seq_u16(w, i);
}
// Avoid repeating operation by copying repeated sequence
for (uint32_t i = SRSLTE_FEC_BLOCK_SIZE; i < output_len; i++) {
output[i] = output[i % SRSLTE_FEC_BLOCK_SIZE];
}
}
static int32_t srslte_block_decode(const block_llr_t llr[SRSLTE_FEC_BLOCK_SIZE], uint8_t* data, uint32_t data_len)
{
int32_t max_corr = 0; //< Stores maximum correlation
uint32_t max_data = 0; //< Stores the word for maximum correlation
// Limit data to maximum
data_len = SRSLTE_MIN(data_len, SRSLTE_FEC_BLOCK_MAX_NOF_BITS);
// Brute force all possible sequences
uint16_t max_guess = (1U << data_len); //< Maximum guess bit combination (excluded)
for (uint16_t guess = 0; guess < max_guess; guess++) {
int32_t corr = 0;
#if USE_LUT
// Load sequence from LUT
block_llr_t* sequence = M_basis_seq_b_lut[guess];
// Dot product
for (uint32_t i = 0; i < SRSLTE_FEC_BLOCK_SIZE; i++) {
corr += llr[i] * sequence[i];
}
#else
for (uint32_t i = 0; i < SRSLTE_FEC_BLOCK_SIZE; i++) {
// On-the-fly sequence generation and product
corr += llr[i] * (encode_M_basis_seq_u16(guess, i) * 2 - 1);
}
#endif
// Take decision
if (corr > max_corr) {
max_corr = corr;
max_data = guess;
}
}
// Unpack
for (uint32_t i = 0; i < data_len; i++) {
data[i] = (uint8_t)((max_data >> i) & 1U);
}
// Return correlation
return max_corr;
}
int32_t srslte_block_decode_i8(const int8_t* llr, uint32_t nof_llr, uint8_t* data, uint32_t data_len)
{
block_llr_t llr_[SRSLTE_FEC_BLOCK_SIZE];
// Return invalid inputs if data is not provided
if (!llr || !data) {
ERROR("Invalid inputs\n");
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Return invalid inputs if not enough LLR are provided
if (nof_llr < SRSLTE_FEC_BLOCK_SIZE) {
ERROR("Not enough LLR bits are provided %d. Required %d;\n", nof_llr, SRSLTE_FEC_BLOCK_SIZE);
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Load the minimum of LLRs
uint32_t i = 0;
for (; i < SRSLTE_FEC_BLOCK_SIZE; i++) {
llr_[i] = (block_llr_t)llr[i];
}
// Combine the rest of LLRs
for (; i < nof_llr; i++) {
llr_[i % SRSLTE_FEC_BLOCK_SIZE] += (block_llr_t)llr[i];
}
return srslte_block_decode(llr_, data, data_len);
}
int32_t srslte_block_decode_i16(const int16_t* llr, uint32_t nof_llr, uint8_t* data, uint32_t data_len)
{
block_llr_t llr_[SRSLTE_FEC_BLOCK_SIZE];
// Return invalid inputs if data is not provided
if (!llr || !data) {
ERROR("Invalid inputs\n");
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Return invalid inputs if not enough LLR are provided
if (nof_llr < SRSLTE_FEC_BLOCK_SIZE) {
ERROR("Not enough LLR bits are provided %d. Required %d;\n", nof_llr, SRSLTE_FEC_BLOCK_SIZE);
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Load the minimum of LLRs
uint32_t i = 0;
for (; i < SRSLTE_FEC_BLOCK_SIZE; i++) {
llr_[i] = (block_llr_t)llr[i];
}
// Combine the rest of LLRs
for (; i < nof_llr; i++) {
llr_[i % SRSLTE_FEC_BLOCK_SIZE] += (block_llr_t)llr[i];
}
return srslte_block_decode(llr_, data, data_len);
}

@ -0,0 +1,16 @@
#
# Copyright 2013-2020 Software Radio Systems Limited
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the distribution.
#
########################################################################
# Viterbi TEST
########################################################################
add_executable(block_test block_test.c)
target_link_libraries(block_test srslte_phy)
add_test(block_test block_test)

@ -0,0 +1,128 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/common/test_common.h"
#include "srslte/phy/fec/block/block.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/random.h"
#include <memory.h>
#include <srslte/phy/utils/vector.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
static uint32_t seed = 0x1234;
static uint32_t nof_repetitions = 1;
static uint32_t E = SRSLTE_FEC_BLOCK_SIZE;
static uint32_t A = 100;
static srslte_random_t random_gen = NULL;
void usage(char* prog)
{
printf("Usage: %s [Rv]\n", prog);
printf("\t-R Number of repetitions [Default %d]\n", nof_repetitions);
printf("\t-v increase verbose [Default %d]\n", srslte_verbose);
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "Rv")) != -1) {
switch (opt) {
case 'R':
nof_repetitions = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int test(uint32_t block_size)
{
struct timeval t[3] = {};
uint8_t tx[SRSLTE_FEC_BLOCK_MAX_NOF_BITS] = {};
uint8_t rx[SRSLTE_FEC_BLOCK_MAX_NOF_BITS] = {};
uint8_t encoded[SRSLTE_FEC_BLOCK_SIZE] = {};
int16_t llr_i16[SRSLTE_FEC_BLOCK_SIZE] = {};
int8_t llr_i8[SRSLTE_FEC_BLOCK_SIZE] = {};
uint64_t t_encode_us = 0;
uint64_t t_decode_i16_us = 0;
uint64_t t_decode_i8_us = 0;
for (uint32_t r = 0; r < nof_repetitions; r++) {
// Generate random data
for (uint32_t i = 0; i < block_size; i++) {
tx[i] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 1);
}
gettimeofday(&t[1], NULL);
srslte_block_encode(tx, block_size, encoded, E);
gettimeofday(&t[2], NULL);
get_time_interval(t);
t_encode_us += t[0].tv_sec * 1000000 + t[0].tv_usec;
for (uint32_t i = 0; i < E; i++) {
int32_t llr = (encoded[i] == 0) ? -A : +A;
llr_i16[i] = (int16_t)llr;
llr_i8[i] = (int8_t)llr;
}
gettimeofday(&t[1], NULL);
int32_t corr_i16 = srslte_block_decode_i16(llr_i16, E, rx, block_size);
gettimeofday(&t[2], NULL);
get_time_interval(t);
TESTASSERT(corr_i16 == E * A);
TESTASSERT(memcmp(tx, rx, block_size) == 0);
t_decode_i16_us += t[0].tv_sec * 1000000 + t[0].tv_usec;
gettimeofday(&t[1], NULL);
int32_t corr_i8 = srslte_block_decode_i8(llr_i8, E, rx, block_size);
gettimeofday(&t[2], NULL);
get_time_interval(t);
TESTASSERT(corr_i8 == E * A);
TESTASSERT(memcmp(tx, rx, block_size) == 0);
t_decode_i8_us += t[0].tv_sec * 1000000 + t[0].tv_usec;
}
double total_bits = (double)(block_size * nof_repetitions);
INFO("Block size %d PASSED! Encoder: %.1f us / %.1f Mbps; 16 bit Decoder: %.1f us / %.2f Mbps; 8 bit decoder: %.1f / "
"%.2f Mbps\n",
block_size,
t_encode_us / (double)nof_repetitions,
total_bits / (double)t_encode_us,
t_decode_i16_us / (double)nof_repetitions,
total_bits / (double)t_decode_i16_us,
t_decode_i8_us / (double)nof_repetitions,
total_bits / (double)t_decode_i8_us);
return SRSLTE_SUCCESS;
}
int main(int argc, char** argv)
{
parse_args(argc, argv);
random_gen = srslte_random_init(seed);
for (uint32_t block_size = 3; block_size <= SRSLTE_FEC_BLOCK_MAX_NOF_BITS; block_size++) {
if (test(block_size) < SRSLTE_SUCCESS) {
break;
}
}
srslte_random_free(random_gen);
}

@ -10,6 +10,7 @@
* *
*/ */
#include "srslte/phy/fec/block/block.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <assert.h> #include <assert.h>
#include <complex.h> #include <complex.h>
@ -639,7 +640,7 @@ static int decode_signal_format3(srslte_pucch_t* q,
srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS); srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
return (int)srslte_uci_decode_m_basis_bits(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS); return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS);
} else { } else {
ERROR("Error modulating PUCCH3 bits: rnti not set\n"); ERROR("Error modulating PUCCH3 bits: rnti not set\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -699,7 +700,7 @@ static int encode_bits(srslte_pucch_cfg_t* cfg,
temp[k] = (uint8_t)(uci_data->scheduling_request ? 1 : 0); temp[k] = (uint8_t)(uci_data->scheduling_request ? 1 : 0);
k++; k++;
} }
srslte_uci_encode_m_basis_bits(temp, k, pucch_bits, SRSLTE_PUCCH3_NOF_BITS); srslte_block_encode(temp, k, pucch_bits, SRSLTE_PUCCH3_NOF_BITS);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -20,6 +20,7 @@
#include <strings.h> #include <strings.h>
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/fec/block/block.h"
#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/cbsegm.h"
#include "srslte/phy/fec/convolutional/convcoder.h" #include "srslte/phy/fec/convolutional/convcoder.h"
#include "srslte/phy/fec/convolutional/rm_conv.h" #include "srslte/phy/fec/convolutional/rm_conv.h"
@ -30,7 +31,7 @@
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
/* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */ /* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */
static uint8_t M_basis_seq[SRSLTE_UCI_M_BASIS_SEQ_LEN][SRSLTE_UCI_MAX_ACK_SR_BITS] = { static uint8_t M_basis_seq[SRSLTE_FEC_BLOCK_SIZE][SRSLTE_UCI_MAX_ACK_SR_BITS] = {
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1}, {1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1}, {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1}, {1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1},
{1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1}, {1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}, {1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1}, {1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1}, {1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1}, {1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1}, {1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1}, {1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1}, {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1}, {1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1}, {1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1},
@ -44,30 +45,6 @@ static uint8_t M_basis_seq[SRSLTE_UCI_M_BASIS_SEQ_LEN][SRSLTE_UCI_MAX_ACK_SR_BIT
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 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 inline bool encode_M_basis_seq_u16(uint16_t w, uint32_t bit_idx)
{
/// Table 5.2.2.6.4-1: Basis sequence for (32, O) code compressed in uint16_t types
const uint16_t M_basis_seq_b[SRSLTE_UCI_M_BASIS_SEQ_LEN] = {
0b10000000011, 0b11000000111, 0b11101001001, 0b10100001101, 0b10010001111, 0b10111010011, 0b11101010101,
0b10110011001, 0b11010011011, 0b11001011101, 0b11011100101, 0b10101100111, 0b11110101001, 0b11010101011,
0b10010110001, 0b11011110011, 0b01001110111, 0b00100111001, 0b00011111011, 0b00001100001, 0b10001000101,
0b11000001011, 0b10110010001, 0b11100010111, 0b01111011111, 0b10011100011, 0b01100101101, 0b01110101111,
0b00101110101, 0b00111111101, 0b11111111111, 0b00000000001,
};
// Apply mask
uint16_t d = (uint16_t)w & M_basis_seq_b[bit_idx % SRSLTE_UCI_M_BASIS_SEQ_LEN];
// Compute parity
d ^= (uint16_t)(d >> 8U);
d ^= (uint16_t)(d >> 4U);
d &= 0xf;
d = (0x6996U >> d) & 1U;
// Return false if 0, otherwise it returns true
return (d != 0);
}
static uint8_t M_basis_seq_pucch[20][13] = { 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}, {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},
{1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1}, {1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1}, {1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1}, {1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1},
@ -182,88 +159,6 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q,
} }
} }
void srslte_uci_encode_m_basis_bits(const uint8_t* input, uint32_t input_len, uint8_t* output, uint32_t output_len)
{
// Limit number of input bits
input_len = SRSLTE_MIN(input_len, SRSLTE_UCI_MAX_ACK_SR_BITS);
// Pack input bits
uint16_t w = 0;
for (uint32_t i = 0; i < input_len; i++) {
w |= (input[i] & 1U) << i;
}
// Encode bits
for (uint32_t i = 0; i < SRSLTE_MIN(output_len, SRSLTE_UCI_M_BASIS_SEQ_LEN); i++) {
output[i] = encode_M_basis_seq_u16(w, i);
}
// Avoid repeating operation by copying repeated sequence
for (uint32_t i = SRSLTE_UCI_M_BASIS_SEQ_LEN; i < output_len; i++) {
output[i] = output[i % SRSLTE_UCI_M_BASIS_SEQ_LEN];
}
}
int32_t srslte_uci_decode_m_basis_bits(const int16_t* llr, uint32_t nof_llr, uint8_t* data, uint32_t data_len)
{
int32_t max_corr = 0; ///< Stores maximum correlation
uint16_t max_data = 0; ///< Stores the word for maximum correlation
// Return invalid inputs if data is not provided
if (!llr || !data) {
ERROR("Invalid inputs\n");
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Return invalid inputs if not enough LLR are provided
if (nof_llr < SRSLTE_UCI_M_BASIS_SEQ_LEN) {
ERROR("Not enough LLR bits are provided %d. Required %d;\n", nof_llr, SRSLTE_UCI_M_BASIS_SEQ_LEN);
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Limit data to maximum
data_len = SRSLTE_MIN(data_len, SRSLTE_UCI_MAX_ACK_SR_BITS);
// Brute force all possible sequences
uint16_t max_guess = (1 << data_len); ///< Maximum guess bit combination
for (uint16_t guess = 0; guess < max_guess; guess++) {
int32_t corr = 0;
/// Compute correlation for the number of LLR
bool early_termination = false;
for (uint32_t i = 0; i < nof_llr && !early_termination; i++) {
// Encode guess word
bool d = encode_M_basis_seq_u16(guess, i);
// Correlate
corr += (int32_t)(d ? llr[i] : -llr[i]);
// Limit correlation to half range
corr = SRSLTE_MIN(corr, INT32_MAX / 2);
/// Early terminates if at least SRSLTE_UCI_M_BASIS_SEQ_LEN/4 LLR processed and negative correlation
early_termination |= (i > SRSLTE_UCI_M_BASIS_SEQ_LEN / 4) && (corr < 0);
/// Early terminates if the correlation overflows
early_termination |= (corr < -INT32_MAX / 2);
}
// Take decision
if (corr > max_corr) {
max_corr = corr;
max_data = guess;
}
}
// Unpack
for (uint32_t i = 0; i < data_len; i++) {
data[i] = (uint8_t)((max_data >> i) & 1U);
}
// Return correlation
return max_corr;
}
void cqi_pusch_pregen(srslte_uci_cqi_pusch_t* q) void cqi_pusch_pregen(srslte_uci_cqi_pusch_t* q)
{ {
uint8_t word[11]; uint8_t word[11];
@ -275,7 +170,7 @@ void cqi_pusch_pregen(srslte_uci_cqi_pusch_t* q)
for (uint32_t w = 0; w < nwords; w++) { for (uint32_t w = 0; w < nwords; w++) {
uint8_t* ptr = word; uint8_t* ptr = word;
srslte_bit_unpack(w, &ptr, i + 1); srslte_bit_unpack(w, &ptr, i + 1);
srslte_uci_encode_m_basis_bits(word, i + 1, &q->cqi_table[i][32 * w], SRSLTE_UCI_M_BASIS_SEQ_LEN); srslte_block_encode(word, i + 1, &q->cqi_table[i][32 * w], SRSLTE_FEC_BLOCK_SIZE);
for (int j = 0; j < 32; j++) { for (int j = 0; j < 32; j++) {
q->cqi_table_s[i][32 * w + j] = 2 * q->cqi_table[i][32 * w + j] - 1; q->cqi_table_s[i][32 * w + j] = 2 * q->cqi_table[i][32 * w + j] - 1;
} }
@ -829,8 +724,8 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
int16_t llr_acc[32] = {}; ///< LLR accumulator int16_t llr_acc[32] = {}; ///< LLR accumulator
uint32_t nof_acc = uint32_t nof_acc =
(nof_bits == 1) ? Qm : (nof_bits == 2) ? Qm * 3 : SRSLTE_UCI_M_BASIS_SEQ_LEN; ///< Number of required LLR (nof_bits == 1) ? Qm : (nof_bits == 2) ? Qm * 3 : SRSLTE_FEC_BLOCK_SIZE; ///< Number of required LLR
uint32_t count_acc = 0; ///< LLR counter uint32_t count_acc = 0; ///< LLR counter
for (uint32_t i = 0; i < Qprime; i++) { for (uint32_t i = 0; i < Qprime; i++) {
if (is_ri) { if (is_ri) {
@ -875,7 +770,7 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
break; break;
default: default:
// For more than 2 bits... // For more than 2 bits...
corr = srslte_uci_decode_m_basis_bits(llr_acc, SRSLTE_UCI_M_BASIS_SEQ_LEN, data, nof_bits); corr = srslte_block_decode_i16(llr_acc, SRSLTE_FEC_BLOCK_SIZE, data, nof_bits);
} }
if (valid) { if (valid) {

Loading…
Cancel
Save