Get around the viterbi kernel issue in Volk

This commit is contained in:
Aang23 2021-07-21 15:36:44 +02:00
parent c9b3774ee0
commit 86caa06ce8
3 changed files with 207 additions and 12 deletions

View file

@ -4,17 +4,6 @@ A generic satellite data processing software.
**Still WIP**
# Important - Possible issues with VOLK Viterbi decoding (Windows users can probably ignore this)
/!\ Some decoders utilize VOLK's Viterbi decoder. But as of writing this, only the "spiral" (SSE) implementation performs as intended. Please ensure you have it set as such in your volk_config or things may not work as expected! /!\
On Windows, this should not be necessary as it this will (should!) be the default already.
On Linux, Mac OS and similar platforms, please edit your ~/.volk/volk_config file.
Find the line referring to `volk_8u_x4_conv_k7_r2_8u`, and make sure it contains the following : `volk_8u_x4_conv_k7_r2_8u spiral spiral`.
If you are using an ARM-based machine (Raspbery Pi, most Android devices), there is unfortunately no way around poorer decoding performances of the "generic" kernel... Until this gets fixed in VOLK itself.
# Usage
First of all, as with any program using volk, running volk_profile once is highly recommended for better performances.

View file

@ -15,6 +15,8 @@
#include <cstdio>
#include <sstream>
#include <vector>
#include "logger.h"
#include "volk_k7_r2_generic_fixed.h"
namespace fec
{
@ -122,7 +124,35 @@ namespace fec
d_SUBSHIFT = 0;
}
std::map<std::string, conv_kernel> yp_kernel = {{"k=7r=2", volk_8u_x4_conv_k7_r2_8u}};
conv_kernel k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_generic; // Default to our fixed generic kernel
// We need to get around Volk's broken generic and AVX kernel....
{
volk_func_desc k7_r2_desc = volk_8u_x4_conv_k7_r2_8u_get_func_desc(); // Check what kernels are available
bool has_spiral = false;
for (int i = 0; i < (int)k7_r2_desc.n_impls; i++)
{
if (std::string(k7_r2_desc.impl_names[i]) == "spiral") // Try to find spiral
{
has_spiral = true;
break;
}
}
if (has_spiral)
{ // If spiral is available, use it
logger->trace("Volk has the spiral kernel using it!");
k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_spiral;
}
else
{ // Stick to our fixed kernel
logger->trace("Volk does not have the spiral kernel, will default to bundled generic.");
}
}
std::map<std::string, conv_kernel> yp_kernel = {{"k=7r=2", k7_r2_kernel}};
std::string k_ = "k=";
std::string r_ = "r=";

View file

@ -0,0 +1,176 @@
/* -*- c++ -*- */
/*
* Copyright 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.
*/
/*!
* \page volk_8u_x4_conv_k7_r2_8u
*
* \b Overview
*
* Performs convolutional decoding for a K=7, rate 1/2 convolutional
* code. The polynomials user defined.
*
* <b>Dispatcher Prototype</b>
* \code
* void volk_8u_x4_conv_k7_r2_8u(unsigned char* Y, unsigned char* X, unsigned char* syms,
* unsigned char* dec, unsigned int framebits, unsigned int excess, unsigned char*
* Branchtab) \endcode
*
* \b Inputs
* \li X: <FIXME>
* \li syms: <FIXME>
* \li dec: <FIXME>
* \li framebits: size of the frame to decode in bits.
* \li excess: <FIXME>
* \li Branchtab: <FIXME>
*
* \b Outputs
* \li Y: The decoded output bits.
*
* \b Example
* \code
* int N = 10000;
*
* volk_8u_x4_conv_k7_r2_8u();
*
* volk_free(x);
* \endcode
*/
// The default version in Volk is broken right now, so I am including this fix
// SatDump will default to unless volk_config returned a working implemenation
#ifndef INCLUDED_volk_8u_x4_conv_k7_r2_8u_H
#define INCLUDED_volk_8u_x4_conv_k7_r2_8u_H
#include <volk/volk.h>
namespace volk_fixed
{
typedef union
{
unsigned char /*DECISIONTYPE*/ t[64 /*NUMSTATES*/ / 8 /*DECISIONTYPE_BITSIZE*/];
unsigned int w[64 /*NUMSTATES*/ / 32];
unsigned short s[64 /*NUMSTATES*/ / 16];
unsigned char c[64 /*NUMSTATES*/ / 8];
#ifdef _MSC_VER
} decision_t;
#else
} decision_t __attribute__((aligned(16)));
#endif
static inline void renormalize(unsigned char *X, unsigned char /*threshold*/)
{
int NUMSTATES = 64;
int i;
unsigned char min = X[0];
// if(min > threshold) {
for (i = 0; i < NUMSTATES; i++)
if (min > X[i])
min = X[i];
for (i = 0; i < NUMSTATES; i++)
X[i] -= min;
//}
}
// helper BFLY for GENERIC version
static inline void BFLY(int i,
int s,
unsigned char *syms,
unsigned char *Y,
unsigned char *X,
decision_t *d,
unsigned char *Branchtab)
{
int j, decision0, decision1;
unsigned char metric, m0, m1, m2, m3;
int NUMSTATES = 64;
int RATE = 2;
int METRICSHIFT = 2;
int PRECISIONSHIFT = 2;
metric = 0;
for (j = 0; j < RATE; j++)
metric += (Branchtab[i + j * NUMSTATES / 2] ^ syms[s * RATE + j]) >> METRICSHIFT;
metric = metric >> PRECISIONSHIFT;
unsigned char max = ((RATE * ((256 - 1) >> METRICSHIFT)) >> PRECISIONSHIFT);
m0 = X[i] + metric;
m1 = X[i + NUMSTATES / 2] + (max - metric);
m2 = X[i] + (max - metric);
m3 = X[i + NUMSTATES / 2] + metric;
decision0 = (signed int)(m0 - m1) > 0;
decision1 = (signed int)(m2 - m3) > 0;
Y[2 * i] = decision0 ? m1 : m0;
Y[2 * i + 1] = decision1 ? m3 : m2;
d->w[i / (sizeof(unsigned int) * 8 / 2) +
s * (sizeof(decision_t) / sizeof(unsigned int))] |=
(decision0 | decision1 << 1) << ((2 * i) & (sizeof(unsigned int) * 8 - 1));
}
static inline void volk_8u_x4_conv_k7_r2_8u_generic(unsigned char *Y,
unsigned char *X,
unsigned char *syms,
unsigned char *dec,
unsigned int framebits,
unsigned int excess,
unsigned char *Branchtab)
{
int nbits = framebits + excess;
int NUMSTATES = 64;
int RENORMALIZE_THRESHOLD = 210;
int s, i;
for (s = 0; s < nbits; s++)
{
void *tmp;
for (i = 0; i < NUMSTATES / 2; i++)
{
BFLY(i, s, syms, Y, X, (decision_t *)dec, Branchtab);
}
renormalize(Y, RENORMALIZE_THRESHOLD);
/// Swap pointers to old and new metrics
tmp = (void *)X;
X = Y;
Y = (unsigned char *)tmp;
}
}
static inline void volk_8u_x4_conv_k7_r2_8u_spiral(unsigned char *Y,
unsigned char *X,
unsigned char *syms,
unsigned char *dec,
unsigned int framebits,
unsigned int excess,
unsigned char *Branchtab)
{
volk_8u_x4_conv_k7_r2_8u_manual(Y, X, syms, dec, framebits, excess, Branchtab, "spiral");
}
};
#endif /*INCLUDED_volk_8u_x4_conv_k7_r2_8u_H*/