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:
parent
43df43ff9d
commit
715987e749
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user