mirror of https://github.com/pvnis/srsRAN_4G.git
Initial moved block coding to FEC
parent
13c594651e
commit
be6cb666e2
@ -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);
|
||||
}
|
Loading…
Reference in New Issue