From 715987e7496daa2a5a9ffca071c81d317bb8e3bf Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 26 Sep 2021 13:23:28 +0200 Subject: [PATCH] Improve design of the Viterbi Decoder API Easier to use, it does not require external memory for internal states anymore --- .../galileo_telemetry_decoder_gs.cc | 25 +++-------- .../galileo_telemetry_decoder_gs.h | 5 --- .../telemetry_decoder/libs/viterbi_decoder.cc | 44 ++++++++++++------- .../telemetry_decoder/libs/viterbi_decoder.h | 36 ++++++++------- .../galileo_fnav_inav_decoder_test.cc | 32 ++++---------- 5 files changed, 62 insertions(+), 80 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index d93d690ec..89c51e727 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -236,17 +236,8 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( d_inav_nav.init_PRN(d_satellite.get_PRN()); d_first_eph_sent = false; - // vars for Viterbi decoder - const int32_t max_states = 1U << static_cast(d_mm); // 2^d_mm - d_out0 = std::vector(max_states); - d_out1 = std::vector(max_states); - d_state0 = std::vector(max_states); - d_state1 = std::vector(max_states); - - // create Vitrebi decoder and appropriate transition vectors + // Instantiate the Viterbi decoder d_viterbi = std::make_unique(KK, nn, d_datalength, g_encoder); - d_viterbi->nsc_transit(d_out0, d_state0, 0); - d_viterbi->nsc_transit(d_out1, d_state1, 1); } @@ -317,7 +308,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } const int32_t decoded_length = frame_length / 2; std::vector page_part_bits(decoded_length); - d_viterbi->decode(page_part_bits, d_out0, d_state0, d_out1, d_state1, page_part_symbols_soft_value); + d_viterbi->decode(page_part_bits, page_part_symbols_soft_value); // 3. Call the Galileo page decoder std::string page_String; @@ -470,7 +461,7 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t const int32_t decoded_length = frame_length / 2; std::vector page_bits(decoded_length); - d_viterbi->decode(page_bits, d_out0, d_state0, d_out1, d_state1, page_symbols_soft_value); + d_viterbi->decode(page_bits, page_symbols_soft_value); // 3. Call the Galileo page decoder std::string page_String; @@ -543,7 +534,7 @@ void galileo_telemetry_decoder_gs::decode_CNAV_word(float *page_symbols, int32_t } const int32_t decoded_length = page_length / 2; std::vector page_bits(decoded_length); - d_viterbi->decode(page_bits, d_out0, d_state0, d_out1, d_state1, page_symbols_soft_value); + d_viterbi->decode(page_bits, page_symbols_soft_value); // 3. Call the Galileo page decoder std::string page_String; @@ -617,13 +608,7 @@ void galileo_telemetry_decoder_gs::reset() d_last_valid_preamble = d_sample_counter; d_sent_tlm_failed_msg = false; d_stat = 0; - const int32_t max_states = 1U << static_cast(d_mm); // 2^d_mm - d_out0 = std::vector(max_states); - d_out1 = std::vector(max_states); - d_state0 = std::vector(max_states); - d_state1 = std::vector(max_states); - d_viterbi->nsc_transit(d_out0, d_state0, 0); - d_viterbi->nsc_transit(d_out1, d_state1, 1); + d_viterbi->reset(); DLOG(INFO) << "Telemetry decoder reset for satellite " << d_satellite; } diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index da09f1d29..68ac43e2d 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -85,14 +85,9 @@ private: void decode_FNAV_word(float *page_symbols, int32_t frame_length); void decode_CNAV_word(float *page_symbols, int32_t page_length); - // data members for Viterbi decoder std::unique_ptr d_viterbi; std::vector d_preamble_samples; std::vector d_page_part_symbols; - std::vector d_out0; - std::vector d_out1; - std::vector d_state0; - std::vector d_state1; std::string d_dump_filename; std::ofstream d_dump_file; diff --git a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc index 825cd0f35..8534a0d54 100644 --- a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc +++ b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc @@ -33,15 +33,16 @@ Viterbi_Decoder::Viterbi_Decoder(int32_t KK, int32_t nn, int32_t LL, const std:: d_prev_bit = std::vector(d_states * (d_LL + d_mm)); d_prev_state = std::vector(d_states * (d_LL + d_mm)); d_g = g; + d_out0 = std::vector(d_states); + d_out1 = std::vector(d_states); + d_state0 = std::vector(d_states); + d_state1 = std::vector(d_states); + nsc_transit(d_out0, d_state0, 0); + nsc_transit(d_out1, d_state1, 1); } -void Viterbi_Decoder::decode(std::vector& output_u_int, - const std::vector& out0, - const std::vector& state0, - const std::vector& out1, - const std::vector& state1, - const std::vector& input_c) +void Viterbi_Decoder::decode(std::vector& output_u_int, const std::vector& input_c) { int32_t i; int32_t t; @@ -67,25 +68,25 @@ void Viterbi_Decoder::decode(std::vector& output_u_int, for (state = 0; state < d_states; state++) { // hypothesis: info bit is a zero - metric = d_prev_section[state] + d_metric_c[out0[state]]; + metric = d_prev_section[state] + d_metric_c[d_out0[state]]; // store new metric if more than metric in storage - if (metric > d_next_section[state0[state]]) + if (metric > d_next_section[d_state0[state]]) { - d_next_section[state0[state]] = metric; - d_prev_state[t * d_states + state0[state]] = state; - d_prev_bit[t * d_states + state0[state]] = 0; + d_next_section[d_state0[state]] = metric; + d_prev_state[t * d_states + d_state0[state]] = state; + d_prev_bit[t * d_states + d_state0[state]] = 0; } // hypothesis: info bit is a one - metric = d_prev_section[state] + d_metric_c[out1[state]]; + metric = d_prev_section[state] + d_metric_c[d_out1[state]]; // store new metric if more than metric in storage - if (metric > d_next_section[state1[state]]) + if (metric > d_next_section[d_state1[state]]) { - d_next_section[state1[state]] = metric; - d_prev_state[t * d_states + state1[state]] = state; - d_prev_bit[t * d_states + state1[state]] = 1; + d_next_section[d_state1[state]] = metric; + d_prev_state[t * d_states + d_state1[state]] = state; + d_prev_bit[t * d_states + d_state1[state]] = 1; } } @@ -117,6 +118,17 @@ void Viterbi_Decoder::decode(std::vector& output_u_int, } +void Viterbi_Decoder::reset() +{ + d_out0 = std::vector(d_states); + d_out1 = std::vector(d_states); + d_state0 = std::vector(d_states); + d_state1 = std::vector(d_states); + nsc_transit(d_out0, d_state0, 0); + nsc_transit(d_out1, d_state1, 1); +} + + void Viterbi_Decoder::nsc_transit(std::vector& output_p, std::vector& trans_p, int32_t input) const diff --git a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.h b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.h index ca8a7b896..06470f5a6 100644 --- a/src/algorithms/telemetry_decoder/libs/viterbi_decoder.h +++ b/src/algorithms/telemetry_decoder/libs/viterbi_decoder.h @@ -28,12 +28,15 @@ * \{ */ +/*! + * \brief Class that implements a Viterbi decoder + */ class Viterbi_Decoder { public: /*! * \brief Constructor of a Viterbi decoder - * \param[in] KK Constraint Length + * \param[in] KK Constraint length * \param[in] nn Coding rate 1/n * \param[in] LL Data length * \param[in] g Polynomial G1 and G2 @@ -43,28 +46,24 @@ public: /*! * \brief Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code. * \param[out] output_u_int Hard decisions on the data bits - * \param[in] out0 The output bits for each state if input is a 0. - * \param[in] state0 The next state if input is a 0. - * \param[in] out1 The output bits for each state if input is a 1. - * \param[in] state1 The next state if input is a 1. * \param[in] input_c The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2). * */ - void decode(std::vector& output_u_int, - const std::vector& out0, - const std::vector& state0, - const std::vector& out1, - const std::vector& state1, - const std::vector& input_c); + void decode(std::vector& output_u_int, const std::vector& input_c); /*! - * \brief Function that creates the transit and output vectors + * \brief Reset internal status + */ + void reset(); + +private: + /* + * Function that creates the transit and output vectors */ void nsc_transit(std::vector& output_p, std::vector& trans_p, int32_t input) const; -private: /* * Computes the branch metric used for decoding. * \return (returned float) The metric between the hypothetical symbol and the received vector @@ -81,7 +80,7 @@ private: * \param[in] symbol The integer-valued symbol * \param[in] length The highest bit position in the symbol * - * This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail() + * This function is used by nsc_enc_bit() */ int32_t parity_counter(int32_t symbol, int32_t length) const; @@ -89,10 +88,10 @@ private: * Convolutionally encodes a single bit using a rate 1/n encoder. * Takes in one input bit at a time, and produces a n-bit output. * + * \return (returned int): Computed output + * * \param[in] input The input data bit (i.e. a 0 or 1). * \param[in] state_in The starting state of the encoder (an int from 0 to 2^m-1). - * \param[in] g An n-element vector containing the code generators in binary form. - * \param[out] output_p[] An n-element vector containing the encoded bits. * \param[out] state_out_p[] An integer containing the final state of the encoder * (i.e. the state after encoding this bit) * @@ -111,6 +110,11 @@ private: std::vector d_prev_state{}; std::array d_g{}; + std::vector d_out0; + std::vector d_out1; + std::vector d_state0; + std::vector d_state1; + float d_MAXLOG = 1e7; // Define infinity int32_t d_KK{}; int32_t d_nn{}; diff --git a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc index 9166a6b59..61b4d60ef 100644 --- a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc @@ -18,6 +18,7 @@ #include "galileo_fnav_message.h" #include "galileo_inav_message.h" +#include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 #include "viterbi_decoder.h" #include #include // for copy @@ -34,11 +35,8 @@ class Galileo_FNAV_INAV_test : public ::testing::Test public: Galileo_FNAV_INAV_test() { - // vars for Viterbi decoder - viterbi_inav->nsc_transit(i_out0, i_state0, 0); - viterbi_inav->nsc_transit(i_out1, i_state1, 1); - viterbi_fnav->nsc_transit(f_out0, f_state0, 0); - viterbi_fnav->nsc_transit(f_out1, f_state1, 1); + viterbi_fnav = std::make_unique(KK, nn, ((488 / nn) - mm), g_encoder); + viterbi_inav = std::make_unique(KK, nn, ((240 / nn) - mm), g_encoder); flag_even_word_arrived = 0; } @@ -48,23 +46,11 @@ public: Galileo_Fnav_Message FNAV_decoder; const int32_t nn = 2; // Coding rate 1/n const int32_t KK = 7; // Constraint Length - int32_t mm = KK - 1; - int32_t flag_even_word_arrived; + const int32_t mm = KK - 1; const std::array g_encoder{{121, 91}}; - std::shared_ptr viterbi_fnav = std::make_shared(KK, nn, ((488 / nn) - mm), g_encoder); - std::shared_ptr viterbi_inav = std::make_shared(KK, nn, ((240 / nn) - mm), g_encoder); - - int32_t max_states = 1 << mm; // 2^mm - - std::vector i_out0 = std::vector(max_states); - std::vector i_out1 = std::vector(max_states); - std::vector i_state0 = std::vector(max_states); - std::vector i_state1 = std::vector(max_states); - - std::vector f_out0 = std::vector(max_states); - std::vector f_out1 = std::vector(max_states); - std::vector f_state0 = std::vector(max_states); - std::vector f_state1 = std::vector(max_states); + std::unique_ptr viterbi_fnav; + std::unique_ptr viterbi_inav; + int32_t flag_even_word_arrived; void deinterleaver(int32_t rows, int32_t cols, const float *in, float *out) { @@ -96,7 +82,7 @@ public: } std::vector page_part_bits = std::vector(frame_length / 2); - viterbi_inav->decode(page_part_bits, i_out0, i_state0, i_out1, i_state1, page_part_symbols_deint); + viterbi_inav->decode(page_part_bits, page_part_symbols_deint); // 3. Call the Galileo page decoder std::string page_String; @@ -151,7 +137,7 @@ public: } std::vector page_bits = std::vector(frame_length); - viterbi_fnav->decode(page_bits, f_out0, f_state0, f_out1, f_state1, page_symbols_deint); + viterbi_fnav->decode(page_bits, page_symbols_deint); // 3. Call the Galileo page decoder std::string page_String;