1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-14 12:10:34 +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_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;
}

View File

@ -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;

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_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

View File

@ -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{};

View File

@ -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;