1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
/* -*- c++ -*- */
/*
* Copyright 2002, 2014 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "atsc_single_viterbi.h"
#include <math.h>
namespace gr {
namespace dtv {
/* was_sent is a table of what symbol we get given what bit pair
was sent and what state we where in [state][pair] */
const int atsc_single_viterbi::d_was_sent[4][4] = {
{0,2,4,6},
{0,2,4,6},
{1,3,5,7},
{1,3,5,7},
};
/* transition_table is a table of what state we were in
given current state and bit pair sent [state][pair] */
const int atsc_single_viterbi::d_transition_table[4][4] = {
{0,2,0,2},
{2,0,2,0},
{1,3,1,3},
{3,1,3,1},
};
void
atsc_single_viterbi::reset()
{
for (unsigned int i = 0; i<2; i++)
for (unsigned int j = 0; j<4; j++) {
d_path_metrics[i][j] = 0;
d_traceback[i][j] = 0;
}
d_post_coder_state = 0;
d_phase = 0;
d_best_state_metric = 100000;
}
atsc_single_viterbi::atsc_single_viterbi()
{
reset();
}
float
atsc_single_viterbi::best_state_metric() const
{
return d_best_state_metric;
}
char
atsc_single_viterbi::decode(float input)
{
unsigned int best_state = 0;
//float best_state_metric = 100000;
d_best_state_metric = 100000;
/* Precompute distances from input to each possible symbol */
float distances[8] = { fabsf( input + 7 ), fabsf( input + 5 ),
fabsf( input + 3 ), fabsf( input + 1 ),
fabsf( input - 1 ), fabsf( input - 3 ),
fabsf( input - 5 ), fabsf( input - 7 ) };
/* We start by iterating over all possible states */
for (unsigned int state = 0; state < 4; state++) {
/* Next we find the most probable path from the previous
states to the state we are testing, we only need to look at
the 4 paths that can be taken given the 2-bit input */
int min_metric_symb = 0;
float min_metric = distances[d_was_sent[state][0]] +
d_path_metrics[d_phase][d_transition_table[state][0]];
for (unsigned int symbol_sent = 1; symbol_sent < 4; symbol_sent++)
if( (distances[d_was_sent[state][symbol_sent]] +
d_path_metrics[d_phase][d_transition_table[state][symbol_sent]]) < min_metric) {
min_metric = distances[d_was_sent[state][symbol_sent]] +
d_path_metrics[d_phase][d_transition_table[state][symbol_sent]];
min_metric_symb = symbol_sent;
}
d_path_metrics[d_phase^1][state] = min_metric;
d_traceback[d_phase^1][state] = (((unsigned long long)min_metric_symb) << 62) |
(d_traceback[d_phase][d_transition_table[state][min_metric_symb]] >> 2);
/* If this is the most probable state so far remember it, this
only needs to be checked when we are about to output a path
so this test can be saved till later if needed, if performed
later it could also be optimized with SIMD instructions.
Even better this check could be eliminated as we are
outputting the tail of our traceback not the head, for any
head state path will tend towards the optimal path with a
probability approaching 1 in just 8 or so transitions
*/
if(min_metric <= d_best_state_metric) {
d_best_state_metric = min_metric;
best_state = state;
}
}
if(d_best_state_metric > 10000) {
for(unsigned int state = 0; state < 4; state++)
d_path_metrics[d_phase^1][state] -= d_best_state_metric;
}
d_phase ^= 1;
int y2 = (0x2 & d_traceback[d_phase][best_state]) >> 1;
int x2 = y2 ^ d_post_coder_state;
d_post_coder_state = y2;
return ( x2 << 1 ) | (0x1 & d_traceback[d_phase][best_state]);
}
} /* namespace dtv */
} /* namespace gr */
|