blob: bee95ba139783523257f504284c3c02cff03e06c [file] [log] [blame]
piotr437f5462014-02-04 17:57:25 +01001/* -*- c++ -*- */
2/*
3 * @file
piotrebd06232014-05-02 17:28:21 +02004 * @author Piotr Krysik <pkrysik@elka.pw.edu.pl>
piotr437f5462014-02-04 17:57:25 +01005 * @section LICENSE
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23/*
24 * viterbi_detector:
25 * This part does the detection of received sequnece.
26 * Employed algorithm is viterbi Maximum Likehood Sequence Estimation.
27 * At this moment it gives hard decisions on the output, but
28 * it was designed with soft decisions in mind.
29 *
30 * SYNTAX: void viterbi_detector(
31 * const gr_complex * input,
32 * unsigned int samples_num,
33 * gr_complex * rhh,
34 * unsigned int start_state,
35 * const unsigned int * stop_states,
36 * unsigned int stops_num,
37 * float * output)
38 *
39 * INPUT: input: Complex received signal afted matched filtering.
40 * samples_num: Number of samples in the input table.
41 * rhh: The autocorrelation of the estimated channel
42 * impulse response.
43 * start_state: Number of the start point. In GSM each burst
44 * starts with sequence of three bits (0,0,0) which
45 * indicates start point of the algorithm.
46 * stop_states: Table with numbers of possible stop states.
47 * stops_num: Number of possible stop states
48 *
49 *
50 * OUTPUT: output: Differentially decoded hard output of the algorithm:
51 * -1 for logical "0" and 1 for logical "1"
52 *
53 * SUB_FUNC: none
54 *
55 * TEST(S): Tested with real world normal burst.
56 */
57
58#include <gnuradio/gr_complex.h>
59#include <gsm_constants.h>
piotrebd06232014-05-02 17:28:21 +020060#include <cmath>
61
piotr437f5462014-02-04 17:57:25 +010062#define PATHS_NUM (1 << (CHAN_IMP_RESP_LENGTH-1))
63
64void viterbi_detector(const gr_complex * input, unsigned int samples_num, gr_complex * rhh, unsigned int start_state, const unsigned int * stop_states, unsigned int stops_num, float * output)
65{
66 float increment[8];
67 float path_metrics1[16];
68 float path_metrics2[16];
69 float * new_path_metrics;
70 float * old_path_metrics;
71 float * tmp;
72 float trans_table[BURST_SIZE][16];
73 float pm_candidate1, pm_candidate2;
74 bool real_imag;
75 float input_symbol_real, input_symbol_imag;
76 unsigned int i, sample_nr;
77
78/*
79* Setup first path metrics, so only state pointed by start_state is possible.
80* Start_state metric is equal to zero, the rest is written with some very low value,
81* which makes them practically impossible to occur.
82*/
83 for(i=0; i<PATHS_NUM; i++){
84 path_metrics1[i]=(-10e30);
85 }
86 path_metrics1[start_state]=0;
87
88/*
89* Compute Increment - a table of values which does not change for subsequent input samples.
90* Increment is table of reference levels for computation of branch metrics:
91* branch metric = (+/-)received_sample (+/-) reference_level
92*/
93 increment[0] = -rhh[1].imag() -rhh[2].real() -rhh[3].imag() +rhh[4].real();
94 increment[1] = rhh[1].imag() -rhh[2].real() -rhh[3].imag() +rhh[4].real();
95 increment[2] = -rhh[1].imag() +rhh[2].real() -rhh[3].imag() +rhh[4].real();
96 increment[3] = rhh[1].imag() +rhh[2].real() -rhh[3].imag() +rhh[4].real();
97 increment[4] = -rhh[1].imag() -rhh[2].real() +rhh[3].imag() +rhh[4].real();
98 increment[5] = rhh[1].imag() -rhh[2].real() +rhh[3].imag() +rhh[4].real();
99 increment[6] = -rhh[1].imag() +rhh[2].real() +rhh[3].imag() +rhh[4].real();
100 increment[7] = rhh[1].imag() +rhh[2].real() +rhh[3].imag() +rhh[4].real();
101
102
103/*
104* Computation of path metrics and decisions (Add-Compare-Select).
105* It's composed of two parts: one for odd input samples (imaginary numbers)
106* and one for even samples (real numbers).
107* Each part is composed of independent (parallelisable) statements like
108* this one:
109* pm_candidate1 = old_path_metrics[0] - input_symbol_real - increment[7];
110* pm_candidate2 = old_path_metrics[8] - input_symbol_real + increment[0];
111* if(pm_candidate1 > pm_candidate2){
112* new_path_metrics[0] = pm_candidate1;
113* trans_table[sample_nr][0] = -1.0;
114* }
115* else{
116* new_path_metrics[0] = pm_candidate2;
117* trans_table[sample_nr][0] = 1.0;
118* }
119* This is very good point for optimisations (SIMD or OpenMP) as it's most time
120* consuming part of this function.
121*/
122 sample_nr=0;
123 old_path_metrics=path_metrics1;
124 new_path_metrics=path_metrics2;
125 while(sample_nr<samples_num){
126 //Processing imag states
127 real_imag=1;
128 input_symbol_imag = input[sample_nr].imag();
129
piotrebd06232014-05-02 17:28:21 +0200130 pm_candidate1 = old_path_metrics[0] +input_symbol_imag -increment[2];
131 pm_candidate2 = old_path_metrics[8] +input_symbol_imag +increment[5];
piotr437f5462014-02-04 17:57:25 +0100132 if(pm_candidate1 > pm_candidate2){
133 new_path_metrics[0] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200134 trans_table[sample_nr][0] = -std::abs( +input_symbol_imag -increment[2]);
piotr437f5462014-02-04 17:57:25 +0100135 }
136 else{
137 new_path_metrics[0] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200138 trans_table[sample_nr][0] = std::abs( +input_symbol_imag +increment[5]);
piotr437f5462014-02-04 17:57:25 +0100139 }
140
piotrebd06232014-05-02 17:28:21 +0200141 pm_candidate1 = old_path_metrics[0] -input_symbol_imag +increment[2];
142 pm_candidate2 = old_path_metrics[8] -input_symbol_imag -increment[5];
piotr437f5462014-02-04 17:57:25 +0100143 if(pm_candidate1 > pm_candidate2){
144 new_path_metrics[1] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200145 trans_table[sample_nr][1] = -std::abs( -input_symbol_imag +increment[2]);
piotr437f5462014-02-04 17:57:25 +0100146 }
147 else{
148 new_path_metrics[1] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200149 trans_table[sample_nr][1] = std::abs( -input_symbol_imag -increment[5]);
piotr437f5462014-02-04 17:57:25 +0100150 }
151
piotrebd06232014-05-02 17:28:21 +0200152 pm_candidate1 = old_path_metrics[1] +input_symbol_imag -increment[3];
153 pm_candidate2 = old_path_metrics[9] +input_symbol_imag +increment[4];
piotr437f5462014-02-04 17:57:25 +0100154 if(pm_candidate1 > pm_candidate2){
155 new_path_metrics[2] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200156 trans_table[sample_nr][2] = -std::abs( +input_symbol_imag -increment[3]);
piotr437f5462014-02-04 17:57:25 +0100157 }
158 else{
159 new_path_metrics[2] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200160 trans_table[sample_nr][2] = std::abs( +input_symbol_imag +increment[4]);
piotr437f5462014-02-04 17:57:25 +0100161 }
162
piotrebd06232014-05-02 17:28:21 +0200163 pm_candidate1 = old_path_metrics[1] -input_symbol_imag +increment[3];
164 pm_candidate2 = old_path_metrics[9] -input_symbol_imag -increment[4];
piotr437f5462014-02-04 17:57:25 +0100165 if(pm_candidate1 > pm_candidate2){
166 new_path_metrics[3] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200167 trans_table[sample_nr][3] = -std::abs( -input_symbol_imag +increment[3]);
piotr437f5462014-02-04 17:57:25 +0100168 }
169 else{
170 new_path_metrics[3] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200171 trans_table[sample_nr][3] = std::abs( -input_symbol_imag -increment[4]);
piotr437f5462014-02-04 17:57:25 +0100172 }
173
piotrebd06232014-05-02 17:28:21 +0200174 pm_candidate1 = old_path_metrics[2] +input_symbol_imag -increment[0];
175 pm_candidate2 = old_path_metrics[10] +input_symbol_imag +increment[7];
piotr437f5462014-02-04 17:57:25 +0100176 if(pm_candidate1 > pm_candidate2){
177 new_path_metrics[4] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200178 trans_table[sample_nr][4] = -std::abs( +input_symbol_imag -increment[0]);
piotr437f5462014-02-04 17:57:25 +0100179 }
180 else{
181 new_path_metrics[4] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200182 trans_table[sample_nr][4] = std::abs( +input_symbol_imag +increment[7]);
piotr437f5462014-02-04 17:57:25 +0100183 }
184
piotrebd06232014-05-02 17:28:21 +0200185 pm_candidate1 = old_path_metrics[2] -input_symbol_imag +increment[0];
186 pm_candidate2 = old_path_metrics[10] -input_symbol_imag -increment[7];
piotr437f5462014-02-04 17:57:25 +0100187 if(pm_candidate1 > pm_candidate2){
188 new_path_metrics[5] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200189 trans_table[sample_nr][5] = -std::abs( -input_symbol_imag +increment[0]);
piotr437f5462014-02-04 17:57:25 +0100190 }
191 else{
192 new_path_metrics[5] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200193 trans_table[sample_nr][5] = std::abs( -input_symbol_imag -increment[7]);
piotr437f5462014-02-04 17:57:25 +0100194 }
195
piotrebd06232014-05-02 17:28:21 +0200196 pm_candidate1 = old_path_metrics[3] +input_symbol_imag -increment[1];
197 pm_candidate2 = old_path_metrics[11] +input_symbol_imag +increment[6];
piotr437f5462014-02-04 17:57:25 +0100198 if(pm_candidate1 > pm_candidate2){
199 new_path_metrics[6] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200200 trans_table[sample_nr][6] = -std::abs( +input_symbol_imag -increment[1]);
piotr437f5462014-02-04 17:57:25 +0100201 }
202 else{
203 new_path_metrics[6] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200204 trans_table[sample_nr][6] = std::abs( +input_symbol_imag +increment[6]);
piotr437f5462014-02-04 17:57:25 +0100205 }
206
piotrebd06232014-05-02 17:28:21 +0200207 pm_candidate1 = old_path_metrics[3] -input_symbol_imag +increment[1];
208 pm_candidate2 = old_path_metrics[11] -input_symbol_imag -increment[6];
piotr437f5462014-02-04 17:57:25 +0100209 if(pm_candidate1 > pm_candidate2){
210 new_path_metrics[7] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200211 trans_table[sample_nr][7] = -std::abs( -input_symbol_imag +increment[1]);
piotr437f5462014-02-04 17:57:25 +0100212 }
213 else{
214 new_path_metrics[7] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200215 trans_table[sample_nr][7] = std::abs( -input_symbol_imag -increment[6]);
piotr437f5462014-02-04 17:57:25 +0100216 }
217
piotrebd06232014-05-02 17:28:21 +0200218 pm_candidate1 = old_path_metrics[4] +input_symbol_imag -increment[6];
219 pm_candidate2 = old_path_metrics[12] +input_symbol_imag +increment[1];
piotr437f5462014-02-04 17:57:25 +0100220 if(pm_candidate1 > pm_candidate2){
221 new_path_metrics[8] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200222 trans_table[sample_nr][8] = -std::abs( +input_symbol_imag -increment[6]);
piotr437f5462014-02-04 17:57:25 +0100223 }
224 else{
225 new_path_metrics[8] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200226 trans_table[sample_nr][8] = std::abs( +input_symbol_imag +increment[1]);
piotr437f5462014-02-04 17:57:25 +0100227 }
228
piotrebd06232014-05-02 17:28:21 +0200229 pm_candidate1 = old_path_metrics[4] -input_symbol_imag +increment[6];
230 pm_candidate2 = old_path_metrics[12] -input_symbol_imag -increment[1];
piotr437f5462014-02-04 17:57:25 +0100231 if(pm_candidate1 > pm_candidate2){
232 new_path_metrics[9] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200233 trans_table[sample_nr][9] = -std::abs( -input_symbol_imag +increment[6]);
piotr437f5462014-02-04 17:57:25 +0100234 }
235 else{
236 new_path_metrics[9] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200237 trans_table[sample_nr][9] = std::abs( -input_symbol_imag -increment[1]);
piotr437f5462014-02-04 17:57:25 +0100238 }
239
piotrebd06232014-05-02 17:28:21 +0200240 pm_candidate1 = old_path_metrics[5] +input_symbol_imag -increment[7];
241 pm_candidate2 = old_path_metrics[13] +input_symbol_imag +increment[0];
piotr437f5462014-02-04 17:57:25 +0100242 if(pm_candidate1 > pm_candidate2){
243 new_path_metrics[10] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200244 trans_table[sample_nr][10] = -std::abs( +input_symbol_imag -increment[7]);
piotr437f5462014-02-04 17:57:25 +0100245 }
246 else{
247 new_path_metrics[10] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200248 trans_table[sample_nr][10] = std::abs( +input_symbol_imag +increment[0]);
piotr437f5462014-02-04 17:57:25 +0100249 }
250
piotrebd06232014-05-02 17:28:21 +0200251 pm_candidate1 = old_path_metrics[5] -input_symbol_imag +increment[7];
252 pm_candidate2 = old_path_metrics[13] -input_symbol_imag -increment[0];
piotr437f5462014-02-04 17:57:25 +0100253 if(pm_candidate1 > pm_candidate2){
254 new_path_metrics[11] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200255 trans_table[sample_nr][11] = -std::abs( -input_symbol_imag +increment[7]);
piotr437f5462014-02-04 17:57:25 +0100256 }
257 else{
258 new_path_metrics[11] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200259 trans_table[sample_nr][11] = std::abs( -input_symbol_imag -increment[0]);
piotr437f5462014-02-04 17:57:25 +0100260 }
261
piotrebd06232014-05-02 17:28:21 +0200262 pm_candidate1 = old_path_metrics[6] +input_symbol_imag -increment[4];
263 pm_candidate2 = old_path_metrics[14] +input_symbol_imag +increment[3];
piotr437f5462014-02-04 17:57:25 +0100264 if(pm_candidate1 > pm_candidate2){
265 new_path_metrics[12] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200266 trans_table[sample_nr][12] = -std::abs( +input_symbol_imag -increment[4]);
piotr437f5462014-02-04 17:57:25 +0100267 }
268 else{
269 new_path_metrics[12] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200270 trans_table[sample_nr][12] = std::abs( +input_symbol_imag +increment[3]);
piotr437f5462014-02-04 17:57:25 +0100271 }
272
piotrebd06232014-05-02 17:28:21 +0200273 pm_candidate1 = old_path_metrics[6] -input_symbol_imag +increment[4];
274 pm_candidate2 = old_path_metrics[14] -input_symbol_imag -increment[3];
piotr437f5462014-02-04 17:57:25 +0100275 if(pm_candidate1 > pm_candidate2){
276 new_path_metrics[13] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200277 trans_table[sample_nr][13] = -std::abs( -input_symbol_imag +increment[4]);
piotr437f5462014-02-04 17:57:25 +0100278 }
279 else{
280 new_path_metrics[13] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200281 trans_table[sample_nr][13] = std::abs( -input_symbol_imag -increment[3]);
piotr437f5462014-02-04 17:57:25 +0100282 }
283
piotrebd06232014-05-02 17:28:21 +0200284 pm_candidate1 = old_path_metrics[7] +input_symbol_imag -increment[5];
285 pm_candidate2 = old_path_metrics[15] +input_symbol_imag +increment[2];
piotr437f5462014-02-04 17:57:25 +0100286 if(pm_candidate1 > pm_candidate2){
287 new_path_metrics[14] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200288 trans_table[sample_nr][14] = -std::abs( +input_symbol_imag -increment[5]);
piotr437f5462014-02-04 17:57:25 +0100289 }
290 else{
291 new_path_metrics[14] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200292 trans_table[sample_nr][14] = std::abs( +input_symbol_imag +increment[2]);
piotr437f5462014-02-04 17:57:25 +0100293 }
294
piotrebd06232014-05-02 17:28:21 +0200295 pm_candidate1 = old_path_metrics[7] -input_symbol_imag +increment[5];
296 pm_candidate2 = old_path_metrics[15] -input_symbol_imag -increment[2];
piotr437f5462014-02-04 17:57:25 +0100297 if(pm_candidate1 > pm_candidate2){
298 new_path_metrics[15] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200299 trans_table[sample_nr][15] = -std::abs( -input_symbol_imag +increment[5]);
piotr437f5462014-02-04 17:57:25 +0100300 }
301 else{
302 new_path_metrics[15] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200303 trans_table[sample_nr][15] = std::abs( -input_symbol_imag -increment[2]);
piotr437f5462014-02-04 17:57:25 +0100304 }
305 tmp=old_path_metrics;
306 old_path_metrics=new_path_metrics;
307 new_path_metrics=tmp;
308
309 sample_nr++;
310 if(sample_nr==samples_num)
311 break;
312
313 //Processing real states
314 real_imag=0;
315 input_symbol_real = input[sample_nr].real();
316
piotrebd06232014-05-02 17:28:21 +0200317 pm_candidate1 = old_path_metrics[0] -input_symbol_real -increment[7];
318 pm_candidate2 = old_path_metrics[8] -input_symbol_real +increment[0];
piotr437f5462014-02-04 17:57:25 +0100319 if(pm_candidate1 > pm_candidate2){
320 new_path_metrics[0] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200321 trans_table[sample_nr][0] = -std::abs( -input_symbol_real -increment[7]);
piotr437f5462014-02-04 17:57:25 +0100322 }
323 else{
324 new_path_metrics[0] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200325 trans_table[sample_nr][0] = std::abs( -input_symbol_real +increment[0]);
piotr437f5462014-02-04 17:57:25 +0100326 }
327
piotrebd06232014-05-02 17:28:21 +0200328 pm_candidate1 = old_path_metrics[0] +input_symbol_real +increment[7];
329 pm_candidate2 = old_path_metrics[8] +input_symbol_real -increment[0];
piotr437f5462014-02-04 17:57:25 +0100330 if(pm_candidate1 > pm_candidate2){
331 new_path_metrics[1] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200332 trans_table[sample_nr][1] = -std::abs( +input_symbol_real +increment[7]);
piotr437f5462014-02-04 17:57:25 +0100333 }
334 else{
335 new_path_metrics[1] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200336 trans_table[sample_nr][1] = std::abs( +input_symbol_real -increment[0]);
piotr437f5462014-02-04 17:57:25 +0100337 }
338
piotrebd06232014-05-02 17:28:21 +0200339 pm_candidate1 = old_path_metrics[1] -input_symbol_real -increment[6];
340 pm_candidate2 = old_path_metrics[9] -input_symbol_real +increment[1];
piotr437f5462014-02-04 17:57:25 +0100341 if(pm_candidate1 > pm_candidate2){
342 new_path_metrics[2] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200343 trans_table[sample_nr][2] = -std::abs( -input_symbol_real -increment[6]);
piotr437f5462014-02-04 17:57:25 +0100344 }
345 else{
346 new_path_metrics[2] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200347 trans_table[sample_nr][2] = std::abs( -input_symbol_real +increment[1]);
piotr437f5462014-02-04 17:57:25 +0100348 }
349
piotrebd06232014-05-02 17:28:21 +0200350 pm_candidate1 = old_path_metrics[1] +input_symbol_real +increment[6];
351 pm_candidate2 = old_path_metrics[9] +input_symbol_real -increment[1];
piotr437f5462014-02-04 17:57:25 +0100352 if(pm_candidate1 > pm_candidate2){
353 new_path_metrics[3] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200354 trans_table[sample_nr][3] = -std::abs( +input_symbol_real +increment[6]);
piotr437f5462014-02-04 17:57:25 +0100355 }
356 else{
357 new_path_metrics[3] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200358 trans_table[sample_nr][3] = std::abs( +input_symbol_real -increment[1]);
piotr437f5462014-02-04 17:57:25 +0100359 }
360
piotrebd06232014-05-02 17:28:21 +0200361 pm_candidate1 = old_path_metrics[2] -input_symbol_real -increment[5];
362 pm_candidate2 = old_path_metrics[10] -input_symbol_real +increment[2];
piotr437f5462014-02-04 17:57:25 +0100363 if(pm_candidate1 > pm_candidate2){
364 new_path_metrics[4] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200365 trans_table[sample_nr][4] = -std::abs( -input_symbol_real -increment[5]);
piotr437f5462014-02-04 17:57:25 +0100366 }
367 else{
368 new_path_metrics[4] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200369 trans_table[sample_nr][4] = std::abs( -input_symbol_real +increment[2]);
piotr437f5462014-02-04 17:57:25 +0100370 }
371
piotrebd06232014-05-02 17:28:21 +0200372 pm_candidate1 = old_path_metrics[2] +input_symbol_real +increment[5];
373 pm_candidate2 = old_path_metrics[10] +input_symbol_real -increment[2];
piotr437f5462014-02-04 17:57:25 +0100374 if(pm_candidate1 > pm_candidate2){
375 new_path_metrics[5] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200376 trans_table[sample_nr][5] = -std::abs( +input_symbol_real +increment[5]);
piotr437f5462014-02-04 17:57:25 +0100377 }
378 else{
379 new_path_metrics[5] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200380 trans_table[sample_nr][5] = std::abs( +input_symbol_real -increment[2]);
piotr437f5462014-02-04 17:57:25 +0100381 }
382
piotrebd06232014-05-02 17:28:21 +0200383 pm_candidate1 = old_path_metrics[3] -input_symbol_real -increment[4];
384 pm_candidate2 = old_path_metrics[11] -input_symbol_real +increment[3];
piotr437f5462014-02-04 17:57:25 +0100385 if(pm_candidate1 > pm_candidate2){
386 new_path_metrics[6] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200387 trans_table[sample_nr][6] = -std::abs( -input_symbol_real -increment[4]);
piotr437f5462014-02-04 17:57:25 +0100388 }
389 else{
390 new_path_metrics[6] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200391 trans_table[sample_nr][6] = std::abs( -input_symbol_real +increment[3]);
piotr437f5462014-02-04 17:57:25 +0100392 }
393
piotrebd06232014-05-02 17:28:21 +0200394 pm_candidate1 = old_path_metrics[3] +input_symbol_real +increment[4];
395 pm_candidate2 = old_path_metrics[11] +input_symbol_real -increment[3];
piotr437f5462014-02-04 17:57:25 +0100396 if(pm_candidate1 > pm_candidate2){
397 new_path_metrics[7] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200398 trans_table[sample_nr][7] = -std::abs( +input_symbol_real +increment[4]);
piotr437f5462014-02-04 17:57:25 +0100399 }
400 else{
401 new_path_metrics[7] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200402 trans_table[sample_nr][7] = std::abs( +input_symbol_real -increment[3]);
piotr437f5462014-02-04 17:57:25 +0100403 }
404
piotrebd06232014-05-02 17:28:21 +0200405 pm_candidate1 = old_path_metrics[4] -input_symbol_real -increment[3];
406 pm_candidate2 = old_path_metrics[12] -input_symbol_real +increment[4];
piotr437f5462014-02-04 17:57:25 +0100407 if(pm_candidate1 > pm_candidate2){
408 new_path_metrics[8] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200409 trans_table[sample_nr][8] = -std::abs( -input_symbol_real -increment[3]);
piotr437f5462014-02-04 17:57:25 +0100410 }
411 else{
412 new_path_metrics[8] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200413 trans_table[sample_nr][8] = std::abs( -input_symbol_real +increment[4]);
piotr437f5462014-02-04 17:57:25 +0100414 }
415
piotrebd06232014-05-02 17:28:21 +0200416 pm_candidate1 = old_path_metrics[4] +input_symbol_real +increment[3];
417 pm_candidate2 = old_path_metrics[12] +input_symbol_real -increment[4];
piotr437f5462014-02-04 17:57:25 +0100418 if(pm_candidate1 > pm_candidate2){
419 new_path_metrics[9] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200420 trans_table[sample_nr][9] = -std::abs( +input_symbol_real +increment[3]);
piotr437f5462014-02-04 17:57:25 +0100421 }
422 else{
423 new_path_metrics[9] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200424 trans_table[sample_nr][9] = std::abs( +input_symbol_real -increment[4]);
piotr437f5462014-02-04 17:57:25 +0100425 }
426
piotrebd06232014-05-02 17:28:21 +0200427 pm_candidate1 = old_path_metrics[5] -input_symbol_real -increment[2];
428 pm_candidate2 = old_path_metrics[13] -input_symbol_real +increment[5];
piotr437f5462014-02-04 17:57:25 +0100429 if(pm_candidate1 > pm_candidate2){
430 new_path_metrics[10] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200431 trans_table[sample_nr][10] = -std::abs( -input_symbol_real -increment[2]);
piotr437f5462014-02-04 17:57:25 +0100432 }
433 else{
434 new_path_metrics[10] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200435 trans_table[sample_nr][10] = std::abs( -input_symbol_real +increment[5]);
piotr437f5462014-02-04 17:57:25 +0100436 }
437
piotrebd06232014-05-02 17:28:21 +0200438 pm_candidate1 = old_path_metrics[5] +input_symbol_real +increment[2];
439 pm_candidate2 = old_path_metrics[13] +input_symbol_real -increment[5];
piotr437f5462014-02-04 17:57:25 +0100440 if(pm_candidate1 > pm_candidate2){
441 new_path_metrics[11] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200442 trans_table[sample_nr][11] = -std::abs( +input_symbol_real +increment[2]);
piotr437f5462014-02-04 17:57:25 +0100443 }
444 else{
445 new_path_metrics[11] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200446 trans_table[sample_nr][11] = std::abs( +input_symbol_real -increment[5]);
piotr437f5462014-02-04 17:57:25 +0100447 }
448
piotrebd06232014-05-02 17:28:21 +0200449 pm_candidate1 = old_path_metrics[6] -input_symbol_real -increment[1];
450 pm_candidate2 = old_path_metrics[14] -input_symbol_real +increment[6];
piotr437f5462014-02-04 17:57:25 +0100451 if(pm_candidate1 > pm_candidate2){
452 new_path_metrics[12] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200453 trans_table[sample_nr][12] = -std::abs( -input_symbol_real -increment[1]);
piotr437f5462014-02-04 17:57:25 +0100454 }
455 else{
456 new_path_metrics[12] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200457 trans_table[sample_nr][12] = std::abs( -input_symbol_real +increment[6]);
piotr437f5462014-02-04 17:57:25 +0100458 }
459
piotrebd06232014-05-02 17:28:21 +0200460 pm_candidate1 = old_path_metrics[6] +input_symbol_real +increment[1];
461 pm_candidate2 = old_path_metrics[14] +input_symbol_real -increment[6];
piotr437f5462014-02-04 17:57:25 +0100462 if(pm_candidate1 > pm_candidate2){
463 new_path_metrics[13] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200464 trans_table[sample_nr][13] = -std::abs( +input_symbol_real +increment[1]);
piotr437f5462014-02-04 17:57:25 +0100465 }
466 else{
467 new_path_metrics[13] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200468 trans_table[sample_nr][13] = std::abs( +input_symbol_real -increment[6]);
piotr437f5462014-02-04 17:57:25 +0100469 }
470
piotrebd06232014-05-02 17:28:21 +0200471 pm_candidate1 = old_path_metrics[7] -input_symbol_real -increment[0];
472 pm_candidate2 = old_path_metrics[15] -input_symbol_real +increment[7];
piotr437f5462014-02-04 17:57:25 +0100473 if(pm_candidate1 > pm_candidate2){
474 new_path_metrics[14] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200475 trans_table[sample_nr][14] = -std::abs( -input_symbol_real -increment[0]);
piotr437f5462014-02-04 17:57:25 +0100476 }
477 else{
478 new_path_metrics[14] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200479 trans_table[sample_nr][14] = std::abs( -input_symbol_real +increment[7]);
piotr437f5462014-02-04 17:57:25 +0100480 }
481
piotrebd06232014-05-02 17:28:21 +0200482 pm_candidate1 = old_path_metrics[7] +input_symbol_real +increment[0];
483 pm_candidate2 = old_path_metrics[15] +input_symbol_real -increment[7];
piotr437f5462014-02-04 17:57:25 +0100484 if(pm_candidate1 > pm_candidate2){
485 new_path_metrics[15] = pm_candidate1;
piotrebd06232014-05-02 17:28:21 +0200486 trans_table[sample_nr][15] = -std::abs( +input_symbol_real +increment[0]);
piotr437f5462014-02-04 17:57:25 +0100487 }
488 else{
489 new_path_metrics[15] = pm_candidate2;
piotrebd06232014-05-02 17:28:21 +0200490 trans_table[sample_nr][15] = std::abs( +input_symbol_real -increment[7]);
piotr437f5462014-02-04 17:57:25 +0100491 }
492 tmp=old_path_metrics;
493 old_path_metrics=new_path_metrics;
494 new_path_metrics=tmp;
495
496 sample_nr++;
497 }
498
499/*
500* Find the best from the stop states by comparing their path metrics.
501* Not every stop state is always possible, so we are searching in
502* a subset of them.
503*/
504 unsigned int best_stop_state;
505 float stop_state_metric, max_stop_state_metric;
506 best_stop_state = stop_states[0];
507 max_stop_state_metric = old_path_metrics[best_stop_state];
508 for(i=1; i< stops_num; i++){
509 stop_state_metric = old_path_metrics[stop_states[i]];
510 if(stop_state_metric > max_stop_state_metric){
511 max_stop_state_metric = stop_state_metric;
512 best_stop_state = stop_states[i];
513 }
514 }
515
516/*
517* This table was generated with hope that it gives a litle speedup during
518* traceback stage.
519* Received bit is related to the number of state in the trellis.
520* I've numbered states so their parity (number of ones) is related
521* to a received bit.
522*/
523 static const unsigned int parity_table[PATHS_NUM] = { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, };
524
525/*
526* Table of previous states in the trellis diagram.
527* For GMSK modulation every state has two previous states.
528* Example:
529* previous_state_nr1 = prev_table[current_state_nr][0]
530* previous_state_nr2 = prev_table[current_state_nr][1]
531*/
532 static const unsigned int prev_table[PATHS_NUM][2] = { {0,8}, {0,8}, {1,9}, {1,9}, {2,10}, {2,10}, {3,11}, {3,11}, {4,12}, {4,12}, {5,13}, {5,13}, {6,14}, {6,14}, {7,15}, {7,15}, };
533
534/*
535* Traceback and differential decoding of received sequence.
536* Decisions stored in trans_table are used to restore best path in the trellis.
537*/
538 sample_nr=samples_num;
539 unsigned int state_nr=best_stop_state;
540 unsigned int decision;
541 bool out_bit=0;
542
543 while(sample_nr>0){
544 sample_nr--;
545 decision = (trans_table[sample_nr][state_nr]>0);
piotrebd06232014-05-02 17:28:21 +0200546
547 output[sample_nr] = (decision == out_bit ? trans_table[sample_nr][state_nr] : -trans_table[sample_nr][state_nr]);
piotr437f5462014-02-04 17:57:25 +0100548 out_bit = out_bit ^ real_imag ^ parity_table[state_nr];
549 state_nr = prev_table[state_nr][decision];
550 real_imag = !real_imag;
551 }
552}