mirror of https://github.com/gnss-sdr/gnss-sdr
205 lines
6.4 KiB
C++
205 lines
6.4 KiB
C++
/*!
|
|
* \file viterbi_decoder.cc
|
|
* \brief Class that implements a Viterbi decoder
|
|
* \author Carles Fernandez, 2021. cfernandez(at)cttc.es
|
|
*
|
|
* -----------------------------------------------------------------------------
|
|
*
|
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
|
* This file is part of GNSS-SDR.
|
|
*
|
|
* Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors)
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "viterbi_decoder.h"
|
|
#include <volk_gnsssdr/volk_gnsssdr.h> // for volk_gnsssdr_32f_index_max_32u
|
|
#include <algorithm> // for std::copy
|
|
|
|
Viterbi_Decoder::Viterbi_Decoder(int32_t KK,
|
|
int32_t nn,
|
|
int32_t LL,
|
|
const std::array<int32_t, 2>& g) : d_g(g),
|
|
d_KK(KK),
|
|
d_nn(nn),
|
|
d_LL(LL),
|
|
d_mm(KK - 1),
|
|
d_states(1 << d_mm), // 2^d_mm
|
|
d_number_symbols(1 << nn) // 2^d_nn
|
|
{
|
|
d_prev_section = std::vector<float>(d_states, -d_MAXLOG);
|
|
d_next_section = std::vector<float>(d_states, -d_MAXLOG);
|
|
d_rec_array = std::vector<float>(d_nn);
|
|
d_metric_c = std::vector<float>(d_number_symbols);
|
|
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_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<float>& input_c)
|
|
{
|
|
int32_t i;
|
|
int32_t t;
|
|
int32_t state;
|
|
uint32_t max_index;
|
|
float metric;
|
|
float max_val;
|
|
|
|
d_prev_section[0] = 0.0; // start in all-zeros state
|
|
|
|
// go through trellis
|
|
for (t = 0; t < d_LL + d_mm; t++)
|
|
{
|
|
std::copy(input_c.begin() + d_nn * t, input_c.begin() + d_nn * t + (d_nn - 1), d_rec_array.begin());
|
|
|
|
// precompute all possible branch metrics
|
|
for (i = 0; i < d_number_symbols; i++)
|
|
{
|
|
d_metric_c[i] = this->Gamma(i);
|
|
}
|
|
|
|
// step through all states
|
|
for (state = 0; state < d_states; state++)
|
|
{
|
|
// hypothesis: info bit is a zero
|
|
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[d_state0[state]])
|
|
{
|
|
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[d_out1[state]];
|
|
|
|
// store new metric if more than metric in storage
|
|
if (metric > d_next_section[d_state1[state]])
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
// normalize
|
|
volk_gnsssdr_32f_index_max_32u(&max_index, d_next_section.data(), d_states);
|
|
max_val = d_next_section[max_index];
|
|
|
|
for (state = 0; state < d_states; state++)
|
|
{
|
|
d_prev_section[state] = d_next_section[state] - max_val;
|
|
d_next_section[state] = -d_MAXLOG;
|
|
}
|
|
}
|
|
|
|
// trace-back operation
|
|
state = 0;
|
|
|
|
// tail, no need to output
|
|
for (t = d_LL + d_mm - 1; t >= d_LL; t--)
|
|
{
|
|
state = d_prev_state[t * d_states + state];
|
|
}
|
|
|
|
for (t = d_LL - 1; t >= 0; t--)
|
|
{
|
|
output_u_int[t] = d_prev_bit[t * d_states + state];
|
|
state = d_prev_state[t * d_states + state];
|
|
}
|
|
}
|
|
|
|
|
|
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
|
|
{
|
|
int32_t nextstate;
|
|
int32_t state;
|
|
const int32_t states = (1 << (d_KK - 1)); // The number of states: 2^d_mm
|
|
|
|
// Determine the output and next state for each possible starting state
|
|
for (state = 0; state < states; state++)
|
|
{
|
|
output_p[state] = nsc_enc_bit(&nextstate, input, state);
|
|
trans_p[state] = nextstate;
|
|
}
|
|
}
|
|
|
|
|
|
float Viterbi_Decoder::Gamma(int32_t symbol) const
|
|
{
|
|
float rm = 0;
|
|
int32_t mask = 1;
|
|
int32_t i;
|
|
|
|
for (i = 0; i < d_nn; i++)
|
|
{
|
|
if (symbol & mask)
|
|
{
|
|
rm += d_rec_array[d_nn - i - 1];
|
|
}
|
|
mask = mask << 1;
|
|
}
|
|
return rm;
|
|
}
|
|
|
|
|
|
int32_t Viterbi_Decoder::parity_counter(int32_t symbol, int32_t length) const
|
|
{
|
|
int32_t counter;
|
|
int32_t temp_parity = 0;
|
|
|
|
for (counter = 0; counter < length; counter++)
|
|
{
|
|
temp_parity = temp_parity ^ (symbol & 1);
|
|
symbol = symbol >> 1;
|
|
}
|
|
return temp_parity;
|
|
}
|
|
|
|
|
|
int32_t Viterbi_Decoder::nsc_enc_bit(int32_t* state_out_p,
|
|
int32_t input,
|
|
int32_t state_in) const
|
|
{
|
|
// declare variables
|
|
int32_t i;
|
|
int32_t out_ = 0;
|
|
|
|
// create a word made up of state and new input
|
|
const int32_t state = (input << (d_KK - 1)) ^ state_in;
|
|
|
|
// AND the word with the generators
|
|
for (i = 0; i < d_nn; i++)
|
|
{
|
|
// update output symbol
|
|
out_ = (out_ << 1) + parity_counter(state & d_g[i], d_KK);
|
|
}
|
|
|
|
// shift the state to make the new state
|
|
*state_out_p = state >> 1;
|
|
return out_;
|
|
}
|