GNSS-SDR  0.0.14
An Open Source GNSS Software Defined Receiver
convolutional.h
Go to the documentation of this file.
1 /*!
2  * \file convolutional.h
3  * \brief General functions used to implement convolutional encoding.
4  * \author Matthew C. Valenti, 2006-2008.
5  * \author C. Fernandez-Prades, 2019.
6  *
7  * -----------------------------------------------------------------------------
8  *
9  * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
10  * This file is part of GNSS-SDR.
11  *
12  * Copyright (C) 2006-2008 Matthew C. Valenti
13  * Copyright (C) 2019 C. Fernandez-Prades
14  * SPDX-License-Identifier: GPL-3.0-or-later
15  *
16  * This file is a derived work of the original file, which had this note:
17  *
18  * The functions in this file are part of the Iterative Solutions
19  * Coded Modulation Library. The Iterative Solutions Coded Modulation
20  * Library is free software; you can redistribute it and/or modify it
21  * under the terms of the GNU Lesser General Public License as published
22  * by the Free Software Foundation; either version 2.1 of the License,
23  * or (at your option) any later version.
24  *
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33  */
34 
35 #ifndef GNSS_SDR_CONVOLUTIONAL_H
36 #define GNSS_SDR_CONVOLUTIONAL_H
37 
38 #include <volk_gnsssdr/volk_gnsssdr.h>
39 #include <vector>
40 
41 /** \addtogroup Telemetry_Decoder
42  * \{ */
43 /** \addtogroup Telemetry_Decoder_libs
44  * Utilities for the decoding of GNSS navigation messages.
45  * \{ */
46 
47 
48 /* define constants used throughout the library */
49 const float MAXLOG = 1e7; /* Define infinity */
50 
51 
52 /*!
53  * \brief Determines if a symbol has odd (1) or even (0) parity
54  * Output parameters:
55  * \return (returned int): The symbol's parity = 1 for odd and 0 for even
56  *
57  * \param[in] symbol The integer-valued symbol
58  * \param[in] length The highest bit position in the symbol
59  *
60  * This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail()
61  */
62 inline int parity_counter(int symbol, int length)
63 {
64  int counter;
65  int temp_parity = 0;
66 
67  for (counter = 0; counter < length; counter++)
68  {
69  temp_parity = temp_parity ^ (symbol & 1);
70  symbol = symbol >> 1;
71  }
72  return (temp_parity);
73 }
74 
75 
76 /*!
77  * \brief Convolutionally encodes a single bit using a rate 1/n encoder.
78  * Takes in one input bit at a time, and produces a n-bit output.
79  *
80  * \param[in] input The input data bit (i.e. a 0 or 1).
81  * \param[in] state_in The starting state of the encoder (an int from 0 to 2^m-1).
82  * \param[in] g[] An n-element vector containing the code generators in binary form.
83  * \param[in] KK The constraint length of the convolutional code.
84  * \param[out] output_p[] An n-element vector containing the encoded bits.
85  * \param[out] state_out_p[] An integer containing the final state of the encoder
86  * (i.e. the state after encoding this bit)
87  *
88  * This function is used by nsc_transit()
89  */
90 inline int nsc_enc_bit(int state_out_p[],
91  int input,
92  int state_in,
93  const int g[],
94  int KK,
95  int nn)
96 {
97  /* declare variables */
98  int state, i;
99  int out_ = 0;
100 
101  /* create a word made up of state and new input */
102  state = (input << (KK - 1)) ^ state_in;
103 
104  /* AND the word with the generators */
105  for (i = 0; i < nn; i++)
106  {
107  /* update output symbol */
108  out_ = (out_ << 1) + parity_counter(state & g[i], KK);
109  }
110 
111  /* shift the state to make the new state */
112  state_out_p[0] = state >> 1;
113  return (out_);
114 }
115 
116 
117 /*!
118  * \brief Function that creates the transit and output vectors
119  */
120 inline void nsc_transit(int output_p[],
121  int trans_p[],
122  int input,
123  int g[],
124  int KK,
125  int nn)
126 {
127  int nextstate[1];
128  int state, states;
129  states = (1 << (KK - 1)); /* The number of states: 2^mm */
130 
131  /* Determine the output and next state for each possible starting state */
132  for (state = 0; state < states; state++)
133  {
134  output_p[state] = nsc_enc_bit(nextstate, input, state, g, KK, nn);
135  trans_p[state] = nextstate[0];
136  }
137  return;
138 }
139 
140 
141 /*!
142  * \brief Computes the branch metric used for decoding.
143  * \return (returned float) The metric between the hypothetical symbol and the received vector
144  * \param[in] rec_array The received vector, of length nn
145  * \param[in] symbol The hypothetical symbol
146  * \param[in] nn The length of the received vector
147  *
148  */
149 inline float Gamma(const float rec_array[],
150  int symbol,
151  int nn)
152 {
153  float rm = 0;
154  int i;
155  int mask = 1;
156 
157  for (i = 0; i < nn; i++)
158  {
159  if (symbol & mask)
160  {
161  rm += rec_array[nn - i - 1];
162  }
163  mask = mask << 1;
164  }
165  return (rm);
166 }
167 
168 
169 /*!
170  * \brief Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code.
171  * \param[in] out0[] The output bits for each state if input is a 0.
172  * \param[in] state0[] The next state if input is a 0.
173  * \param[in] out1[] The output bits for each state if input is a 1.
174  * \param[in] state1[] The next state if input is a 1.
175  * \param[in] r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2).
176  * \param[in] KK The constraint length of the convolutional code.
177  * \param[in] LL The number of data bits.
178  * \param[out] output_u_int[] Hard decisions on the data bits
179  *
180  */
181 inline void Viterbi(int output_u_int[],
182  const int out0[],
183  const int state0[],
184  const int out1[],
185  const int state1[],
186  const float input_c[],
187  int KK,
188  int nn,
189  int LL)
190 {
191  int i, t, state, mm, states;
192  int number_symbols;
193  uint32_t max_index;
194  float metric;
195  float max_val;
196 
197  /* some derived constants */
198  mm = KK - 1;
199  states = 1 << mm; /* 2^mm */
200  number_symbols = 1 << nn; /* 2^nn */
201 
202  std::vector<float> prev_section(states, -MAXLOG);
203  std::vector<float> next_section(states, -MAXLOG);
204  std::vector<int> prev_bit(states * (LL + mm), 0);
205  std::vector<int> prev_state(states * (LL + mm), 0);
206  std::vector<float> rec_array(nn);
207  std::vector<float> metric_c(number_symbols);
208 
209  prev_section[0] = 0.0; /* start in all-zeros state */
210 
211  /* go through trellis */
212  for (t = 0; t < LL + mm; t++)
213  {
214  rec_array.assign(input_c + nn * t, input_c + nn * t + (nn - 1));
215 
216  /* precompute all possible branch metrics */
217  for (i = 0; i < number_symbols; i++)
218  {
219  metric_c[i] = Gamma(rec_array.data(), i, nn);
220  }
221 
222  /* step through all states */
223  for (state = 0; state < states; state++)
224  {
225  /* hypothesis: info bit is a zero */
226  metric = prev_section[state] + metric_c[out0[state]];
227 
228  /* store new metric if more than metric in storage */
229  if (metric > next_section[state0[state]])
230  {
231  next_section[state0[state]] = metric;
232  prev_state[t * states + state0[state]] = state;
233  prev_bit[t * states + state0[state]] = 0;
234  }
235 
236  /* hypothesis: info bit is a one */
237  metric = prev_section[state] + metric_c[out1[state]];
238 
239  /* store new metric if more than metric in storage */
240  if (metric > next_section[state1[state]])
241  {
242  next_section[state1[state]] = metric;
243  prev_state[t * states + state1[state]] = state;
244  prev_bit[t * states + state1[state]] = 1;
245  }
246  }
247 
248  /* normalize */
249  volk_gnsssdr_32f_index_max_32u(&max_index, next_section.data(), states);
250  max_val = next_section[max_index];
251 
252  for (state = 0; state < states; state++)
253  {
254  prev_section[state] = next_section[state] - max_val;
255  next_section[state] = -MAXLOG;
256  }
257  }
258 
259  /* trace-back operation */
260  state = 0;
261 
262  /* tail, no need to output */
263  for (t = LL + mm - 1; t >= LL; t--)
264  {
265  state = prev_state[t * states + state];
266  }
267 
268  for (t = LL - 1; t >= 0; t--)
269  {
270  output_u_int[t] = prev_bit[t * states + state];
271  state = prev_state[t * states + state];
272  }
273 }
274 
275 
276 /** \} */
277 /** \} */
278 #endif // GNSS_SDR_CONVOLUTIONAL_H
int parity_counter(int symbol, int length)
Determines if a symbol has odd (1) or even (0) parity Output parameters:
Definition: convolutional.h:62
float Gamma(const float rec_array[], int symbol, int nn)
Computes the branch metric used for decoding.
void Viterbi(int output_u_int[], const int out0[], const int state0[], const int out1[], const int state1[], const float input_c[], int KK, int nn, int LL)
Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code.
void nsc_transit(int output_p[], int trans_p[], int input, int g[], int KK, int nn)
Function that creates the transit and output vectors.
int nsc_enc_bit(int state_out_p[], int input, int state_in, const int g[], int KK, int nn)
Convolutionally encodes a single bit using a rate 1/n encoder. Takes in one input bit at a time...
Definition: convolutional.h:90