Don't count erasures (punctures) in the Viterbi cost metric. Minor cleanup in the LLR code, along with more unit tests.

m17_demod_updates
Rob Riggs 2021-06-24 22:00:56 -05:00
rodzic fe1ac10581
commit 05a1e3bbb3
4 zmienionych plików z 199 dodań i 16 usunięć

Wyświetl plik

@ -30,19 +30,47 @@ constexpr std::bitset<sizeof...(Is)> make_bitset(std::index_sequence<Is...>, Tup
return result;
}
template<typename FloatType, size_t LLR>
constexpr std::array<std::tuple<FloatType, std::tuple<int8_t, int8_t>>, (((1 << (LLR - 1)) - 1) * 6 ) + 1> make_llr_map()
/**
* This is the max value for the LLR based on size N.
*/
template <size_t N>
constexpr size_t llr_limit()
{
constexpr size_t size = (((1 << (LLR - 1)) - 1) * 6 ) + 1;
return (1 << (N - 1)) - 1;
}
/**
* There are (2^(N-1)-1) elements (E) per segment (e.g. N=4, E=7; N=3, E=3).
* These contain the LLR values 1..E. There are 6 segments in the LLR map:
* 1. (-Inf,-2]
* 2. (-2, -1]
* 3. (-1, 0]
* 4. (0, 1]
* 5. (1, 2]
* 6. (2, Inf)
*
* Note the slight asymmetry. This is OK as we are dealing with floats and
* it only matters to an epsilon of the float type.
*/
template <size_t N>
constexpr size_t llr_size()
{
return llr_limit<N>() * 6 + 1;
}
template<typename FloatType, size_t LLR>
constexpr std::array<std::tuple<FloatType, std::tuple<int8_t, int8_t>>, llr_size<LLR>()> make_llr_map()
{
constexpr size_t size = llr_size<LLR>();
std::array<std::tuple<FloatType, std::tuple<int8_t, int8_t>>, size> result;
constexpr int8_t limit = (1 << (LLR - 1)) - 1;
constexpr int8_t limit = llr_limit<LLR>();
constexpr FloatType inc = 1.0 / FloatType(limit);
int8_t i = limit;
int8_t j = limit;
// Output must be ordered by k, ascending.
FloatType k = -3.0;
FloatType k = -3.0 + inc;
for (size_t index = 0; index != size; ++index)
{
auto& a = result[index];
@ -50,19 +78,22 @@ constexpr std::array<std::tuple<FloatType, std::tuple<int8_t, int8_t>>, (((1 <<
std::get<0>(std::get<1>(a)) = i;
std::get<1>(std::get<1>(a)) = j;
if (k + 1.0 < inc / -2.0)
if (k + 1.0 < 0)
{
j--;
if (j == 0) j = -1;
if (j < -limit) j = -limit;
}
else if (k - 1.0 < inc / -2.0)
else if (k - 1.0 < 0)
{
i--;
if (i == 0) i = -1;
if (i < -limit) i = -limit;
}
else
{
j++;
if (j == 0) j = 1;
if (j > limit) j = limit;
}
k += inc;

Wyświetl plik

@ -7,6 +7,7 @@
#include "Util.h"
#include <limits>
#include <cmath>
namespace mobilinkd
{
@ -104,7 +105,7 @@ struct Viterbi
prevMetrics[0] = 0; // Starting point.
std::array<std::bitset<NumStates>, IN / 2> history;
// history.fill(0);
history.fill(0);
constexpr size_t BUTTERFLY_SIZE = NumStates / 2;
@ -120,10 +121,18 @@ struct Viterbi
for (size_t j = 0; j != BUTTERFLY_SIZE; ++j)
{
int16_t c = std::abs(cost_[j][0] - s0) + std::abs(cost_[j][1] - s1);
cost0[j] = c;
// cost1[j] = METRIC - c;
cost1[j] = std::abs(cost_[j][0] + s0) + std::abs(cost_[j][1] + s1);
cost0[j] = 0;
cost1[j] = 0;
if (s0)
{
cost0[j] += std::abs(cost_[j][0] - s0);
cost1[j] += std::abs(cost_[j][0] + s0);
}
if (s1)
{
cost0[j] += std::abs(cost_[j][1] - s1);
cost1[j] += std::abs(cost_[j][1] + s1);
}
}
for (size_t j = 0; j != BUTTERFLY_SIZE; ++j)
@ -167,7 +176,7 @@ struct Viterbi
}
}
size_t ber = min_cost / (METRIC >> 1); // Cost is at least equal to # of erasures.
size_t ber = std::round(min_cost / float(detail::llr_limit<LLR_>())); // Cost is at least equal to # of erasures.
// Do chainback.
auto oit = std::rbegin(out);

Wyświetl plik

@ -106,4 +106,100 @@ TEST_F(UtilTest, puncture_bytes)
EXPECT_EQ(get_bit_index(out, 53), 0);
EXPECT_EQ(get_bit_index(out, 54), 1);
EXPECT_EQ(get_bit_index(out, 55), 0);
}
TEST_F(UtilTest, llr_size)
{
auto s = mobilinkd::detail::llr_size<4>();
EXPECT_EQ(s, 43) << "size = " << s;
}
TEST_F(UtilTest, llr_not_zero)
{
for (float i = -4.0; i < 4.0; i += 0.1)
{
auto [a, b] = mobilinkd::llr<float, 4>(i);
EXPECT_NE(int(a), 0) << i << ", a = " << int(a);
EXPECT_NE(int(b), 0) << i << ", b = " << int(b);
}
}
TEST_F(UtilTest, llr_near_zero)
{
{
float v = 0.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), -1) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
{
float v = -0.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), 1) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
}
TEST_F(UtilTest, llr_near_one)
{
{
float v = 1.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), -7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
{
float v = 0.9999;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), -7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
}
TEST_F(UtilTest, llr_near_two)
{
{
float v = 2.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), -7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), 1) << v << ", b = " << int(b);
}
{
float v = 1.9999;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), -7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -1) << v << ", b = " << int(b);
}
}
TEST_F(UtilTest, llr_near_minus_one)
{
{
float v = -1.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), 7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
{
float v = -0.9999;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), 7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -7) << v << ", b = " << int(b);
}
}
TEST_F(UtilTest, llr_near_minus_two)
{
{
float v = -2.0001;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), 7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), 1) << v << ", b = " << int(b);
}
{
float v = -1.9999;
auto [a, b] = mobilinkd::llr<float, 4>(v);
EXPECT_EQ(int(a), 7) << v << ", a = " << int(a);
EXPECT_EQ(int(b), -1) << v << ", b = " << int(b);
}
}

Wyświetl plik

@ -143,7 +143,7 @@ TEST_F(ViterbiTest, decode_ber_1)
auto ber = viterbi.decode(encoded,output);
for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]);
EXPECT_EQ(ber, 1);
EXPECT_EQ(ber, 2);
}
TEST_F(ViterbiTest, decode_ber_llr)
@ -165,7 +165,7 @@ TEST_F(ViterbiTest, decode_ber_llr)
auto ber = viterbi.decode(encoded, output);
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Duration: " << (end - start).count() << "ns" << std::endl;
EXPECT_EQ(ber, 1);
EXPECT_EQ(ber, 2);
for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]);
}
@ -223,6 +223,53 @@ TEST_F(ViterbiTest, decode_depuncture_lsf)
std::cout << "Duration: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() << "ns" << std::endl;
std::cout << "Cost: " << ber / 10000 << std::endl;
EXPECT_GT(ber, 0);
EXPECT_EQ(ber, 0);
for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]) << "i = " << i;
}
TEST_F(ViterbiTest, decode_depuncture_lsf_1_error)
{
std::array<uint8_t, 240> expected = {1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0};
std::array<int8_t, 368> punctured = {1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0};
std::array<int8_t, 488> expected_depunctured = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
std::array<uint8_t, 244> output;
for (size_t i = 0; i != punctured.size(); ++i)
{
punctured[i] = punctured[i] * 2 - 1;
}
mobilinkd::Trellis<4,2> trellis({031,027});
mobilinkd::Viterbi<decltype(trellis)> viterbi(trellis);
auto depunctured = mobilinkd::depunctured<488>(mobilinkd::P1, punctured);
depunctured[8] = 1;
auto cost = viterbi.decode(depunctured, output);
EXPECT_EQ(cost, 2);
for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]) << "i = " << i;
}
TEST_F(ViterbiTest, decode_llr4_1_error)
{
std::array<uint8_t, 240> expected = {1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0};
std::array<int8_t, 368> punctured = {1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0};
std::array<int8_t, 488> expected_depunctured = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
std::array<uint8_t, 244> output;
for (size_t i = 0; i != punctured.size(); ++i)
{
punctured[i] = punctured[i] * 14 - 7;
}
mobilinkd::Trellis<4,2> trellis({031,027});
mobilinkd::Viterbi<decltype(trellis), 4> viterbi(trellis);
auto depunctured = mobilinkd::depunctured<488>(mobilinkd::P1, punctured);
depunctured[8] = -1;
auto cost = viterbi.decode(depunctured, output);
EXPECT_EQ(cost, 1);
for (size_t i = 0; i != expected.size(); ++i) EXPECT_EQ(output[i], expected[i]) << "i = " << i;
}