mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-30 23:03:05 +00:00 
			
		
		
		
	Improve design of the Viterbi Decoder API
Easier to use, it does not require external memory for internal states anymore
This commit is contained in:
		| @@ -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<uint32_t>(d_mm);  // 2^d_mm | ||||
|     d_out0 = std::vector<int32_t>(max_states); | ||||
|     d_out1 = std::vector<int32_t>(max_states); | ||||
|     d_state0 = std::vector<int32_t>(max_states); | ||||
|     d_state1 = std::vector<int32_t>(max_states); | ||||
|  | ||||
|     // create Vitrebi decoder and appropriate transition vectors | ||||
|     // Instantiate the Viterbi decoder | ||||
|     d_viterbi = std::make_unique<Viterbi_Decoder>(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<int32_t> 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<int32_t> 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<int32_t> 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<uint32_t>(d_mm);  // 2^d_mm | ||||
|     d_out0 = std::vector<int32_t>(max_states); | ||||
|     d_out1 = std::vector<int32_t>(max_states); | ||||
|     d_state0 = std::vector<int32_t>(max_states); | ||||
|     d_state1 = std::vector<int32_t>(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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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<Viterbi_Decoder> d_viterbi; | ||||
|     std::vector<int32_t> d_preamble_samples; | ||||
|     std::vector<float> d_page_part_symbols; | ||||
|     std::vector<int32_t> d_out0; | ||||
|     std::vector<int32_t> d_out1; | ||||
|     std::vector<int32_t> d_state0; | ||||
|     std::vector<int32_t> d_state1; | ||||
|  | ||||
|     std::string d_dump_filename; | ||||
|     std::ofstream d_dump_file; | ||||
|   | ||||
| @@ -33,15 +33,16 @@ Viterbi_Decoder::Viterbi_Decoder(int32_t KK, int32_t nn, int32_t LL, const std:: | ||||
|     d_prev_bit = std::vector<int32_t>(d_states * (d_LL + d_mm)); | ||||
|     d_prev_state = std::vector<int32_t>(d_states * (d_LL + d_mm)); | ||||
|     d_g = g; | ||||
|     d_out0 = std::vector<int32_t>(d_states); | ||||
|     d_out1 = std::vector<int32_t>(d_states); | ||||
|     d_state0 = std::vector<int32_t>(d_states); | ||||
|     d_state1 = std::vector<int32_t>(d_states); | ||||
|     nsc_transit(d_out0, d_state0, 0); | ||||
|     nsc_transit(d_out1, d_state1, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Viterbi_Decoder::decode(std::vector<int32_t>& output_u_int, | ||||
|     const std::vector<int32_t>& out0, | ||||
|     const std::vector<int32_t>& state0, | ||||
|     const std::vector<int32_t>& out1, | ||||
|     const std::vector<int32_t>& state1, | ||||
|     const std::vector<float>& input_c) | ||||
| void Viterbi_Decoder::decode(std::vector<int32_t>& output_u_int, const std::vector<float>& input_c) | ||||
| { | ||||
|     int32_t i; | ||||
|     int32_t t; | ||||
| @@ -67,25 +68,25 @@ void Viterbi_Decoder::decode(std::vector<int32_t>& 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<int32_t>& output_u_int, | ||||
| } | ||||
|  | ||||
|  | ||||
| void Viterbi_Decoder::reset() | ||||
| { | ||||
|     d_out0 = std::vector<int32_t>(d_states); | ||||
|     d_out1 = std::vector<int32_t>(d_states); | ||||
|     d_state0 = std::vector<int32_t>(d_states); | ||||
|     d_state1 = std::vector<int32_t>(d_states); | ||||
|     nsc_transit(d_out0, d_state0, 0); | ||||
|     nsc_transit(d_out1, d_state1, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| void Viterbi_Decoder::nsc_transit(std::vector<int32_t>& output_p, | ||||
|     std::vector<int32_t>& trans_p, | ||||
|     int32_t input) const | ||||
|   | ||||
| @@ -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<int32_t>& output_u_int, | ||||
|         const std::vector<int32_t>& out0, | ||||
|         const std::vector<int32_t>& state0, | ||||
|         const std::vector<int32_t>& out1, | ||||
|         const std::vector<int32_t>& state1, | ||||
|         const std::vector<float>& input_c); | ||||
|     void decode(std::vector<int32_t>& output_u_int, const std::vector<float>& 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<int32_t>& output_p, | ||||
|         std::vector<int32_t>& 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<int32_t> d_prev_state{}; | ||||
|     std::array<int32_t, 2> d_g{}; | ||||
|  | ||||
|     std::vector<int32_t> d_out0; | ||||
|     std::vector<int32_t> d_out1; | ||||
|     std::vector<int32_t> d_state0; | ||||
|     std::vector<int32_t> d_state1; | ||||
|  | ||||
|     float d_MAXLOG = 1e7;  // Define infinity | ||||
|     int32_t d_KK{}; | ||||
|     int32_t d_nn{}; | ||||
|   | ||||
| @@ -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 <gtest/gtest.h> | ||||
| #include <algorithm>  // 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<Viterbi_Decoder>(KK, nn, ((488 / nn) - mm), g_encoder); | ||||
|         viterbi_inav = std::make_unique<Viterbi_Decoder>(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<int32_t, 2> g_encoder{{121, 91}}; | ||||
|     std::shared_ptr<Viterbi_Decoder> viterbi_fnav = std::make_shared<Viterbi_Decoder>(KK, nn, ((488 / nn) - mm), g_encoder); | ||||
|     std::shared_ptr<Viterbi_Decoder> viterbi_inav = std::make_shared<Viterbi_Decoder>(KK, nn, ((240 / nn) - mm), g_encoder); | ||||
|  | ||||
|     int32_t max_states = 1 << mm;  // 2^mm | ||||
|  | ||||
|     std::vector<int32_t> i_out0 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> i_out1 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> i_state0 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> i_state1 = std::vector<int32_t>(max_states); | ||||
|  | ||||
|     std::vector<int32_t> f_out0 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> f_out1 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> f_state0 = std::vector<int32_t>(max_states); | ||||
|     std::vector<int32_t> f_state1 = std::vector<int32_t>(max_states); | ||||
|     std::unique_ptr<Viterbi_Decoder> viterbi_fnav; | ||||
|     std::unique_ptr<Viterbi_Decoder> 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<int32_t> page_part_bits = std::vector<int32_t>(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<int32_t> page_bits = std::vector<int32_t>(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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez