2017-03-28 17:08:59 +00:00
|
|
|
/*!
|
|
|
|
* \file viterbi27.c
|
|
|
|
* \author Phil Karn, KA9Q
|
|
|
|
* \brief K=7 r=1/2 Viterbi decoder in portable C
|
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* This file was originally borrowed from libswiftnav
|
|
|
|
* <https://github.com/swift-nav/libswiftnav>,
|
|
|
|
* a portable C library implementing GNSS related functions and algorithms,
|
|
|
|
* and then modified by J. Arribas and C. Fernandez
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004, Phil Karn, KA9Q
|
|
|
|
*
|
|
|
|
* GNSS-SDR is a software defined Global Navigation
|
|
|
|
* Satellite Systems receiver
|
|
|
|
*
|
|
|
|
* This file is part of GNSS-SDR.
|
|
|
|
*
|
|
|
|
* This file 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, version 3.
|
|
|
|
*
|
|
|
|
* This program 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 Lesser Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
2018-05-13 20:49:11 +00:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2017-03-23 14:45:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "fec.h"
|
2019-02-11 20:13:02 +00:00
|
|
|
#include <stdlib.h>
|
2017-03-23 14:45:41 +00:00
|
|
|
|
2019-07-19 16:23:36 +00:00
|
|
|
static inline unsigned int parity(unsigned int x)
|
2017-03-23 14:45:41 +00:00
|
|
|
{
|
2019-07-19 16:23:36 +00:00
|
|
|
x ^= x >> 16U;
|
|
|
|
x ^= x >> 8U;
|
|
|
|
x ^= x >> 4U;
|
|
|
|
x &= 0xFU;
|
|
|
|
return (0x6996U >> x) & 1U;
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2017-03-23 14:45:41 +00:00
|
|
|
/** Initialize a v27_poly_t struct for use with a v27_t decoder.
|
|
|
|
*
|
|
|
|
* \param poly Structure to initialize.
|
|
|
|
* \param polynomial Byte array representing the desired polynomials.
|
|
|
|
*/
|
|
|
|
void v27_poly_init(v27_poly_t *poly, const signed char polynomial[2])
|
|
|
|
{
|
2017-03-28 17:32:42 +00:00
|
|
|
int state;
|
2017-03-23 14:45:41 +00:00
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
for (state = 0; state < 32; state++)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
poly->c0[state] = (polynomial[0] < 0) ^ parity((2 * state) & abs(polynomial[0])) ? 255 : 0;
|
|
|
|
poly->c1[state] = (polynomial[1] < 0) ^ parity((2 * state) & abs(polynomial[1])) ? 255 : 0;
|
2017-03-28 17:32:42 +00:00
|
|
|
}
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2017-03-23 14:45:41 +00:00
|
|
|
/** Initialize a v27_t struct for Viterbi decoding.
|
|
|
|
*
|
|
|
|
* \param v Structure to initialize
|
|
|
|
* \param decisions Array of v27_decision_t structs, capacity = decisions_count.
|
|
|
|
* Must remain valid as long as v is used.
|
|
|
|
* \param decisions_count Size of decisions array. Equal to the number of bit
|
|
|
|
* decisions kept in history.
|
|
|
|
* \param poly Struct describing the polynomials to use. Must remain valid as
|
|
|
|
* long as v is used. May be shared between multiple decoders.
|
|
|
|
* \param initial_state Initial state of the decoder shift register. Usually zero.
|
|
|
|
*/
|
|
|
|
void v27_init(v27_t *v, v27_decision_t *decisions, unsigned int decisions_count,
|
2019-02-11 20:13:02 +00:00
|
|
|
const v27_poly_t *poly, unsigned char initial_state)
|
2017-03-23 14:45:41 +00:00
|
|
|
{
|
2017-03-28 17:32:42 +00:00
|
|
|
int i;
|
2017-03-23 14:45:41 +00:00
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
v->old_metrics = v->metrics1;
|
|
|
|
v->new_metrics = v->metrics2;
|
|
|
|
v->poly = poly;
|
|
|
|
v->decisions = decisions;
|
|
|
|
v->decisions_index = 0;
|
|
|
|
v->decisions_count = decisions_count;
|
2017-03-23 14:45:41 +00:00
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 64; i++)
|
|
|
|
{
|
|
|
|
v->old_metrics[i] = 63;
|
|
|
|
}
|
2017-03-23 14:45:41 +00:00
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
v->old_metrics[initial_state & 63] = 0; /* Bias known start state */
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2017-03-23 14:45:41 +00:00
|
|
|
/* C-language butterfly */
|
2019-02-11 20:13:02 +00:00
|
|
|
#define BFLY(i) \
|
|
|
|
{ \
|
2019-08-12 22:19:31 +00:00
|
|
|
unsigned int metric; \
|
|
|
|
unsigned int m0; \
|
|
|
|
unsigned int m1; \
|
|
|
|
unsigned int decision; \
|
2019-02-11 20:13:02 +00:00
|
|
|
metric = (v->poly->c0[i] ^ sym0) + (v->poly->c1[i] ^ sym1); \
|
|
|
|
m0 = v->old_metrics[i] + metric; \
|
|
|
|
m1 = v->old_metrics[(i) + 32] + (510 - metric); \
|
|
|
|
decision = (signed int)(m0 - m1) > 0; \
|
|
|
|
v->new_metrics[2 * (i)] = decision ? m1 : m0; \
|
2019-07-19 16:23:36 +00:00
|
|
|
d->w[(i) / 16] |= decision << ((2U * (i)) & 31U); \
|
2019-02-11 20:13:02 +00:00
|
|
|
m0 -= (metric + metric - 510); \
|
|
|
|
m1 += (metric + metric - 510); \
|
|
|
|
decision = (signed int)(m0 - m1) > 0; \
|
|
|
|
v->new_metrics[2 * (i) + 1] = decision ? m1 : m0; \
|
2019-07-19 16:23:36 +00:00
|
|
|
d->w[(i) / 16] |= decision << ((2U * (i) + 1U) & 31U); \
|
2019-02-11 20:13:02 +00:00
|
|
|
}
|
2017-03-23 14:45:41 +00:00
|
|
|
|
|
|
|
/** Update a v27_t decoder with a block of symbols.
|
|
|
|
*
|
|
|
|
* \param v Structure to update.
|
|
|
|
* \param syms Array of symbols to use. Must contain two symbols per bit.
|
|
|
|
* 0xff = strong 1, 0x00 = strong 0.
|
|
|
|
* \param nbits Number of bits corresponding to the provided symbols.
|
|
|
|
*/
|
|
|
|
void v27_update(v27_t *v, const unsigned char *syms, int nbits)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
unsigned char sym0;
|
|
|
|
unsigned char sym1;
|
2017-03-28 17:32:42 +00:00
|
|
|
unsigned int *tmp;
|
|
|
|
int normalize = 0;
|
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
while (nbits--)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
|
|
|
v27_decision_t *d = &v->decisions[v->decisions_index];
|
|
|
|
|
|
|
|
d->w[0] = d->w[1] = 0;
|
|
|
|
sym0 = *syms++;
|
|
|
|
sym1 = *syms++;
|
|
|
|
|
2019-07-19 16:23:36 +00:00
|
|
|
BFLY(0U);
|
|
|
|
BFLY(1U);
|
|
|
|
BFLY(2U);
|
|
|
|
BFLY(3U);
|
|
|
|
BFLY(4U);
|
|
|
|
BFLY(5U);
|
|
|
|
BFLY(6U);
|
|
|
|
BFLY(7U);
|
|
|
|
BFLY(8U);
|
|
|
|
BFLY(9U);
|
|
|
|
BFLY(10U);
|
|
|
|
BFLY(11U);
|
|
|
|
BFLY(12U);
|
|
|
|
BFLY(13U);
|
|
|
|
BFLY(14U);
|
|
|
|
BFLY(15U);
|
|
|
|
BFLY(16U);
|
|
|
|
BFLY(17U);
|
|
|
|
BFLY(18U);
|
|
|
|
BFLY(19U);
|
|
|
|
BFLY(20U);
|
|
|
|
BFLY(21U);
|
|
|
|
BFLY(22U);
|
|
|
|
BFLY(23U);
|
|
|
|
BFLY(24U);
|
|
|
|
BFLY(25U);
|
|
|
|
BFLY(26U);
|
|
|
|
BFLY(27U);
|
|
|
|
BFLY(28U);
|
|
|
|
BFLY(29U);
|
|
|
|
BFLY(30U);
|
|
|
|
BFLY(31U);
|
2017-03-28 17:32:42 +00:00
|
|
|
|
|
|
|
/* Normalize metrics if they are nearing overflow */
|
2019-07-19 16:23:36 +00:00
|
|
|
if (v->new_metrics[0] > (1U << 30U))
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
|
|
|
int i;
|
2019-07-19 16:23:36 +00:00
|
|
|
unsigned int minmetric = 1U << 31U;
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 64; i++)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (v->new_metrics[i] < minmetric)
|
|
|
|
{
|
|
|
|
minmetric = v->new_metrics[i];
|
|
|
|
}
|
2017-03-28 17:32:42 +00:00
|
|
|
}
|
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 64; i++)
|
|
|
|
{
|
|
|
|
v->new_metrics[i] -= minmetric;
|
|
|
|
}
|
2017-03-28 17:32:42 +00:00
|
|
|
|
|
|
|
normalize += minmetric;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Advance decision index */
|
2019-02-11 20:13:02 +00:00
|
|
|
if (++v->decisions_index >= v->decisions_count)
|
|
|
|
{
|
|
|
|
v->decisions_index = 0;
|
|
|
|
}
|
2017-03-28 17:32:42 +00:00
|
|
|
|
|
|
|
/* Swap pointers to old and new metrics */
|
|
|
|
tmp = v->old_metrics;
|
|
|
|
v->old_metrics = v->new_metrics;
|
|
|
|
v->new_metrics = tmp;
|
|
|
|
}
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2017-03-23 14:45:41 +00:00
|
|
|
/** Retrieve the most likely output bit sequence with known final state from
|
|
|
|
* a v27_t decoder.
|
|
|
|
*
|
|
|
|
* \param v Structure to use.
|
|
|
|
* \param data Array used to store output bits, capacity = nbits.
|
|
|
|
* \param nbits Number of bits to retrieve.
|
|
|
|
* \param final_state Known final state of the decoder shift register.
|
|
|
|
*/
|
|
|
|
void v27_chainback_fixed(v27_t *v, unsigned char *data, unsigned int nbits,
|
2019-02-11 20:13:02 +00:00
|
|
|
unsigned char final_state)
|
2017-03-23 14:45:41 +00:00
|
|
|
{
|
2019-07-19 16:23:36 +00:00
|
|
|
unsigned int k;
|
2017-03-28 17:32:42 +00:00
|
|
|
unsigned int decisions_index = v->decisions_index;
|
|
|
|
|
|
|
|
final_state %= 64;
|
2019-07-19 16:23:36 +00:00
|
|
|
final_state <<= 2U;
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
while (nbits-- != 0)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
|
|
|
/* Decrement decision index */
|
2019-02-11 20:13:02 +00:00
|
|
|
decisions_index = (decisions_index == 0) ? v->decisions_count - 1 : decisions_index - 1;
|
2017-03-28 17:32:42 +00:00
|
|
|
|
|
|
|
v27_decision_t *d = &v->decisions[decisions_index];
|
2019-07-19 16:23:36 +00:00
|
|
|
k = (d->w[(final_state >> 2U) / 32] >> ((final_state >> 2U) % 32)) & 1U;
|
2017-03-28 17:32:42 +00:00
|
|
|
/* The store into data[] only needs to be done every 8 bits.
|
|
|
|
* But this avoids a conditional branch, and the writes will
|
|
|
|
* combine in the cache anyway
|
|
|
|
*/
|
2019-07-19 16:23:36 +00:00
|
|
|
data[nbits >> 3U] = final_state = (final_state >> 1U) | (k << 7U);
|
2017-03-28 17:32:42 +00:00
|
|
|
}
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 17:32:42 +00:00
|
|
|
|
2017-03-23 14:45:41 +00:00
|
|
|
/** Retrieve the most likely output bit sequence with unknown final state from
|
|
|
|
* a v27_t decoder.
|
|
|
|
*
|
|
|
|
* \param v Structure to use.
|
|
|
|
* \param data Array used to store output bits, capacity = nbits.
|
|
|
|
* \param nbits Number of bits to retrieve.
|
|
|
|
*/
|
|
|
|
void v27_chainback_likely(v27_t *v, unsigned char *data, unsigned int nbits)
|
|
|
|
{
|
2017-03-28 17:32:42 +00:00
|
|
|
/* Determine state with minimum metric */
|
|
|
|
|
|
|
|
int i;
|
|
|
|
unsigned int best_metric = 0xffffffff;
|
|
|
|
unsigned char best_state = 0;
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 64; i++)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (v->new_metrics[i] < best_metric)
|
2017-03-28 17:32:42 +00:00
|
|
|
{
|
|
|
|
best_metric = v->new_metrics[i];
|
|
|
|
best_state = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v27_chainback_fixed(v, data, nbits, best_state);
|
2017-03-23 14:45:41 +00:00
|
|
|
}
|