mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-01-29 18:34:51 +00:00
Galileo INAV de-interleaver and Viterbi decoder implemented.
git-svn-id: https://svn.code.sf.net/p/gnss-sdr/code/trunk@390 64b25241-fba3-4117-9849-534c7e92360d
This commit is contained in:
parent
b0a323095d
commit
fc04633fba
@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file galileo_e1b_telemetry_decoder_cc.cc
|
* \file galileo_e1b_telemetry_decoder_cc.cc
|
||||||
* \brief Implementation of a NAV message demodulator block
|
* \brief Implementation of a Galileo INAV message demodulator block
|
||||||
* \author Mara Branzanti 2013. mara.branzanti(at)gmail.com
|
* \author Mara Branzanti 2013. mara.branzanti(at)gmail.com
|
||||||
* \author Javier Arribas 2013. jarribas(at)cttc.es
|
* \author Javier Arribas 2013. jarribas(at)cttc.es
|
||||||
*
|
*
|
||||||
@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
#include "gnss_synchro.h"
|
#include "gnss_synchro.h"
|
||||||
|
|
||||||
|
#include "convolutional.h"
|
||||||
|
|
||||||
using google::LogMessage;
|
using google::LogMessage;
|
||||||
|
|
||||||
|
|
||||||
@ -63,6 +65,59 @@ void galileo_e1b_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void galileo_e1b_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int *page_part_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
int CodeLength=240;
|
||||||
|
int DataLength;
|
||||||
|
int nn, KK, mm, max_states;
|
||||||
|
int g_encoder[2];
|
||||||
|
|
||||||
|
nn = 2; //Coding rate 1/n
|
||||||
|
KK = 7; //Constraint Length
|
||||||
|
g_encoder[0]=121; // Polynomial G1
|
||||||
|
g_encoder[1]=91; // Polinomial G2
|
||||||
|
|
||||||
|
mm = KK - 1;
|
||||||
|
max_states = 1 << mm; /* 2^mm */
|
||||||
|
DataLength = (CodeLength/nn)-mm;
|
||||||
|
|
||||||
|
/* create appropriate transition matrices */
|
||||||
|
int *out0, *out1, *state0, *state1;
|
||||||
|
out0 = (int*)calloc( max_states, sizeof(int) );
|
||||||
|
out1 = (int*)calloc( max_states, sizeof(int) );
|
||||||
|
state0 = (int*)calloc( max_states, sizeof(int) );
|
||||||
|
state1 = (int*)calloc( max_states, sizeof(int) );
|
||||||
|
|
||||||
|
nsc_transit( out0, state0, 0, g_encoder, KK, nn );
|
||||||
|
nsc_transit( out1, state1, 1, g_encoder, KK, nn );
|
||||||
|
|
||||||
|
Viterbi( page_part_bits, out0, state0, out1, state1,
|
||||||
|
page_part_symbols, KK, nn, DataLength );
|
||||||
|
|
||||||
|
|
||||||
|
/* Clean up memory */
|
||||||
|
free( out0 );
|
||||||
|
free( out1 );
|
||||||
|
free( state0 );
|
||||||
|
free( state1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void galileo_e1b_telemetry_decoder_cc::deinterleaver(int rows, int cols, double *in, double *out)
|
||||||
|
{
|
||||||
|
for (int r=0;r<rows;r++)
|
||||||
|
{
|
||||||
|
for(int c=0;c<cols;c++)
|
||||||
|
{
|
||||||
|
out[c*rows+r]=in[r*cols+c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
galileo_e1b_telemetry_decoder_cc::galileo_e1b_telemetry_decoder_cc(
|
galileo_e1b_telemetry_decoder_cc::galileo_e1b_telemetry_decoder_cc(
|
||||||
Gnss_Satellite satellite,
|
Gnss_Satellite satellite,
|
||||||
long if_freq,
|
long if_freq,
|
||||||
@ -120,19 +175,6 @@ galileo_e1b_telemetry_decoder_cc::galileo_e1b_telemetry_decoder_cc(
|
|||||||
d_TOW_at_current_symbol = 0;
|
d_TOW_at_current_symbol = 0;
|
||||||
flag_TOW_set = false;
|
flag_TOW_set = false;
|
||||||
|
|
||||||
// set up de-interleaver table
|
|
||||||
// std::vector<int> positions;
|
|
||||||
// for (int rows=0;rows<GALILEO_INAV_INTERLEAVER_ROWS;rows++)
|
|
||||||
// {
|
|
||||||
// for (int cols=0;cols<GALILEO_INAV_INTERLEAVER_COLS;cols++)
|
|
||||||
// {
|
|
||||||
// positions.push_back(rows*GALILEO_INAV_INTERLEAVER_ROWS+cols);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// d_interleaver= new gr::trellis::interleaver();
|
|
||||||
|
|
||||||
// set up trellis decoder
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -174,10 +216,8 @@ int galileo_e1b_telemetry_decoder_cc::general_work (int noutput_items, gr_vector
|
|||||||
if (abs(corr_value) >= d_symbols_per_preamble)
|
if (abs(corr_value) >= d_symbols_per_preamble)
|
||||||
{
|
{
|
||||||
//std::cout << "Positive preamble correlation for Galileo SAT " << this->d_satellite << std::endl;
|
//std::cout << "Positive preamble correlation for Galileo SAT " << this->d_satellite << std::endl;
|
||||||
//TODO: Rewrite with state machine
|
|
||||||
if (d_stat == 0)
|
if (d_stat == 0)
|
||||||
{
|
{
|
||||||
//d_GPS_FSM.Event_gps_word_preamble();
|
|
||||||
d_preamble_index = d_sample_counter;//record the preamble sample stamp
|
d_preamble_index = d_sample_counter;//record the preamble sample stamp
|
||||||
std::cout << "Preamble detection for Galileo SAT " << this->d_satellite << std::endl;
|
std::cout << "Preamble detection for Galileo SAT " << this->d_satellite << std::endl;
|
||||||
d_stat = 1; // enter into frame pre-detection status
|
d_stat = 1; // enter into frame pre-detection status
|
||||||
@ -188,14 +228,88 @@ int galileo_e1b_telemetry_decoder_cc::general_work (int noutput_items, gr_vector
|
|||||||
//std::cout << "preamble_diff="<< preamble_diff <<" for Galileo SAT " << this->d_satellite << std::endl;
|
//std::cout << "preamble_diff="<< preamble_diff <<" for Galileo SAT " << this->d_satellite << std::endl;
|
||||||
if (abs(preamble_diff - GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) < 1)
|
if (abs(preamble_diff - GALILEO_INAV_PREAMBLE_PERIOD_SYMBOLS) < 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//std::cout<<"d_sample_counter="<<d_sample_counter<<std::endl;
|
||||||
|
//std::cout<<"corr_value="<<corr_value<<std::endl;
|
||||||
// NEW Galileo page part is received
|
// NEW Galileo page part is received
|
||||||
|
// 0. fetch the symbols into an array
|
||||||
|
int frame_length=GALILEO_INAV_PAGE_PART_SYMBOLS-d_symbols_per_preamble;
|
||||||
|
double page_part_symbols[frame_length];
|
||||||
|
double page_part_symbols_deint[frame_length];
|
||||||
|
|
||||||
|
for (int i=0;i<frame_length;i++)
|
||||||
|
{
|
||||||
|
page_part_symbols[i]=in[0][i+d_symbols_per_preamble].Prompt_I; // because last symbol of the preamble is just received now!
|
||||||
|
}
|
||||||
|
|
||||||
// 1. De-interleave
|
// 1. De-interleave
|
||||||
|
deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS,GALILEO_INAV_INTERLEAVER_COLS,page_part_symbols, page_part_symbols_deint);
|
||||||
|
|
||||||
// 2. Viterbi decoder
|
// 2. Viterbi decoder
|
||||||
|
// 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder)
|
||||||
|
// 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180º
|
||||||
|
for (int i=0;i<frame_length;i++)
|
||||||
|
{
|
||||||
|
if (corr_value<0)
|
||||||
|
{
|
||||||
|
page_part_symbols_deint[i]=-page_part_symbols_deint[i];
|
||||||
|
}
|
||||||
|
if (i%2==0)
|
||||||
|
{
|
||||||
|
page_part_symbols_deint[i]=-page_part_symbols_deint[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int page_part_bits[frame_length/2];
|
||||||
|
viterbi_decoder(page_part_symbols_deint, page_part_bits);
|
||||||
|
|
||||||
// 3. Call the Galileo page decoder
|
// 3. Call the Galileo page decoder
|
||||||
|
|
||||||
//d_GPS_FSM.Event_gps_word_preamble();
|
// std::cout<<"frame_symbols=[";
|
||||||
|
// for (int i=0;i<frame_length;i++)
|
||||||
|
// {
|
||||||
|
// if (page_part_symbols[i]>0)
|
||||||
|
// {
|
||||||
|
// std::cout<<",1";
|
||||||
|
// }else{
|
||||||
|
// std::cout<<",0";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// std::cout<<"]"<<std::endl;
|
||||||
|
// std::cout<<"frame_symbols_deint=[";
|
||||||
|
// for (int i=0;i<frame_length;i++)
|
||||||
|
// {
|
||||||
|
// if (page_part_symbols_deint[i]>0)
|
||||||
|
// {
|
||||||
|
// std::cout<<",1";
|
||||||
|
// }else{
|
||||||
|
// std::cout<<",0";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// std::cout<<"]"<<std::endl;
|
||||||
|
//
|
||||||
|
// std::cout<<"frame_bits=[";
|
||||||
|
// for (int i=0;i<frame_length/2;i++)
|
||||||
|
// {
|
||||||
|
// if (page_part_bits[i]>0)
|
||||||
|
// {
|
||||||
|
// std::cout<<",1";
|
||||||
|
// }else{
|
||||||
|
// std::cout<<",0";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// std::cout<<"]"<<std::endl;
|
||||||
|
|
||||||
|
if (page_part_bits[0]==1)
|
||||||
|
{
|
||||||
|
std::cout<<"Page Odd"<<std::endl;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
std::cout<<"Page Even"<<std::endl;
|
||||||
|
}
|
||||||
|
//ToDo: Call here the frame decoder
|
||||||
|
|
||||||
|
|
||||||
d_flag_preamble = true;
|
d_flag_preamble = true;
|
||||||
d_preamble_index = d_sample_counter; //record the preamble sample stamp (t_P)
|
d_preamble_index = d_sample_counter; //record the preamble sample stamp (t_P)
|
||||||
d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs;// - d_preamble_duration_seconds; //record the PRN start sample index associated to the preamble
|
d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs;// - d_preamble_duration_seconds; //record the PRN start sample index associated to the preamble
|
||||||
|
@ -89,6 +89,10 @@ private:
|
|||||||
galileo_e1b_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in, unsigned
|
galileo_e1b_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in, unsigned
|
||||||
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump);
|
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump);
|
||||||
|
|
||||||
|
void viterbi_decoder(double *page_part_symbols, int *page_part_bits);
|
||||||
|
|
||||||
|
void deinterleaver(int rows, int cols, double *in, double *out);
|
||||||
|
|
||||||
unsigned short int d_preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS];
|
unsigned short int d_preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS];
|
||||||
|
|
||||||
signed int *d_preambles_symbols;
|
signed int *d_preambles_symbols;
|
||||||
|
637
src/algorithms/telemetry_decoder/libs/convolutional.h
Normal file
637
src/algorithms/telemetry_decoder/libs/convolutional.h
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
/* File convolutional.h
|
||||||
|
|
||||||
|
Description: General functions used to implement convolutional encoding.
|
||||||
|
|
||||||
|
Copyright (C) 2006-2008, Matthew C. Valenti
|
||||||
|
|
||||||
|
Last updated on May 22, 2008
|
||||||
|
|
||||||
|
The functions in this file are part of the Iterative Solutions
|
||||||
|
Coded Modulation Library. The Iterative Solutions Coded Modulation
|
||||||
|
Library is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published
|
||||||
|
by the Free Software Foundation; either version 2.1 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* define constants used throughout the library */
|
||||||
|
#define MAXLOG 1e7 /* Define infinity */
|
||||||
|
|
||||||
|
/* function itob()
|
||||||
|
|
||||||
|
Description: Converts an integer symbol into a vector of bits
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
binvec_p: The binary vector
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
symbol: The integer-valued symbol
|
||||||
|
length: The length of the binary vector
|
||||||
|
|
||||||
|
This function is used by conv_encode() */
|
||||||
|
|
||||||
|
void itob(
|
||||||
|
int binvec_p[],
|
||||||
|
int symbol,
|
||||||
|
int length )
|
||||||
|
{
|
||||||
|
int counter;
|
||||||
|
|
||||||
|
/* Go through each bit in the vector */
|
||||||
|
for (counter=0;counter<length;counter++) {
|
||||||
|
binvec_p[length-counter-1] = (symbol&1);
|
||||||
|
symbol = symbol>>1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function parity_counter()
|
||||||
|
|
||||||
|
Description: Determines if a symbol has odd (1) or even (0) parity
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
(returned int): The symbol's parity = 1 for odd and 0 for even
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
symbol: The integer-valued symbol
|
||||||
|
length: The highest bit position in the symbol
|
||||||
|
|
||||||
|
This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail() */
|
||||||
|
|
||||||
|
int parity_counter( int symbol, int length )
|
||||||
|
{
|
||||||
|
int counter;
|
||||||
|
int temp_parity = 0;
|
||||||
|
|
||||||
|
for (counter=0;counter<length;counter++) {
|
||||||
|
temp_parity = temp_parity^(symbol&1);
|
||||||
|
symbol = symbol>>1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( temp_parity );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Function nsc_enc_bit()
|
||||||
|
|
||||||
|
Description: 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.
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
input The input data bit (i.e. a 0 or 1).
|
||||||
|
state_in The starting state of the encoder (an int from 0 to 2^m-1).
|
||||||
|
g[] An n-element vector containing the code generators in binary form.
|
||||||
|
KK The constraint length of the convolutional code.
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
output_p[] An n-element vector containing the encoded bits.
|
||||||
|
state_out_p[] An integer containing the final state of the encoder
|
||||||
|
(i.e. the state after encoding this bit)
|
||||||
|
|
||||||
|
This function is used by rsc_encode(), nsc_transit(), rsc_transit(), and nsc_transit() */
|
||||||
|
|
||||||
|
static int nsc_enc_bit(
|
||||||
|
int state_out_p[],
|
||||||
|
int input,
|
||||||
|
int state_in,
|
||||||
|
int g[],
|
||||||
|
int KK,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
/* declare variables */
|
||||||
|
int state, i;
|
||||||
|
int out = 0;
|
||||||
|
|
||||||
|
/* create a word made up of state and new input */
|
||||||
|
state = (input<<(KK-1))^state_in;
|
||||||
|
|
||||||
|
/* AND the word with the generators */
|
||||||
|
for (i=0;i<nn;i++)
|
||||||
|
{
|
||||||
|
/* update output symbol */
|
||||||
|
out = (out<<1) + parity_counter( state&g[i], KK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift the state to make the new state */
|
||||||
|
state_out_p[0] = state>>1;
|
||||||
|
return(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* like nsc_enc_bit() but for a RSC code */
|
||||||
|
static int rsc_enc_bit(
|
||||||
|
int state_out_p[],
|
||||||
|
int input,
|
||||||
|
int state_in,
|
||||||
|
int g[],
|
||||||
|
int KK,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
/* declare variables */
|
||||||
|
int state, i, out, a_k;
|
||||||
|
|
||||||
|
/* systematic output */
|
||||||
|
out = input;
|
||||||
|
|
||||||
|
/* determine feedback bit */
|
||||||
|
a_k = input^parity_counter( g[0]&state_in, KK );
|
||||||
|
|
||||||
|
/* create a word made up of state and feedback bit */
|
||||||
|
state = (a_k<<(KK-1))^state_in;
|
||||||
|
|
||||||
|
/* AND the word with the generators */
|
||||||
|
for (i=1;i<nn;i++)
|
||||||
|
{
|
||||||
|
/* update output symbol */
|
||||||
|
out = (out<<1) + parity_counter( state&g[i], KK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift the state to make the new state */
|
||||||
|
state_out_p[0] = state>>1;
|
||||||
|
return(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function that creates the transit and output vectors */
|
||||||
|
static void nsc_transit(
|
||||||
|
int output_p[],
|
||||||
|
int trans_p[],
|
||||||
|
int input,
|
||||||
|
int g[],
|
||||||
|
int KK,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
int nextstate[1];
|
||||||
|
int state, states;
|
||||||
|
states = (1<<(KK-1)); /* The number of states: 2^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, g, KK, nn );
|
||||||
|
trans_p[state] = nextstate[0];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function rsc_transit()
|
||||||
|
|
||||||
|
Description: Calculates the "transition matrix" for the trellis.
|
||||||
|
This information tells the decoder what the next state and output bits
|
||||||
|
will be given the current state and input bit.
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
input Either 0 or 1 --- the input data bit.
|
||||||
|
g[] A two element vector containing the code generators.
|
||||||
|
KK The constraint length of the convolutional code.
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
output_p[] A vector of length max_states = 2^(KK-1) containing
|
||||||
|
the output symbols.
|
||||||
|
trans_p[] A vector of length max_states that tells the decoder
|
||||||
|
what the next state will be given the input and current state.
|
||||||
|
|
||||||
|
This function is used by turbo_decode() */
|
||||||
|
|
||||||
|
static void rsc_transit(
|
||||||
|
int output_p[],
|
||||||
|
int trans_p[],
|
||||||
|
int input,
|
||||||
|
int g[],
|
||||||
|
int KK,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
int nextstate[1];
|
||||||
|
int state, states;
|
||||||
|
|
||||||
|
states = 1 << (KK-1); /* The number of states: 2^mm */
|
||||||
|
|
||||||
|
/* Determine the output and next state for each possible starting state */
|
||||||
|
for(state=0;state<states;state++) {
|
||||||
|
output_p[state] = rsc_enc_bit( nextstate, input, state, g, KK, nn );
|
||||||
|
trans_p[state] = nextstate[0];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine the tail for a RSC code */
|
||||||
|
static void rsc_tail(
|
||||||
|
int tail_p[],
|
||||||
|
int g[],
|
||||||
|
int max_states,
|
||||||
|
int mm )
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
|
||||||
|
/* Determine the tail for each state */
|
||||||
|
for(state=0;state<max_states;state++) {
|
||||||
|
/* determine feedback word */
|
||||||
|
tail_p[state] = parity_counter( g[0]&state, mm );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform convolutional encoding */
|
||||||
|
static void conv_encode(
|
||||||
|
int output_p[],
|
||||||
|
int input[],
|
||||||
|
int out0[],
|
||||||
|
int state0[],
|
||||||
|
int out1[],
|
||||||
|
int state1[],
|
||||||
|
int tail[],
|
||||||
|
int KK,
|
||||||
|
int LL,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
int i, j, outsym;
|
||||||
|
int *bin_vec;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
/* Negative value in "tail" is a flag that this is
|
||||||
|
a tail-biting NSC code. Determine initial state */
|
||||||
|
|
||||||
|
if ( tail[0] < 0 ) {
|
||||||
|
for (i=LL-KK+1;i<LL;i++) {
|
||||||
|
if (input[i]) {
|
||||||
|
/* Determine next state */
|
||||||
|
state = state1[state];
|
||||||
|
} else {
|
||||||
|
/* Determine next state */
|
||||||
|
state = state0[state];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bin_vec = (int*)calloc( nn, sizeof(int) );
|
||||||
|
|
||||||
|
/* encode data bits one bit at a time */
|
||||||
|
for (i=0;i<LL;i++) {
|
||||||
|
if (input[i]) {
|
||||||
|
/* Input is a one */
|
||||||
|
outsym = out1[state]; /* The output symbol */
|
||||||
|
|
||||||
|
/* Determine next state */
|
||||||
|
state = state1[state];
|
||||||
|
} else {
|
||||||
|
/* Input is a zero */
|
||||||
|
outsym = out0[state]; /* The output symbol */
|
||||||
|
|
||||||
|
/* Determine next state */
|
||||||
|
state = state0[state];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert symbol to a binary vector */
|
||||||
|
itob( bin_vec, outsym, nn );
|
||||||
|
|
||||||
|
/* Assign to output */
|
||||||
|
for (j=0;j<nn;j++)
|
||||||
|
output_p[nn*i+j] = bin_vec[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode tail if needed */
|
||||||
|
if (tail[0] >= 0) {
|
||||||
|
for (i=LL;i<LL+KK-1;i++) {
|
||||||
|
if (tail[state]) {
|
||||||
|
/* Input is a one */
|
||||||
|
outsym = out1[state]; /* The output symbol */
|
||||||
|
|
||||||
|
/* Determine next state */
|
||||||
|
state = state1[state];
|
||||||
|
} else {
|
||||||
|
/* Input is a zero */
|
||||||
|
outsym = out0[state]; /* The output symbol */
|
||||||
|
|
||||||
|
/* Determine next state */
|
||||||
|
state = state0[state];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert symbol to a binary vector */
|
||||||
|
itob( bin_vec, outsym, nn );
|
||||||
|
|
||||||
|
/* Assign to output */
|
||||||
|
for (j=0;j<nn;j++)
|
||||||
|
output_p[nn*i+j] = bin_vec[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bin_vec);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* function Gamma()
|
||||||
|
|
||||||
|
Description: Computes the branch metric used for decoding.
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
(returned float) The metric between the hypothetical symbol and the recevieved vector
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
rec_array The received vector, of length nn
|
||||||
|
symbol The hypothetical symbol
|
||||||
|
nn The length of the received vector
|
||||||
|
|
||||||
|
This function is used by siso() */
|
||||||
|
|
||||||
|
|
||||||
|
static float Gamma(float rec_array[],
|
||||||
|
int symbol,
|
||||||
|
int nn )
|
||||||
|
{
|
||||||
|
float rm = 0;
|
||||||
|
int i;
|
||||||
|
int mask;
|
||||||
|
|
||||||
|
mask = 1;
|
||||||
|
for (i=0;i<nn;i++) {
|
||||||
|
if (symbol&mask)
|
||||||
|
rm += rec_array[nn-i-1];
|
||||||
|
mask = mask<<1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(rm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Function Viterbi()
|
||||||
|
|
||||||
|
Description: Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code.
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
out0[] The output bits for each state if input is a 0 (generated by rsc_transit).
|
||||||
|
state0[] The next state if input is a 0 (generated by rsc_transit).
|
||||||
|
out1[] The output bits for each state if input is a 1 (generated by rsc_transit).
|
||||||
|
state1[] The next state if input is a 1 (generated by rsc_transit).
|
||||||
|
r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2).
|
||||||
|
KK The constraint length of the convolutional code.
|
||||||
|
LL The number of data bits.
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
output_u_int[] Hard decisions on the data bits
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void Viterbi(
|
||||||
|
int output_u_int[],
|
||||||
|
int out0[],
|
||||||
|
int state0[],
|
||||||
|
int out1[],
|
||||||
|
int state1[],
|
||||||
|
double input_c[],
|
||||||
|
int KK,
|
||||||
|
int nn,
|
||||||
|
int LL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, t, state, mm, states;
|
||||||
|
int number_symbols;
|
||||||
|
float metric;
|
||||||
|
float *prev_section, *next_section;
|
||||||
|
int *prev_bit;
|
||||||
|
int *prev_state;
|
||||||
|
float *metric_c; /* Set of all possible branch metrics */
|
||||||
|
float *rec_array; /* Received values for one trellis section */
|
||||||
|
float max_val;
|
||||||
|
|
||||||
|
/* some derived constants */
|
||||||
|
mm = KK-1;
|
||||||
|
states = 1 << mm; /* 2^mm */
|
||||||
|
number_symbols = 1 << nn; /* 2^nn */
|
||||||
|
|
||||||
|
/* dynamically allocate memory */
|
||||||
|
prev_section = (float*)calloc( states, sizeof(float) );
|
||||||
|
next_section = (float*)calloc( states, sizeof(float) );
|
||||||
|
prev_bit = (int*)calloc( states*(LL+mm), sizeof(int) );
|
||||||
|
prev_state = (int*)calloc( states*(LL+mm), sizeof(int) );
|
||||||
|
rec_array = (float*)calloc( nn, sizeof(float) );
|
||||||
|
metric_c = (float*)calloc( number_symbols, sizeof(float) );
|
||||||
|
|
||||||
|
/* initialize trellis */
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
prev_section[state] = -MAXLOG;
|
||||||
|
next_section[state] = -MAXLOG;
|
||||||
|
}
|
||||||
|
prev_section[0] = 0; /* start in all-zeros state */
|
||||||
|
|
||||||
|
/* go through trellis */
|
||||||
|
for (t=0;t<LL+mm;t++) {
|
||||||
|
for (i=0;i<nn;i++)
|
||||||
|
rec_array[i] = (float)input_c[nn*t+i];
|
||||||
|
|
||||||
|
/* precompute all possible branch metrics */
|
||||||
|
for (i=0;i<number_symbols;i++)
|
||||||
|
metric_c[i] = Gamma( rec_array, i, nn );
|
||||||
|
|
||||||
|
/* step through all states */
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
|
||||||
|
/* hypothesis: info bit is a zero */
|
||||||
|
metric = prev_section[state] + metric_c[ out0[ state ] ];
|
||||||
|
|
||||||
|
/* store new metric if more than metric in storage */
|
||||||
|
if ( metric > next_section[state0[state]] ) {
|
||||||
|
next_section[state0[state]] = metric;
|
||||||
|
prev_state[t*states+state0[state]] = state;
|
||||||
|
prev_bit[t*states+state0[state]] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hypothesis: info bit is a one */
|
||||||
|
metric = prev_section[state] + metric_c[ out1[ state ] ];
|
||||||
|
|
||||||
|
/* store new metric if more than metric in storage */
|
||||||
|
if ( metric > next_section[state1[state]] ) {
|
||||||
|
next_section[state1[state]] = metric;
|
||||||
|
prev_state[t*states+state1[state]] = state;
|
||||||
|
prev_bit[t*states+state1[state]] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normalize */
|
||||||
|
max_val = 0;
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
if (next_section[state]>max_val){
|
||||||
|
max_val = next_section[state];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
prev_section[state] = next_section[state] - max_val;
|
||||||
|
next_section[state] = -MAXLOG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* trace-back operation */
|
||||||
|
state = 0;
|
||||||
|
|
||||||
|
/* tail, no need to output */
|
||||||
|
for (t=LL+mm-1; t>=LL; t--) {
|
||||||
|
state = prev_state[t*states+state];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (t=LL-1; t>=0; t--) {
|
||||||
|
output_u_int[t] = prev_bit[t*states+state];
|
||||||
|
state = prev_state[t*states+state];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the dynamically allocated memory */
|
||||||
|
free(prev_section);
|
||||||
|
free(next_section);
|
||||||
|
free(prev_bit);
|
||||||
|
free(prev_state);
|
||||||
|
free(rec_array);
|
||||||
|
free(metric_c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function ViterbiTb()
|
||||||
|
|
||||||
|
Description: Uses the Viterbi algorithm to perform hard-decision decoding of a tail-biting convolutional code.
|
||||||
|
|
||||||
|
Input parameters:
|
||||||
|
out0[] The output bits for each state if input is a 0 (generated by rsc_transit).
|
||||||
|
state0[] The next state if input is a 0 (generated by rsc_transit).
|
||||||
|
out1[] The output bits for each state if input is a 1 (generated by rsc_transit).
|
||||||
|
state1[] The next state if input is a 1 (generated by rsc_transit).
|
||||||
|
r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2).
|
||||||
|
KK The constraint length of the convolutional code.
|
||||||
|
LL The number of data bits.
|
||||||
|
depth head and tail decoding length [Ref. W. Sung, Electronics Letters, vol. 36, no. 7]
|
||||||
|
|
||||||
|
Output parameters:
|
||||||
|
output_u_int[] Hard decisions on the data bits
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void ViterbiTb(
|
||||||
|
int output_u_int[],
|
||||||
|
int out0[],
|
||||||
|
int state0[],
|
||||||
|
int out1[],
|
||||||
|
int state1[],
|
||||||
|
double input_c[],
|
||||||
|
int KK,
|
||||||
|
int nn,
|
||||||
|
int LL,
|
||||||
|
int depth
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, t, state, mm, states, max_state;
|
||||||
|
int number_symbols, starting_bit;
|
||||||
|
float metric;
|
||||||
|
float *prev_section, *next_section;
|
||||||
|
int *prev_bit;
|
||||||
|
int *prev_state;
|
||||||
|
float *metric_c; /* Set of all possible branch metrics */
|
||||||
|
float *rec_array; /* Received values for one trellis section */
|
||||||
|
float max_val;
|
||||||
|
|
||||||
|
/* some derived constants */
|
||||||
|
mm = KK-1;
|
||||||
|
states = 1 << mm; /* 2^mm */
|
||||||
|
number_symbols = 1 << nn; /* 2^nn */
|
||||||
|
|
||||||
|
/* dynamically allocate memory */
|
||||||
|
prev_section = (float*)calloc( states, sizeof(float) );
|
||||||
|
next_section = (float*)calloc( states, sizeof(float) );
|
||||||
|
prev_bit = (int*)calloc( states*(LL+depth), sizeof(int) );
|
||||||
|
prev_state = (int*)calloc( states*(LL+depth), sizeof(int) );
|
||||||
|
rec_array = (float*)calloc( nn, sizeof(float) );
|
||||||
|
metric_c = (float*)calloc( number_symbols, sizeof(float) );
|
||||||
|
|
||||||
|
/* initialize trellis */
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
prev_section[state] = 0; /* equally likely starting state */
|
||||||
|
next_section[state] = -MAXLOG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go through trellis */
|
||||||
|
for (t=-depth;t<LL+depth;t++) {
|
||||||
|
/* determine the corresponding data bits */
|
||||||
|
starting_bit = nn*(t%LL);
|
||||||
|
if (starting_bit < 0 )
|
||||||
|
starting_bit = nn*LL + starting_bit;
|
||||||
|
|
||||||
|
/* printf( "start at %d\n", starting_bit ); */
|
||||||
|
for (i=0;i<nn;i++) {
|
||||||
|
rec_array[i] = (float)input_c[starting_bit+i];
|
||||||
|
/* printf( "%1f\n", rec_array[i] ); */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* precompute all possible branch metrics */
|
||||||
|
for (i=0;i<number_symbols;i++)
|
||||||
|
metric_c[i] = Gamma( rec_array, i, nn );
|
||||||
|
|
||||||
|
/* step through all states */
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
|
||||||
|
/* hypothesis: info bit is a zero */
|
||||||
|
metric = prev_section[state] + metric_c[ out0[ state ] ];
|
||||||
|
|
||||||
|
/* store new metric if more than metric in storage */
|
||||||
|
if ( metric > next_section[state0[state]] ) {
|
||||||
|
next_section[state0[state]] = metric;
|
||||||
|
if (t>=0) {
|
||||||
|
prev_state[t*states+state0[state]] = state;
|
||||||
|
prev_bit[t*states+state0[state]] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hypothesis: info bit is a one */
|
||||||
|
metric = prev_section[state] + metric_c[ out1[ state ] ];
|
||||||
|
|
||||||
|
/* store new metric if more than metric in storage */
|
||||||
|
if ( metric > next_section[state1[state]] ) {
|
||||||
|
next_section[state1[state]] = metric;
|
||||||
|
if (t>=0) {
|
||||||
|
prev_state[t*states+state1[state]] = state;
|
||||||
|
prev_bit[t*states+state1[state]] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normalize */
|
||||||
|
max_val = 0;
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
if (next_section[state]>max_val){
|
||||||
|
max_val = next_section[state];
|
||||||
|
max_state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (state=0;state<states;state++) {
|
||||||
|
prev_section[state] = next_section[state] - max_val;
|
||||||
|
next_section[state] = -MAXLOG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* trace-back operation */
|
||||||
|
state = max_state;
|
||||||
|
|
||||||
|
/* tail, no need to output */
|
||||||
|
for (t=LL+depth-1; t>=LL; t--) {
|
||||||
|
state = prev_state[t*states+state];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (t=LL-1; t>=0; t--) {
|
||||||
|
output_u_int[t] = prev_bit[t*states+state];
|
||||||
|
state = prev_state[t*states+state];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the dynamically allocated memory */
|
||||||
|
free(prev_section);
|
||||||
|
free(next_section);
|
||||||
|
free(prev_bit);
|
||||||
|
free(prev_state);
|
||||||
|
free(rec_array);
|
||||||
|
free(metric_c);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user