1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-14 20:20:35 +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:
Carles Fernandez 2021-09-26 13:23:28 +02:00
parent 43df43ff9d
commit 715987e749
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
5 changed files with 62 additions and 80 deletions

View File

@ -236,17 +236,8 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs(
d_inav_nav.init_PRN(d_satellite.get_PRN()); d_inav_nav.init_PRN(d_satellite.get_PRN());
d_first_eph_sent = false; d_first_eph_sent = false;
// vars for Viterbi decoder // Instantiate the 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
d_viterbi = std::make_unique<Viterbi_Decoder>(KK, nn, d_datalength, g_encoder); 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; const int32_t decoded_length = frame_length / 2;
std::vector<int32_t> page_part_bits(decoded_length); 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 // 3. Call the Galileo page decoder
std::string page_String; 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; const int32_t decoded_length = frame_length / 2;
std::vector<int32_t> page_bits(decoded_length); 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 // 3. Call the Galileo page decoder
std::string page_String; 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; const int32_t decoded_length = page_length / 2;
std::vector<int32_t> page_bits(decoded_length); 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 // 3. Call the Galileo page decoder
std::string page_String; std::string page_String;
@ -617,13 +608,7 @@ void galileo_telemetry_decoder_gs::reset()
d_last_valid_preamble = d_sample_counter; d_last_valid_preamble = d_sample_counter;
d_sent_tlm_failed_msg = false; d_sent_tlm_failed_msg = false;
d_stat = 0; d_stat = 0;
const int32_t max_states = 1U << static_cast<uint32_t>(d_mm); // 2^d_mm d_viterbi->reset();
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);
DLOG(INFO) << "Telemetry decoder reset for satellite " << d_satellite; DLOG(INFO) << "Telemetry decoder reset for satellite " << d_satellite;
} }

View File

@ -85,14 +85,9 @@ private:
void decode_FNAV_word(float *page_symbols, int32_t frame_length); void decode_FNAV_word(float *page_symbols, int32_t frame_length);
void decode_CNAV_word(float *page_symbols, int32_t page_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::unique_ptr<Viterbi_Decoder> d_viterbi;
std::vector<int32_t> d_preamble_samples; std::vector<int32_t> d_preamble_samples;
std::vector<float> d_page_part_symbols; 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::string d_dump_filename;
std::ofstream d_dump_file; std::ofstream d_dump_file;

View 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_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_prev_state = std::vector<int32_t>(d_states * (d_LL + d_mm));
d_g = g; 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, void Viterbi_Decoder::decode(std::vector<int32_t>& output_u_int, const std::vector<float>& input_c)
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)
{ {
int32_t i; int32_t i;
int32_t t; 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++) for (state = 0; state < d_states; state++)
{ {
// hypothesis: info bit is a zero // 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 // 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_next_section[d_state0[state]] = metric;
d_prev_state[t * d_states + state0[state]] = state; d_prev_state[t * d_states + d_state0[state]] = state;
d_prev_bit[t * d_states + state0[state]] = 0; d_prev_bit[t * d_states + d_state0[state]] = 0;
} }
// hypothesis: info bit is a one // 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 // 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_next_section[d_state1[state]] = metric;
d_prev_state[t * d_states + state1[state]] = state; d_prev_state[t * d_states + d_state1[state]] = state;
d_prev_bit[t * d_states + state1[state]] = 1; 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, void Viterbi_Decoder::nsc_transit(std::vector<int32_t>& output_p,
std::vector<int32_t>& trans_p, std::vector<int32_t>& trans_p,
int32_t input) const int32_t input) const

View File

@ -28,12 +28,15 @@
* \{ */ * \{ */
/*!
* \brief Class that implements a Viterbi decoder
*/
class Viterbi_Decoder class Viterbi_Decoder
{ {
public: public:
/*! /*!
* \brief Constructor of a Viterbi decoder * \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] nn Coding rate 1/n
* \param[in] LL Data length * \param[in] LL Data length
* \param[in] g Polynomial G1 and G2 * \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. * \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[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). * \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, void decode(std::vector<int32_t>& output_u_int, const std::vector<float>& input_c);
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);
/*! /*!
* \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, void nsc_transit(std::vector<int32_t>& output_p,
std::vector<int32_t>& trans_p, std::vector<int32_t>& trans_p,
int32_t input) const; int32_t input) const;
private:
/* /*
* Computes the branch metric used for decoding. * Computes the branch metric used for decoding.
* \return (returned float) The metric between the hypothetical symbol and the received vector * \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] symbol The integer-valued symbol
* \param[in] length The highest bit position in the 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; 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. * 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. * 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] 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] 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 * \param[out] state_out_p[] An integer containing the final state of the encoder
* (i.e. the state after encoding this bit) * (i.e. the state after encoding this bit)
* *
@ -111,6 +110,11 @@ private:
std::vector<int32_t> d_prev_state{}; std::vector<int32_t> d_prev_state{};
std::array<int32_t, 2> d_g{}; 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 float d_MAXLOG = 1e7; // Define infinity
int32_t d_KK{}; int32_t d_KK{};
int32_t d_nn{}; int32_t d_nn{};

View File

@ -18,6 +18,7 @@
#include "galileo_fnav_message.h" #include "galileo_fnav_message.h"
#include "galileo_inav_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 "viterbi_decoder.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <algorithm> // for copy #include <algorithm> // for copy
@ -34,11 +35,8 @@ class Galileo_FNAV_INAV_test : public ::testing::Test
public: public:
Galileo_FNAV_INAV_test() Galileo_FNAV_INAV_test()
{ {
// vars for Viterbi decoder viterbi_fnav = std::make_unique<Viterbi_Decoder>(KK, nn, ((488 / nn) - mm), g_encoder);
viterbi_inav->nsc_transit(i_out0, i_state0, 0); viterbi_inav = std::make_unique<Viterbi_Decoder>(KK, nn, ((240 / nn) - mm), g_encoder);
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);
flag_even_word_arrived = 0; flag_even_word_arrived = 0;
} }
@ -48,23 +46,11 @@ public:
Galileo_Fnav_Message FNAV_decoder; Galileo_Fnav_Message FNAV_decoder;
const int32_t nn = 2; // Coding rate 1/n const int32_t nn = 2; // Coding rate 1/n
const int32_t KK = 7; // Constraint Length const int32_t KK = 7; // Constraint Length
int32_t mm = KK - 1; const int32_t mm = KK - 1;
int32_t flag_even_word_arrived;
const std::array<int32_t, 2> g_encoder{{121, 91}}; 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::unique_ptr<Viterbi_Decoder> viterbi_fnav;
std::shared_ptr<Viterbi_Decoder> viterbi_inav = std::make_shared<Viterbi_Decoder>(KK, nn, ((240 / nn) - mm), g_encoder); std::unique_ptr<Viterbi_Decoder> viterbi_inav;
int32_t flag_even_word_arrived;
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);
void deinterleaver(int32_t rows, int32_t cols, const float *in, float *out) 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); 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 // 3. Call the Galileo page decoder
std::string page_String; std::string page_String;
@ -151,7 +137,7 @@ public:
} }
std::vector<int32_t> page_bits = std::vector<int32_t>(frame_length); 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 // 3. Call the Galileo page decoder
std::string page_String; std::string page_String;