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

120 lines
3 KiB
C++
Raw Permalink Normal View History

2021-11-20 14:17:56 +01:00
#include "cc_encoder.h"
2021-03-31 12:16:38 +02:00
#include "cc_common.h"
#include <volk/volk.h>
#include <volk/volk_typedefs.h>
#include <cmath>
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
CCEncoder::CCEncoder(int frame_size, int k, int rate, std::vector<int> polys, int start_state)
: d_rate(rate),
d_k(k),
d_polys(polys),
d_start_state(start_state)
2021-03-31 12:16:38 +02:00
{
2022-08-15 17:07:52 +02:00
if (static_cast<size_t>(d_rate) != d_polys.size())
throw std::runtime_error("cc_encoder: Number of polynomials must be the same as the value of rate");
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (d_rate < 2)
throw std::runtime_error("cc_encoder: inverse rate r must be > 2");
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (k < 2 || k > 31)
throw std::runtime_error("cc_encoder: constraint length K must in be the range [2, 31]");
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (d_start_state >= (1u << (d_k - 1)))
throw std::runtime_error("cc_encoder: start state is invalid; must be in range [0, 2^(K-1)-1] where K is the constraint length");
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
if (frame_size < 1)
throw std::runtime_error("cc_encoder: frame_size must be > 0");
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
partab_init();
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_max_frame_size = frame_size;
set_frame_size(frame_size);
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
CCEncoder::~CCEncoder()
{
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
bool CCEncoder::set_frame_size(unsigned int frame_size)
{
bool ret = true;
if (frame_size > d_max_frame_size)
2021-11-20 14:17:56 +01:00
{
2022-08-15 17:07:52 +02:00
frame_size = d_max_frame_size;
ret = false;
2021-11-20 14:17:56 +01:00
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_frame_size = frame_size;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
d_output_size = d_rate * d_frame_size;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
return ret;
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
double CCEncoder::rate()
{
return static_cast<double>(d_rate);
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
int CCEncoder::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 CCEncoder::parityb(unsigned char x)
{
return Partab[x];
}
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
void CCEncoder::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
void CCEncoder::work(uint8_t *in, uint8_t *out)
{
unsigned int my_state = d_start_state;
2021-03-31 12:16:38 +02:00
2022-08-15 17:07:52 +02:00
for (unsigned int i = 0; i < d_frame_size; ++i)
{
my_state = (my_state << 1) | (in[i] & 1);
for (unsigned int j = 0; j < d_rate; ++j)
out[i * d_rate + j] = (d_polys[j] < 0) ^ parity(my_state & abs(d_polys[j])) ? 1 : 0;
2021-03-31 12:16:38 +02:00
}
2022-08-15 17:07:52 +02:00
d_start_state = my_state;
}
2022-08-20 15:20:27 +02:00
void CCEncoder::work(uint8_t *in, uint8_t *out, int size)
{
unsigned int my_state = d_start_state;
2022-09-09 13:13:10 +02:00
for (int i = 0; i < size; ++i)
2022-08-20 15:20:27 +02:00
{
my_state = (my_state << 1) | (in[i] & 1);
for (unsigned int j = 0; j < d_rate; ++j)
out[i * d_rate + j] = (d_polys[j] < 0) ^ parity(my_state & abs(d_polys[j])) ? 1 : 0;
}
d_start_state = my_state;
}
2022-08-15 17:07:52 +02:00
}