From bca5d1a95a553808a5ae278ef06908d9c31d1ce0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 10 Jan 2020 13:56:13 +0100 Subject: [PATCH] srsLTE: extend viterbi test --- lib/include/srslte/phy/utils/bit.h | 2 +- lib/include/srslte/phy/utils/vector.h | 26 +++- lib/src/phy/fec/test/CMakeLists.txt | 2 + lib/src/phy/fec/test/viterbi_test.c | 172 ++++++++++++++------------ lib/src/phy/fec/test/viterbi_test.h | 5 + lib/src/phy/fec/viterbi.c | 31 ++++- lib/src/phy/utils/bit.c | 2 +- lib/src/phy/utils/vector.c | 90 ++++++++------ 8 files changed, 201 insertions(+), 129 deletions(-) diff --git a/lib/include/srslte/phy/utils/bit.h b/lib/include/srslte/phy/utils/bit.h index e8b3ec292..bb3a60689 100644 --- a/lib/include/srslte/phy/utils/bit.h +++ b/lib/include/srslte/phy/utils/bit.h @@ -83,7 +83,7 @@ SRSLTE_API void srslte_bit_unpack(uint32_t value, uint8_t** bits, int nof_bits); SRSLTE_API void srslte_bit_fprint(FILE* stream, uint8_t* bits, int nof_bits); -SRSLTE_API uint32_t srslte_bit_diff(uint8_t* x, uint8_t* y, int nbits); +SRSLTE_API uint32_t srslte_bit_diff(const uint8_t* x, const uint8_t* y, int nbits); SRSLTE_API uint32_t srslte_bit_count(uint32_t n); diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 8d0d9f9a3..fc61fd3d7 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -82,6 +82,10 @@ SRSLTE_API cf_t srslte_vec_acc_cc(const cf_t* x, const uint32_t len); SRSLTE_API void* srslte_vec_malloc(uint32_t size); SRSLTE_API cf_t* srslte_vec_cf_malloc(uint32_t size); SRSLTE_API float* srslte_vec_f_malloc(uint32_t size); +SRSLTE_API int16_t* srslte_vec_i16_malloc(uint32_t nsamples); +SRSLTE_API uint16_t* srslte_vec_u16_malloc(uint32_t nsamples); +SRSLTE_API int8_t* srslte_vec_i8_malloc(uint32_t nsamples); +SRSLTE_API uint8_t* srslte_vec_u8_malloc(uint32_t nsamples); SRSLTE_API void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_size); @@ -179,17 +183,27 @@ SRSLTE_API void srslte_vec_quant_fuc(const float* in, uint8_t* out, const float gain, const float offset, - const float clip, + const uint8_t clip, + const uint32_t len); +SRSLTE_API void srslte_vec_quant_fus(const float* in, + uint16_t* out, + const float gain, + const float offset, + const uint16_t clip, const uint32_t len); -SRSLTE_API void srslte_vec_quant_fus(float* in, uint16_t* out, float gain, float offset, float clip, uint32_t len); SRSLTE_API void srslte_vec_quant_suc(const int16_t* in, uint8_t* out, const float gain, - const int16_t offset, - const int16_t clip, + const float offset, + const uint8_t clip, + const uint32_t len); + +SRSLTE_API void srslte_vec_quant_sus(const int16_t* in, + uint16_t* out, + const float gain, + const float offset, + const uint16_t clip, const uint32_t len); -SRSLTE_API void -srslte_vec_quant_sus(const int16_t* in, uint16_t* out, const float gain, const int16_t offset, const uint32_t len); /* magnitude of each vector element */ SRSLTE_API void srslte_vec_abs_cf(const cf_t* x, float* abs, const uint32_t len); SRSLTE_API void srslte_vec_abs_square_cf(const cf_t* x, float* abs_square, const uint32_t len); diff --git a/lib/src/phy/fec/test/CMakeLists.txt b/lib/src/phy/fec/test/CMakeLists.txt index 6737d6b66..3e8720e17 100644 --- a/lib/src/phy/fec/test/CMakeLists.txt +++ b/lib/src/phy/fec/test/CMakeLists.txt @@ -67,6 +67,8 @@ add_test(viterbi_1000_2 viterbi_test -n 100 -s 1 -l 1000 -t -e 2.0) add_test(viterbi_1000_3 viterbi_test -n 100 -s 1 -l 1000 -t -e 3.0) add_test(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -t -e 4.5) +add_test(viterbi_56_4 viterbi_test -n 1000 -s 1 -l 56 -t -e 4.5) + ######################################################################## # CRC TEST ######################################################################## diff --git a/lib/src/phy/fec/test/viterbi_test.c b/lib/src/phy/fec/test/viterbi_test.c index 995828080..5aeeb92b0 100644 --- a/lib/src/phy/fec/test/viterbi_test.c +++ b/lib/src/phy/fec/test/viterbi_test.c @@ -32,16 +32,10 @@ #include "viterbi_test.h" -#define VITERBI_16 - -#ifndef LV_HAVE_AVX2 -#undef VITERBI_16 -#endif - -int frame_length = 1000, nof_frames = 256; -float ebno_db = 100.0; -uint32_t seed = 0; -bool tail_biting = false; +static int frame_length = 1000, nof_frames = 256; +static float ebno_db = 100.0; +static uint32_t seed = 0; +static bool tail_biting = false; #define SNR_POINTS 10 #define SNR_MIN 0.0 @@ -84,19 +78,43 @@ void parse_args(int argc, char** argv) } } +#define VITERBI_TEST(FUNC, DEC, LLR, NOF_ERRORS) \ + do { \ + struct timeval t[3] = {}; \ + int M = 1; \ + gettimeofday(&t[1], NULL); \ + for (uint32_t m = 0; m < M && NOF_ERRORS >= 0; m++) { \ + int ret = FUNC(&DEC, LLR, data_rx, frame_length); \ + if (ret < SRSLTE_SUCCESS) { \ + NOF_ERRORS = ret; \ + } \ + } \ + gettimeofday(&t[2], NULL); \ + get_time_interval(t); \ + /*printf("-- "#FUNC" took\t\t%.1f us\n", (float) t[0].tv_sec * 1e6f + (float) t[0].tv_usec/M);*/ \ + if (NOF_ERRORS >= 0) { \ + NOF_ERRORS += srslte_bit_diff(data_tx, data_rx, frame_length); \ + } \ + } while (0) + +//#define TEST_SSE + int main(int argc, char** argv) { - int frame_cnt; - float* llr; - uint16_t* llr_s; - uint8_t* llr_c; - uint8_t * data_tx, *data_rx, *data_rx2, *symbols; - int j; + int frame_cnt = 0; + float* llr = NULL; + uint16_t* llr_us = NULL; + int16_t* llr_s = NULL; + uint8_t* llr_c = NULL; + uint8_t * data_tx, *data_rx, *symbols; float var[SNR_POINTS], varunc[SNR_POINTS]; int snr_points; - uint32_t errors; + int errors_s = 0; + int errors_us = 0; + int errors_c = 0; + int errors_f = 0; + int errors_sse = 0; #ifdef TEST_SSE - uint32_t errors2; srslte_viterbi_t dec_sse; #endif srslte_viterbi_t dec; @@ -130,40 +148,39 @@ int main(int argc, char** argv) printf(" EbNo: %.2f\n", ebno_db); } - data_tx = malloc(frame_length * sizeof(uint8_t)); + data_tx = srslte_vec_u8_malloc(frame_length); if (!data_tx) { perror("malloc"); exit(-1); } - data_rx = malloc(frame_length * sizeof(uint8_t)); + data_rx = srslte_vec_u8_malloc(frame_length); if (!data_rx) { perror("malloc"); exit(-1); } - data_rx2 = malloc(frame_length * sizeof(uint8_t)); - if (!data_rx2) { - perror("malloc"); - exit(-1); - } - - symbols = malloc(coded_length * sizeof(uint8_t)); + symbols = srslte_vec_u8_malloc(coded_length); if (!symbols) { perror("malloc"); exit(-1); } - llr = malloc(coded_length * sizeof(float)); + llr = srslte_vec_f_malloc(coded_length); if (!llr) { perror("malloc"); exit(-1); } - llr_s = malloc(2 * coded_length * sizeof(uint16_t)); + llr_s = srslte_vec_i16_malloc(2 * coded_length); if (!llr_s) { perror("malloc"); exit(-1); } - llr_c = malloc(2 * coded_length * sizeof(uint8_t)); + llr_us = srslte_vec_u16_malloc(2 * coded_length); + if (!llr_us) { + perror("malloc"); + exit(-1); + } + llr_c = srslte_vec_u8_malloc(2 * coded_length); if (!llr_c) { perror("malloc"); exit(-1); @@ -188,21 +205,21 @@ int main(int argc, char** argv) for (uint32_t i = 0; i < snr_points; i++) { frame_cnt = 0; - errors = 0; -#ifdef TEST_SSE - errors2 = 0; -#endif + errors_s = 0; + errors_c = 0; + errors_f = 0; + errors_sse = 0; while (frame_cnt < nof_frames) { /* generate data_tx */ srslte_random_t random_gen = srslte_random_init(0); - for (j = 0; j < frame_length; j++) { + for (int j = 0; j < frame_length; j++) { data_tx[j] = srslte_random_uniform_int_dist(random_gen, 0, 1); } srslte_random_free(random_gen); /* uncoded BER */ - for (j = 0; j < frame_length; j++) { + for (int j = 0; j < frame_length; j++) { llr[j] = data_tx[j] ? M_SQRT2 : -M_SQRT2; } srslte_ch_awgn_f(llr, llr, varunc[i], frame_length); @@ -210,60 +227,52 @@ int main(int argc, char** argv) /* coded BER */ srslte_convcoder_encode(&cod, data_tx, symbols, frame_length); - for (j = 0; j < coded_length; j++) { + for (int j = 0; j < coded_length; j++) { llr[j] = symbols[j] ? M_SQRT2 : -M_SQRT2; } srslte_ch_awgn_f(llr, llr, var[i], coded_length); // srslte_vec_fprint_f(stdout, llr, 100); - srslte_vec_quant_fuc(llr, llr_c, 32, 127.5, 255, coded_length); - srslte_vec_quant_fus(llr, llr_s, 8192, 32767.5, 65535, coded_length); - - struct timeval t[3]; - gettimeofday(&t[1], NULL); - int M = 1; - - for (uint32_t i = 0; i < M; i++) { -#ifdef VITERBI_16 - srslte_viterbi_decode_us(&dec, llr_s, data_rx, frame_length); -#else - srslte_viterbi_decode_uc(&dec, llr_c, data_rx, frame_length); -#endif - } - -#ifdef TEST_SSE - gettimeofday(&t[2], NULL); - get_time_interval(t); - // printf("Execution time:\t\t%.1f us\n", (float) t[0].tv_usec/M); - gettimeofday(&t[1], NULL); - for (int i = 0; i < M; i++) { - srslte_viterbi_decode_uc(&dec_sse, llr_c, data_rx2, frame_length); - } - gettimeofday(&t[2], NULL); - get_time_interval(t); - // printf("Execution time SIMD:\t%.1f us\n", (float) t[0].tv_usec/M); -#endif + srslte_vec_convert_fi(llr, 1000, llr_s, coded_length); + srslte_vec_quant_fuc(llr, llr_c, 32, INT8_MAX, UINT8_MAX, coded_length); + srslte_vec_quant_fus(llr, llr_us, 8192, INT16_MAX, UINT16_MAX, coded_length); - /* check errors */ - errors += srslte_bit_diff(data_tx, data_rx, frame_length); + VITERBI_TEST(srslte_viterbi_decode_s, dec, llr_s, errors_s); + VITERBI_TEST(srslte_viterbi_decode_us, dec, llr_us, errors_us); + VITERBI_TEST(srslte_viterbi_decode_uc, dec, llr_c, errors_c); + VITERBI_TEST(srslte_viterbi_decode_f, dec, llr, errors_f); #ifdef TEST_SSE - errors2 += srslte_bit_diff(data_tx, data_rx2, frame_length); + VITERBI_TEST(srslte_viterbi_decode_uc, dec_sse, llr_c, errors_sse); #endif frame_cnt++; - printf("Eb/No: %3.2f %10d/%d ", SNR_MIN + i * ebno_inc, frame_cnt, nof_frames); - printf("BER: %.2e ", (float)errors / (frame_cnt * frame_length)); + printf(" Eb/No: %3.2f %10d/%d ", SNR_MIN + i * ebno_inc, frame_cnt, nof_frames); + if (errors_s >= 0) + printf(" int16 BER: %.2e ", (float)errors_s / (frame_cnt * frame_length)); + if (errors_us >= 0) + printf("uint16 BER: %.2e ", (float)errors_us / (frame_cnt * frame_length)); + if (errors_c >= 0) + printf("uint8 BER: %.2e ", (float)errors_c / (frame_cnt * frame_length)); + if (errors_f >= 0) + printf("float BER: %.2e ", (float)errors_f / (frame_cnt * frame_length)); #ifdef TEST_SSE - printf("BER2: %.2e ", (float)errors2 / (frame_cnt * frame_length)); + printf("sse BER: %.2e ", (float)errors_sse / (frame_cnt * frame_length)); #endif - printf("\r"); + printf("\r\n"); } printf("\n"); if (snr_points == 1) { - printf("BER : %g\t%u errors\n", (float)errors / (frame_cnt * frame_length), errors); + if (errors_s >= 0) + printf(" int16 BER : %g\t%u errors\n", (float)errors_s / (frame_cnt * frame_length), errors_s); + if (errors_us >= 0) + printf("uint16 BER : %g\t%u errors\n", (float)errors_us / (frame_cnt * frame_length), errors_us); + if (errors_c >= 0) + printf("uint8 BER : %g\t%u errors\n", (float)errors_c / (frame_cnt * frame_length), errors_c); + if (errors_f >= 0) + printf("float BER : %g\t%u errors\n", (float)errors_f / (frame_cnt * frame_length), errors_f); #ifdef TEST_SSE - printf("BER SSE: %g\t%u errors\n", (float)errors2 / (frame_cnt * frame_length), errors2); + printf("sse BER : %g\t%u errors\n", (float)errors_sse / (frame_cnt * frame_length), errors_sse); #endif } } @@ -277,17 +286,24 @@ int main(int argc, char** argv) free(llr); free(llr_c); free(llr_s); + free(llr_us); free(data_rx); - free(data_rx2); if (snr_points == 1) { - int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db); - if (expected_errors == -1) { + int expected_e = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db); + if (expected_e == -1) { ERROR("Test parameters not defined in test_results.h\n"); exit(-1); } else { - printf("errors =%d, expected =%d\n", errors, expected_errors); - exit(errors > expected_errors); + printf( + "errors =(%d,%d,%d,%d,%d), expected =%d\n", errors_s, errors_us, errors_c, errors_f, errors_sse, expected_e); + bool passed = true; + passed &= (bool)(errors_us <= expected_e); + passed &= (bool)(errors_s <= expected_e); + passed &= (bool)(errors_c <= expected_e); + passed &= (bool)(errors_f <= expected_e); + passed &= (bool)(errors_sse <= expected_e); + exit(!passed); } } else { printf("\n"); diff --git a/lib/src/phy/fec/test/viterbi_test.h b/lib/src/phy/fec/test/viterbi_test.h index 7dc81975c..9a264379b 100644 --- a/lib/src/phy/fec/test/viterbi_test.h +++ b/lib/src/phy/fec/test/viterbi_test.h @@ -38,6 +38,11 @@ static expected_errors_t expected_errors[] = {{1000, 1, 40, true, 0.0, 7282}, {1000, 1, 40, true, 3.0, 176}, {1000, 1, 40, true, 4.5, 24}, + {1000, 1, 56, true, 0.0, 7282}, + {1000, 1, 56, true, 2.0, 725}, + {1000, 1, 56, true, 3.0, 176}, + {1000, 1, 56, true, 4.5, 24}, + {100, 1, 1000, true, 0.0, 13208}, {100, 1, 1000, true, 2.0, 939}, {100, 1, 1000, true, 3.0, 110}, diff --git a/lib/src/phy/fec/viterbi.c b/lib/src/phy/fec/viterbi.c index 2e4a32919..2e77bc95a 100644 --- a/lib/src/phy/fec/viterbi.c +++ b/lib/src/phy/fec/viterbi.c @@ -114,6 +114,9 @@ void free37_sse(void* o) if (q->symbols_uc) { free(q->symbols_uc); } + if (q->symbols_us) { + free(q->symbols_us); + } if (q->tmp) { free(q->tmp); } @@ -320,11 +323,18 @@ int init37_sse(srslte_viterbi_t* q, int poly[3], uint32_t framebits, bool tail_b q->decode = decode37_sse; q->free = free37_sse; q->decode_f = NULL; - q->symbols_uc = srslte_vec_malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t)); + q->symbols_uc = srslte_vec_u8_malloc(3 * (q->framebits + q->K - 1)); if (!q->symbols_uc) { perror("malloc"); return -1; } +#ifdef VITERBI_16 + q->symbols_us = srslte_vec_u16_malloc(3 * (q->framebits + q->K - 1)); + if (!q->symbols_us) { + perror("malloc"); + return -1; + } +#endif if (q->tail_biting) { q->tmp = srslte_vec_malloc(TB_ITER * 3 * (q->framebits + q->K - 1) * sizeof(uint8_t)); if (!q->tmp) { @@ -477,6 +487,7 @@ int srslte_viterbi_init(srslte_viterbi_t* q, uint32_t max_frame_length, bool tail_bitting) { + bzero(q, sizeof(srslte_viterbi_t)); switch (type) { case SRSLTE_VITERBI_37: #ifdef LV_HAVE_SSE @@ -586,7 +597,7 @@ int srslte_viterbi_decode_s(srslte_viterbi_t* q, int16_t* symbols, uint8_t* data } } #ifdef VITERBI_16 - srslte_vec_quant_sus(symbols, q->symbols_us, 1, 32767, len); + srslte_vec_quant_sus(symbols, q->symbols_us, 1, (float)INT16_MAX, UINT16_MAX, len); return srslte_viterbi_decode_us(q, q->symbols_us, data, frame_length); #else srslte_vec_quant_suc(symbols, q->symbols_uc, (float)q->gain_quant / max, 127, 255, len); @@ -596,10 +607,22 @@ int srslte_viterbi_decode_s(srslte_viterbi_t* q, int16_t* symbols, uint8_t* data int srslte_viterbi_decode_us(srslte_viterbi_t* q, uint16_t* symbols, uint8_t* data, uint32_t frame_length) { - return q->decode_s(q, symbols, data, frame_length); + int ret = SRSLTE_ERROR; + + if (q && q->decode_s) { + ret = q->decode_s(q, symbols, data, frame_length); + } + + return ret; } int srslte_viterbi_decode_uc(srslte_viterbi_t* q, uint8_t* symbols, uint8_t* data, uint32_t frame_length) { - return q->decode(q, symbols, data, frame_length); + int ret = SRSLTE_ERROR; + + if (q && q->decode) { + ret = q->decode(q, symbols, data, frame_length); + } + + return ret; } diff --git a/lib/src/phy/utils/bit.c b/lib/src/phy/utils/bit.c index 21837bbe2..b5579f56e 100644 --- a/lib/src/phy/utils/bit.c +++ b/lib/src/phy/utils/bit.c @@ -784,7 +784,7 @@ void srslte_bit_fprint(FILE* stream, uint8_t* bits, int nof_bits) fprintf(stream, "%d]\n", bits[i]); } -uint32_t srslte_bit_diff(uint8_t* x, uint8_t* y, int nbits) +uint32_t srslte_bit_diff(const uint8_t* x, const uint8_t* y, int nbits) { uint32_t errors = 0; for (int i = 0; i < nbits; i++) { diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index b0bb01d4e..fe5fbf79a 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -154,6 +154,26 @@ float* srslte_vec_f_malloc(uint32_t nsamples) return (float*)srslte_vec_malloc((uint32_t)sizeof(float) * nsamples); } +int16_t* srslte_vec_i16_malloc(uint32_t nsamples) +{ + return (int16_t*)srslte_vec_malloc((uint32_t)sizeof(int16_t) * nsamples); +} + +uint16_t* srslte_vec_u16_malloc(uint32_t nsamples) +{ + return (uint16_t*)srslte_vec_malloc((uint32_t)sizeof(uint16_t) * nsamples); +} + +int8_t* srslte_vec_i8_malloc(uint32_t nsamples) +{ + return (int8_t*)srslte_vec_malloc((uint32_t)sizeof(int8_t) * nsamples); +} + +uint8_t* srslte_vec_u8_malloc(uint32_t nsamples) +{ + return (uint8_t*)srslte_vec_malloc((uint32_t)sizeof(uint8_t) * nsamples); +} + void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_size) { #ifndef LV_HAVE_SSE @@ -499,17 +519,17 @@ uint32_t srslte_vec_max_abs_ci(const cf_t* x, const uint32_t len) return srslte_vec_max_ci_simd(x, len); } -void srslte_vec_quant_fus(float* in, uint16_t* out, float gain, float offset, float clip, uint32_t len) +void srslte_vec_quant_fus(const float* in, + uint16_t* out, + const float gain, + const float offset, + const uint16_t clip, + const uint32_t len) { - int i; - long tmp; - - for (i = 0; i < len; i++) { - tmp = (long)(offset + gain * in[i]); - if (tmp < 0) - tmp = 0; - if (tmp > clip) - tmp = clip; + for (uint32_t i = 0; i < len; i++) { + int32_t tmp = (int32_t)(offset + gain * in[i]); + tmp = SRSLTE_MAX(tmp, 0); + tmp = SRSLTE_MIN(tmp, (int32_t)clip); out[i] = (uint16_t)tmp; } } @@ -518,18 +538,13 @@ void srslte_vec_quant_fuc(const float* in, uint8_t* out, const float gain, const float offset, - const float clip, + const uint8_t clip, const uint32_t len) { - int i; - int tmp; - - for (i = 0; i < len; i++) { - tmp = (int)(offset + gain * in[i]); - if (tmp < 0) - tmp = 0; - if (tmp > clip) - tmp = clip; + for (uint32_t i = 0; i < len; i++) { + int32_t tmp = (int32_t)(offset + gain * in[i]); + tmp = SRSLTE_MAX(tmp, 0); + tmp = SRSLTE_MIN(tmp, (int32_t)clip); out[i] = (uint8_t)tmp; } } @@ -537,32 +552,29 @@ void srslte_vec_quant_fuc(const float* in, void srslte_vec_quant_suc(const int16_t* in, uint8_t* out, const float gain, - const int16_t offset, - const int16_t clip, + const float offset, + const uint8_t clip, const uint32_t len) { - int i; - int16_t tmp; - - for (i = 0; i < len; i++) { - tmp = (int16_t)(offset + in[i] * gain); - if (tmp < 0) - tmp = 0; - if (tmp > clip) - tmp = clip; + for (uint32_t i = 0; i < len; i++) { + int32_t tmp = (int32_t)(offset + (float)in[i] * gain); + tmp = SRSLTE_MAX(tmp, 0); + tmp = SRSLTE_MIN(tmp, (int32_t)clip); out[i] = (uint8_t)tmp; } } -void srslte_vec_quant_sus(const int16_t* in, uint16_t* out, const float gain, const int16_t offset, const uint32_t len) +void srslte_vec_quant_sus(const int16_t* in, + uint16_t* out, + const float gain, + const float offset, + const uint16_t clip, + const uint32_t len) { - int i; - int16_t tmp; - - for (i = 0; i < len; i++) { - tmp = (offset + in[i] * gain); - if (tmp < 0) - tmp = 0; + for (uint32_t i = 0; i < len; i++) { + int32_t tmp = (int32_t)(offset + gain * (float)in[i]); + tmp = SRSLTE_MAX(tmp, 0); + tmp = SRSLTE_MIN(tmp, (int32_t)clip); out[i] = (uint16_t)tmp; } }