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:
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_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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{};
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user