satdump/src-core/common/codings/viterbi/cc_decoder.cpp

316 lines
8.9 KiB
C++
Raw Permalink Normal View History

2021-11-20 14:17:56 +01:00
#include "cc_decoder.h"
2021-03-31 12:16:38 +02:00
#include <volk/volk.h>
#include <cmath>
#include "logger.h"
#include "volk_k7_r2_generic_fixed.h"
2023-05-08 23:08:34 +02:00
#include <cstring>
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
namespace viterbi
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
CCDecoder::CCDecoder(int frame_size, int k, int rate, std::vector<int> polys, int start_state, int end_state)
: d_k(k),
d_rate(rate),
d_polys(polys),
d_start_state_chaining(start_state),
d_start_state_nonchaining(start_state),
d_end_state_nonchaining(end_state)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
// Set max frame size here; all buffers and settings will be
// based on this value.
d_max_frame_size = frame_size;
d_frame_size = frame_size;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_numstates = 1 << (d_k - 1);
2022-08-15 17:07:52 +02:00
d_decision_t_size = d_numstates / 8; // packed bit array
2022-08-15 17:07:52 +02:00
d_veclen = d_frame_size + d_k - 1;
d_end_state = &d_end_state_chaining;
2022-08-15 17:07:52 +02:00
d_vp.metrics.resize(2 * d_numstates);
d_vp.metrics1.t = d_vp.metrics.data();
d_vp.metrics2.t = d_vp.metrics.data() + d_numstates;
2022-08-15 17:07:52 +02:00
d_vp.decisions.resize(d_veclen * d_decision_t_size);
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_branchtab.resize(d_numstates / 2 * rate);
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
create_viterbi();
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (d_k - 1 < 8)
{
d_ADDSHIFT = (8 - (d_k - 1));
d_SUBSHIFT = 0;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
else if (d_k - 1 > 8)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
d_ADDSHIFT = 0;
d_SUBSHIFT = ((d_k - 1) - 8);
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
else
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
d_ADDSHIFT = 0;
d_SUBSHIFT = 0;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
conv_kernel k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_generic; // Default to our fixed generic kernel
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
// We need to get around Volk's broken generic and AVX kernel....
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
volk_func_desc k7_r2_desc = volk_8u_x4_conv_k7_r2_8u_get_func_desc(); // Check what kernels are available
2021-03-31 12:16:38 +02:00
2022-08-19 16:26:54 +02:00
bool has_spiral = false, has_spiral_neon = false;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
for (int i = 0; i < (int)k7_r2_desc.n_impls; i++)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
if (std::string(k7_r2_desc.impl_names[i]) == "spiral") // Try to find spiral
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
has_spiral = true;
break;
2021-03-31 12:16:38 +02:00
}
2022-08-19 16:26:54 +02:00
if (std::string(k7_r2_desc.impl_names[i]) == "neonspiral") // Try to find neonspiral
{
has_spiral_neon = true;
break;
}
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
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;
}
2022-08-19 16:26:54 +02:00
else if (has_spiral_neon)
{ // If spiral is available, use it
logger->trace("Volk has the neonspiral kernel, using it!");
k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_neonspiral;
}
2022-08-15 17:07:52 +02:00
else
{ // Stick to our fixed kernel
2022-08-19 16:26:54 +02:00
logger->trace("Volk does not have the spiral/neonspiral kernel, will default to bundled generic.");
2021-03-31 12:16:38 +02:00
}
}
2022-08-15 17:07:52 +02:00
std::map<std::string, conv_kernel> yp_kernel = {{"k=7r=2", k7_r2_kernel}};
std::string k_ = "k=";
std::string r_ = "r=";
std::ostringstream kerneltype;
kerneltype << k_ << d_k << r_ << d_rate;
d_kernel = yp_kernel[kerneltype.str()];
if (d_kernel == NULL)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
throw std::runtime_error("cc_decoder: parameters not supported");
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
CCDecoder::~CCDecoder() {}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
void CCDecoder::create_viterbi()
{
int state;
unsigned int i;
partab_init();
for (state = 0; state < d_numstates / 2; state++)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
for (i = 0; i < d_rate; i++)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
d_branchtab[i * d_numstates / 2 + state] =
(d_polys[i] < 0) ^ parity((2 * state) & abs(d_polys[i])) ? 255 : 0;
2021-03-31 12:16:38 +02:00
}
}
2022-08-15 17:07:52 +02:00
d_start_state = &d_start_state_chaining;
init_viterbi_unbiased(&d_vp);
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
return;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::parity(int x)
{
x ^= (x >> 16);
x ^= (x >> 8);
return parityb(x);
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::parityb(unsigned char x) { return Partab[x]; }
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
void CCDecoder::partab_init(void)
{
int i, cnt, ti;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
/* Initialize parity lookup table */
for (i = 0; i < 256; i++)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
cnt = 0;
ti = i;
while (ti)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
if (ti & 1)
cnt++;
ti >>= 1;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
Partab[i] = cnt & 1;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::init_viterbi(struct v *vp, int starting_state)
{
int i;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (vp == NULL)
return -1;
for (i = 0; i < d_numstates; i++)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
vp->metrics1.t[i] = 63;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
vp->old_metrics = vp->metrics1;
vp->new_metrics = vp->metrics2;
vp->old_metrics.t[starting_state & (d_numstates - 1)] =
0; /* Bias known start state */
return 0;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::init_viterbi_unbiased(struct v *vp)
{
int i;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (vp == NULL)
return -1;
for (i = 0; i < d_numstates; i++)
vp->metrics1.t[i] = 31;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
vp->old_metrics = vp->metrics1;
vp->new_metrics = vp->metrics2;
// no bias step
return 0;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::find_endstate()
{
unsigned char *met =
((d_k + d_veclen) % 2 == 0) ? d_vp.new_metrics.t : d_vp.old_metrics.t;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
unsigned char min = met[0];
int state = 0;
for (int i = 1; i < d_numstates; ++i)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
if (met[i] < min)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
min = met[i];
state = i;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
}
// printf("min %d\n", state);
return state;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::update_viterbi_blk(unsigned char *syms, int nbits)
{
unsigned char *d = d_vp.decisions.data();
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
memset(d, 0, d_decision_t_size * nbits);
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_kernel(d_vp.new_metrics.t,
d_vp.old_metrics.t,
syms,
d,
nbits - (d_k - 1),
d_k - 1,
d_branchtab.data());
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
return 0;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCDecoder::chainback_viterbi(unsigned char *data,
unsigned int nbits,
unsigned int endstate,
unsigned int tailsize)
{
/* ADDSHIFT and SUBSHIFT make sure that the thing returned is a byte. */
unsigned char *d = d_vp.decisions.data();
/* Make room beyond the end of the encoder register so we can
* accumulate a full byte of decoded data
*/
endstate = (endstate % d_numstates) << d_ADDSHIFT;
/* 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
*/
d += tailsize * d_decision_t_size; /* Look past tail */
int retval = 0;
int dif = tailsize - (d_k - 1);
decision_t dec;
while (nbits-- > d_frame_size - (d_k - 1))
{
int k;
dec.t = &d[nbits * d_decision_t_size];
k = (dec.w[(endstate >> d_ADDSHIFT) / 32] >> ((endstate >> d_ADDSHIFT) % 32)) & 1;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
endstate = (endstate >> 1) | (k << (d_k - 2 + d_ADDSHIFT));
data[((nbits + dif) % d_frame_size)] = k;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
retval = endstate;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
nbits += 1;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
while (nbits-- != 0)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
int k;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
dec.t = &d[nbits * d_decision_t_size];
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
k = (dec.w[(endstate >> d_ADDSHIFT) / 32] >> ((endstate >> d_ADDSHIFT) % 32)) & 1;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
endstate = (endstate >> 1) | (k << (d_k - 2 + d_ADDSHIFT));
data[((nbits + dif) % d_frame_size)] = k;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
return retval >> d_ADDSHIFT;
}
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
bool CCDecoder::set_frame_size(unsigned int frame_size)
{
bool ret = true;
if (frame_size > d_max_frame_size)
{
frame_size = d_max_frame_size;
ret = false;
}
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
d_frame_size = frame_size;
d_veclen = d_frame_size + d_k - 1;
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
return ret;
}
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
double CCDecoder::rate() { return 1.0 / static_cast<double>(d_rate); }
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
void CCDecoder::work(uint8_t *in, uint8_t *out)
{
update_viterbi_blk((unsigned char *)(&in[0]), d_veclen);
d_end_state_chaining = find_endstate();
d_start_state_chaining = chainback_viterbi(&out[0], d_frame_size, *d_end_state, d_veclen - d_frame_size);
2021-11-20 14:17:56 +01:00
2022-08-15 17:07:52 +02:00
init_viterbi(&d_vp, *d_start_state);
}
2022-08-19 16:26:54 +02:00
void CCDecoder::work(uint8_t *in, uint8_t *out, int size)
{
int frm_size = size / d_k;
int veclen = frm_size + d_k - 1;
update_viterbi_blk((unsigned char *)(&in[0]), d_veclen);
d_end_state_chaining = find_endstate();
d_start_state_chaining = chainback_viterbi(&out[0], d_frame_size, *d_end_state, veclen - frm_size);
init_viterbi(&d_vp, *d_start_state);
}
2022-08-15 17:07:52 +02:00
}