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