satdump/plugins/dvb_support/dvbs/viterbi_all.cpp

355 lines
16 KiB
C++

#include "viterbi_all.h"
#include <cstring>
#include "common/utils.h"
#define ST_IDLE 0
#define ST_SYNCED 1
namespace viterbi
{
Viterbi_DVBS::Viterbi_DVBS(float ber_threshold, int max_outsync, int buffer_size, std::vector<phase_t> phases)
: d_ber_thresold(ber_threshold),
d_max_outsync(max_outsync),
d_buffer_size(buffer_size),
d_phases_to_check(phases),
d_state(ST_IDLE),
cc_decoder_ber_12(TEST_BITS_LENGTH / 2, 7, 2, {79, 109}),
cc_encoder_ber_12(TEST_BITS_LENGTH / 2, 7, 2, {79, 109}),
cc_decoder_ber_23(TEST_BITS_LENGTH * 1.334 / 2, 7, 2, {79, 109}),
cc_encoder_ber_23(TEST_BITS_LENGTH * 1.334 / 2, 7, 2, {79, 109}),
cc_decoder_ber_34(TEST_BITS_LENGTH * 1.5 / 2, 7, 2, {79, 109}),
cc_encoder_ber_34(TEST_BITS_LENGTH * 1.5 / 2, 7, 2, {79, 109}),
cc_decoder_ber_56(TEST_BITS_LENGTH * 1.66 / 2, 7, 2, {79, 109}),
cc_encoder_ber_56(TEST_BITS_LENGTH * 1.66 / 2, 7, 2, {79, 109}),
cc_decoder_ber_78(TEST_BITS_LENGTH * 1.75 / 2, 7, 2, {79, 109}),
cc_encoder_ber_78(TEST_BITS_LENGTH * 1.75 / 2, 7, 2, {79, 109}),
vit_bufsize_23(ensureIs2Multiple(buffer_size * 1.33)),
vit_bufsize_56(ensureIs2Multiple(buffer_size * 1.66)),
cc_decoder_12(buffer_size / 2, 7, 2, {79, 109}),
cc_decoder_23(vit_bufsize_23 / 2, 7, 2, {79, 109}),
cc_decoder_34(buffer_size * 1.5 / 2, 7, 2, {79, 109}),
cc_decoder_56(vit_bufsize_56 / 2, 7, 2, {79, 109}),
cc_decoder_78(buffer_size * 1.75 / 2, 7, 2, {79, 109}),
vit_buffer_23(vit_bufsize_23 * 4),
vit_buffer_56(vit_bufsize_56 * 4)
{
soft_buffer = new uint8_t[d_buffer_size * 4];
depunc_buffer = new uint8_t[d_buffer_size * 4];
output_buffer = new uint8_t[d_buffer_size * 4];
for (int i = 0; i < 12; i++)
{
for (int y = 0; y < 2; y++)
{
d_bers_12[y][i] = 10;
d_bers_23[y][i] = 10;
d_bers_34[y][i] = 10;
d_bers_56[y][i] = 10;
d_bers_78[y][i] = 10;
}
}
}
Viterbi_DVBS::~Viterbi_DVBS()
{
delete[] soft_buffer;
delete[] depunc_buffer;
delete[] output_buffer;
}
float Viterbi_DVBS::get_ber(uint8_t *raw, uint8_t *rencoded, int len, float ratio)
{
float errors = 0, total = 0;
for (int i = 0; i < len; i++)
{
if (raw[i] != 128)
{
errors += (raw[i] > 127) != rencoded[i];
total++;
}
}
return (errors / total) * ratio;
}
int Viterbi_DVBS::work(int8_t *input, int size, uint8_t *output)
{
if (d_state == ST_IDLE) // Search for a lock
{
d_ber = 10;
for (phase_t phase : d_phases_to_check)
{
memcpy(ber_test_buffer, input, TEST_BITS_LENGTH); // Copy over small buffer
rotate_soft(ber_test_buffer, TEST_BITS_LENGTH, phase, false); // Phase shift
signed_soft_to_unsigned(ber_test_buffer, ber_soft_buffer, TEST_BITS_LENGTH); // Convert to softs for the viterbi
// Rate 1/2
for (int shift = 0; shift < 2; shift++) // Test 2 puncturing shifts
{
cc_decoder_ber_12.work(ber_soft_buffer + shift, ber_decoded_buffer); // Decode....
cc_encoder_ber_12.work(ber_decoded_buffer, ber_encoded_buffer); // ....then reencode for comparison
d_bers_12[phase][shift] = get_ber(ber_soft_buffer + shift, ber_encoded_buffer, TEST_BITS_LENGTH, 2.5); // Compute BER between initial buffer and re-encoded
if (d_bers_12[phase][shift] < d_ber_thresold) // Check for a lock
{
d_ber = d_bers_12[phase][shift]; // Set current BER
d_state = ST_SYNCED; // Set the decoder state to SYNCED so we start decoding
d_phase = (phase_t)phase; // Set current phase
d_shift = shift; // Set current puncturing shift
d_invalid = 0; // Reset invalid BER count
d_rate = RATE_1_2; // Set rate
memset(soft_buffer, 128, d_buffer_size * 4);
memset(depunc_buffer, 128, d_buffer_size * 4);
}
}
// Rate 2/3
for (int shift = 0; shift < 6; shift++) // Test 3 puncturing shifts
{
depunc_23.depunc_static(ber_soft_buffer, ber_depunc_buffer, TEST_BITS_LENGTH, shift); // Depuncture
cc_decoder_ber_23.work(ber_depunc_buffer, ber_decoded_buffer); // Decode....
cc_encoder_ber_23.work(ber_decoded_buffer, ber_encoded_buffer); // ....then reencode for comparison
d_bers_23[phase][shift] = get_ber(ber_depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.25, 3.5); // Compute BER between initial buffer and re-encoded
if (d_bers_23[phase][shift] < d_ber_thresold) // Check for a lock
{
d_ber = d_bers_23[phase][shift]; // Set current BER
d_state = ST_SYNCED; // Set the decoder state to SYNCED so we start decoding
d_phase = (phase_t)phase; // Set current phase
d_shift = shift; // Set current puncturing shift
d_invalid = 0; // Reset invalid BER count
d_rate = RATE_2_3; // Set rate
depunc_23.set_shift(d_shift);
memset(soft_buffer, 128, d_buffer_size * 4);
memset(depunc_buffer, 128, d_buffer_size * 4);
}
}
// Rate 3/4
for (int shift = 0; shift < 2; shift++) // Test 2 puncturing shifts
{
depuncture_34(ber_soft_buffer, ber_depunc_buffer, TEST_BITS_LENGTH, shift); // Depuncture
cc_decoder_ber_34.work(ber_depunc_buffer, ber_decoded_buffer); // Decode....
cc_encoder_ber_34.work(ber_decoded_buffer, ber_encoded_buffer); // ....then reencode for comparison
d_bers_34[phase][shift] = get_ber(ber_depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.5, 5); // Compute BER between initial buffer and re-encoded
if (d_bers_34[phase][shift] < d_ber_thresold) // Check for a lock
{
d_ber = d_bers_34[phase][shift]; // Set current BER
d_state = ST_SYNCED; // Set the decoder state to SYNCED so we start decoding
d_phase = (phase_t)phase; // Set current phase
d_shift = shift; // Set current puncturing shift
d_invalid = 0; // Reset invalid BER count
d_rate = RATE_3_4; // Set rate
memset(soft_buffer, 128, d_buffer_size * 4);
memset(depunc_buffer, 128, d_buffer_size * 4);
}
}
// Rate 5/6
for (int shift = 0; shift < 12; shift++) // Test 3 puncturing shifts
{
depunc_56.depunc_static(ber_soft_buffer, ber_depunc_buffer, TEST_BITS_LENGTH, shift); // Depuncture
cc_decoder_ber_56.work(ber_depunc_buffer, ber_decoded_buffer); // Decode....
cc_encoder_ber_56.work(ber_decoded_buffer, ber_encoded_buffer); // ....then reencode for comparison
d_bers_56[phase][shift] = get_ber(ber_depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.66, 8); // Compute BER between initial buffer and re-encoded
if (d_bers_56[phase][shift] < d_ber_thresold) // Check for a lock
{
d_ber = d_bers_56[phase][shift]; // Set current BER
d_state = ST_SYNCED; // Set the decoder state to SYNCED so we start decoding
d_phase = (phase_t)phase; // Set current phase
d_shift = shift; // Set current puncturing shift
d_invalid = 0; // Reset invalid BER count
d_rate = RATE_5_6; // Set rate
depunc_56.set_shift(d_shift);
memset(soft_buffer, 128, d_buffer_size * 4);
memset(depunc_buffer, 128, d_buffer_size * 4);
}
}
// Rate 7/8
for (int shift = 0; shift < 4; shift++) // Test 3 puncturing shifts
{
depuncture_78(ber_soft_buffer, ber_depunc_buffer, TEST_BITS_LENGTH, shift); // Depuncture
cc_decoder_ber_78.work(ber_depunc_buffer, ber_decoded_buffer); // Decode....
cc_encoder_ber_78.work(ber_decoded_buffer, ber_encoded_buffer); // ....then reencode for comparison
d_bers_78[phase][shift] = get_ber(ber_depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.75, 10); // Compute BER between initial buffer and re-encoded
if (d_bers_78[phase][shift] < d_ber_thresold) // Check for a lock
{
d_ber = d_bers_78[phase][shift]; // Set current BER
d_state = ST_SYNCED; // Set the decoder state to SYNCED so we start decoding
d_phase = (phase_t)phase; // Set current phase
d_shift = shift; // Set current puncturing shift
d_invalid = 0; // Reset invalid BER count
d_rate = RATE_7_8; // Set rate
memset(soft_buffer, 128, d_buffer_size * 4);
memset(depunc_buffer, 128, d_buffer_size * 4);
}
}
}
}
int out_n = 0; // Output bytes count
if (d_state == ST_SYNCED) // Decode
{
rotate_soft((int8_t *)input, size, d_phase, false); // Phase shift
signed_soft_to_unsigned((int8_t *)input, soft_buffer, size); // Soft convertion
if (d_rate == RATE_1_2)
{
cc_decoder_12.work(soft_buffer + d_shift, output, size); // Decode entire buffer
out_n = size / 2;
cc_encoder_ber_12.work(output, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(soft_buffer + d_shift, ber_encoded_buffer, TEST_BITS_LENGTH, 2.5); // Compute BER
}
else if (d_rate == RATE_2_3)
{
int sz = depunc_23.depunc_cont(soft_buffer, depunc_buffer, size); // Depuncturing
#if 0
cc_decoder_23.work(depunc_buffer, output, sz); // Decode entire buffer
out_n = sz / 2;
cc_encoder_ber_23.work(output, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.25, 3.5); // Compute BER
#else
vit_buffer_23.add(depunc_buffer, sz);
out_n = 0;
while (vit_buffer_23.in_buffer > vit_bufsize_23)
{
cc_decoder_23.work(vit_buffer_23.buffer_ptr, output + out_n); // Decode entire buffer
cc_encoder_ber_23.work(output + out_n, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(vit_buffer_23.buffer_ptr, ber_encoded_buffer, TEST_BITS_LENGTH * 1.25, 3.5); // Compute BER
out_n += vit_bufsize_23 / 2;
vit_buffer_23.del(vit_bufsize_23);
}
#endif
}
else if (d_rate == RATE_3_4)
{
int sz = depuncture_34(soft_buffer, depunc_buffer, size, d_shift); // Depuncturing
cc_decoder_34.work(depunc_buffer, output, sz); // Decode entire buffer
out_n = sz / 2;
cc_encoder_ber_34.work(output, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.5, 5); // Compute BER
}
else if (d_rate == RATE_5_6)
{
int sz = depunc_56.depunc_cont(soft_buffer, depunc_buffer, size); // Depuncturing
#if 0
cc_decoder_56.work(depunc_buffer, output, sz); // Decode entire buffer
out_n = sz / 2;
cc_encoder_ber_56.work(output, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.66, 8); // Compute BER
#else
vit_buffer_56.add(depunc_buffer, sz);
out_n = 0;
while (vit_buffer_56.in_buffer > vit_bufsize_56)
{
cc_decoder_56.work(vit_buffer_56.buffer_ptr, output + out_n); // Decode entire buffer
cc_encoder_ber_56.work(output + out_n, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(vit_buffer_56.buffer_ptr, ber_encoded_buffer, TEST_BITS_LENGTH * 1.66, 8); // Compute BER
out_n += vit_bufsize_56 / 2;
vit_buffer_56.del(vit_bufsize_56);
}
#endif
}
else if (d_rate == RATE_7_8)
{
int sz = depuncture_78(soft_buffer, depunc_buffer, size, d_shift); // Depuncturing
cc_decoder_78.work(depunc_buffer, output, sz); // Decode entire buffer
out_n = sz / 2;
cc_encoder_ber_78.work(output, ber_encoded_buffer); // Re-encoded for a BER check
d_ber = get_ber(depunc_buffer, ber_encoded_buffer, TEST_BITS_LENGTH * 1.75, 10); // Compute BER
}
if (d_ber > d_ber_thresold) // Check current BER
{
d_invalid++;
if (d_invalid > d_max_outsync) // If we get over out max unsynced thresold...
d_state = ST_IDLE; // ...reset the decoder
}
else
{
d_invalid = 0; // Otherwise, reset current count
}
}
return out_n;
}
float Viterbi_DVBS::ber()
{
if (d_state == ST_SYNCED)
return d_ber;
else
{
float ber = 10;
for (phase_t phase : d_phases_to_check)
for (int o = 0; o < 2; o++)
if (ber > d_bers_12[phase][o])
ber = d_bers_12[phase][o];
for (phase_t phase : d_phases_to_check)
for (int o = 0; o < 6; o++)
if (ber > d_bers_23[phase][o])
ber = d_bers_23[phase][o];
for (phase_t phase : d_phases_to_check)
for (int o = 0; o < 2; o++)
if (ber > d_bers_34[phase][o])
ber = d_bers_34[phase][o];
for (phase_t phase : d_phases_to_check)
for (int o = 0; o < 12; o++)
if (ber > d_bers_56[phase][o])
ber = d_bers_56[phase][o];
for (phase_t phase : d_phases_to_check)
for (int o = 0; o < 4; o++)
if (ber > d_bers_78[phase][o])
ber = d_bers_78[phase][o];
return ber;
}
}
int Viterbi_DVBS::getState()
{
return d_state;
}
}