Commit eee2cc79 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Suppoort different block types: a, b, and ab for convolution codes.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 1e1a673c
......@@ -382,7 +382,7 @@ mark_bit_linear (int f, const vector<complex<float>>& fft_out, vector<complex<fl
size_t
mark_data_frame_count()
{
return conv_code_size (Params::payload_size) * Params::frames_per_bit;
return conv_code_size (ConvBlockType::a, Params::payload_size) * Params::frames_per_bit;
}
struct MixEntry
......@@ -608,7 +608,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
printf ("Strength: %.6g\n\n", Params::water_delta * 1000);
/* add forward error correction, bitvec will now be a lot larger */
bitvec = randomize_bit_order (conv_encode (bitvec), /* encode */ true);
bitvec = randomize_bit_order (conv_encode (ConvBlockType::a, bitvec), /* encode */ true);
/* pad with zeros to match block_size */
bitvec.resize (mark_data_frame_count() / Params::frames_per_bit);
......@@ -1116,12 +1116,12 @@ decode_and_report (const WavData& wav_data, const string& orig_pattern)
auto decode_single = [&] (const vector<float>& raw_bit_vec, SyncFinder::Score sync_score)
{
assert (raw_bit_vec.size() == conv_code_size (Params::payload_size));
assert (raw_bit_vec.size() == conv_code_size (ConvBlockType::a, Params::payload_size));
vector<float> soft_bit_vec = normalize_soft_bits (raw_bit_vec);
float decode_error = 0;
vector<int> bit_vec = conv_decode_soft (randomize_bit_order (soft_bit_vec, /* encode */ false), &decode_error);
vector<int> bit_vec = conv_decode_soft (ConvBlockType::a, randomize_bit_order (soft_bit_vec, /* encode */ false), &decode_error);
if (sync_score.index)
{
......@@ -1148,7 +1148,7 @@ decode_and_report (const WavData& wav_data, const string& orig_pattern)
total_count++;
};
vector<float> raw_bit_vec_all (conv_code_size (Params::payload_size));
vector<float> raw_bit_vec_all (conv_code_size (ConvBlockType::a, Params::payload_size));
SyncFinder::Score score_all { 0, 0 };
for (auto sync_score : sync_scores)
......
......@@ -24,9 +24,9 @@ parity (unsigned int v)
// rate 1/6 code generator poynomial from "In search of a 2dB Coding Gain", Yuen and Vo
// minimum free distance 56
constexpr unsigned int rate = 6;
constexpr unsigned int order = 15;
constexpr auto generators = std::array<unsigned,6> { 046321, 051271, 070535, 063667, 073277, 076531 };
constexpr auto ab_generators = std::array<unsigned,6> { 046321, 051271, 070535, 063667, 073277, 076531 };
constexpr unsigned int ab_rate = ab_generators.size();
constexpr unsigned int order = 15;
/*
constexpr unsigned int order = 9;
......@@ -43,14 +43,45 @@ constexpr unsigned int state_count = (1 << order);
constexpr unsigned int state_mask = (1 << order) - 1;
size_t
conv_code_size (size_t msg_size)
conv_code_size (ConvBlockType block_type, size_t msg_size)
{
return (msg_size + order) * rate;
switch (block_type)
{
case ConvBlockType::a:
case ConvBlockType::b: return (msg_size + order) * ab_rate / 2;
case ConvBlockType::ab: return (msg_size + order) * ab_rate;
default: assert (false);
}
}
vector<unsigned>
get_block_type_generators (ConvBlockType block_type)
{
vector<unsigned> generators;
if (block_type == ConvBlockType::a)
{
for (unsigned int i = 0; i < ab_rate / 2; i++)
generators.push_back (ab_generators[i * 2]);
}
else if (block_type == ConvBlockType::b)
{
for (unsigned int i = 0; i < ab_rate / 2; i++)
generators.push_back (ab_generators[i * 2 + 1]);
}
else
{
assert (block_type == ConvBlockType::ab);
generators.assign (ab_generators.begin(), ab_generators.end());
}
return generators;
}
vector<int>
conv_encode (const vector<int>& in_bits)
conv_encode (ConvBlockType block_type, const vector<int>& in_bits)
{
auto generators = get_block_type_generators (block_type);
vector<int> out_vec;
vector<int> vec = in_bits;
......@@ -75,8 +106,10 @@ conv_encode (const vector<int>& in_bits)
/* decode using viterbi algorithm */
vector<int>
conv_decode_soft (const vector<float>& coded_bits, float *error_out)
conv_decode_soft (ConvBlockType block_type, const vector<float>& coded_bits, float *error_out)
{
auto generators = get_block_type_generators (block_type);
unsigned int rate = generators.size();
vector<int> decoded_bits;
assert (coded_bits.size() % rate == 0);
......@@ -121,7 +154,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
float delta = old_table[state].delta;
int sbit_pos = new_state * rate;
for (size_t p = 0; p < generators.size(); p++)
for (size_t p = 0; p < rate; p++)
{
const float cbit = coded_bits[i + p];
const float sbit = state2bits[sbit_pos + p];
......@@ -160,7 +193,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
}
vector<int>
conv_decode_hard (const vector<int>& coded_bits)
conv_decode_hard (ConvBlockType block_type, const vector<int>& coded_bits)
{
/* for the final application, we always want soft decoding, so we don't
* special case hard decoding here, so this will be a little slower than
......@@ -170,5 +203,5 @@ conv_decode_hard (const vector<int>& coded_bits)
for (auto b : coded_bits)
soft_bits.push_back (b ? 1.0f : 0.0f);
return conv_decode_soft (soft_bits);
return conv_decode_soft (block_type, soft_bits);
}
......@@ -4,9 +4,11 @@
#include <vector>
#include <string>
size_t conv_code_size (size_t msg_size);
std::vector<int> conv_encode (const std::vector<int>& in_bits);
std::vector<int> conv_decode_hard (const std::vector<int>& coded_bits);
std::vector<int> conv_decode_soft (const std::vector<float>& coded_bits, float *error_out = nullptr);
enum class ConvBlockType { a, b, ab };
size_t conv_code_size (ConvBlockType block_type, size_t msg_size);
std::vector<int> conv_encode (ConvBlockType block_type, const std::vector<int>& in_bits);
std::vector<int> conv_decode_hard (ConvBlockType block_type, const std::vector<int>& coded_bits);
std::vector<int> conv_decode_soft (ConvBlockType block_type, const std::vector<float>& coded_bits, float *error_out = nullptr);
#endif /* AUDIOWMARK_CONV_CODE_HH */
......@@ -46,16 +46,16 @@ main (int argc, char **argv)
printf ("%d", b);
printf ("\n");
vector<int> coded_bits = conv_encode (in_bits);
vector<int> coded_bits = conv_encode (ConvBlockType::a, in_bits);
printf ("coded vector (n=%zd): ", coded_bits.size());
for (auto b : coded_bits)
printf ("%d", b);
printf ("\n");
printf ("coded hex: %s\n", bit_vec_to_str (coded_bits).c_str());
assert (coded_bits.size() == conv_code_size (in_bits.size()));
assert (coded_bits.size() == conv_code_size (ConvBlockType::a, in_bits.size()));
vector<int> decoded_bits = conv_decode_hard (coded_bits);
vector<int> decoded_bits = conv_decode_hard (ConvBlockType::a, coded_bits);
printf ("output vector (k=%zd): ", decoded_bits.size());
for (auto b : decoded_bits)
printf ("%d", b);
......@@ -70,7 +70,7 @@ main (int argc, char **argv)
}
if (argc == 2 && string (argv[1]) == "error")
{
size_t max_bit_errors = conv_code_size (128) * 0.5;
size_t max_bit_errors = conv_code_size (ConvBlockType::a, 128) * 0.5;
for (size_t bit_errors = 0; bit_errors < max_bit_errors; bit_errors++)
{
......@@ -84,14 +84,14 @@ main (int argc, char **argv)
while (in_bits.size() != 128)
in_bits.push_back (rand() & 1);
vector<int> coded_bits = conv_encode (in_bits);
vector<int> coded_bits = conv_encode (ConvBlockType::a, in_bits);
coded_bit_count = coded_bits.size();
vector<int> error_bits = generate_error_vector (coded_bits.size(), bit_errors);
for (size_t pos = 0; pos < coded_bits.size(); pos++)
coded_bits[pos] ^= error_bits[pos];
vector<int> decoded_bits = conv_decode_hard (coded_bits);
vector<int> decoded_bits = conv_decode_hard (ConvBlockType::a, coded_bits);
assert (decoded_bits.size() == 128);
......@@ -120,7 +120,7 @@ main (int argc, char **argv)
while (in_bits.size() != 128)
in_bits.push_back (rand() & 1);
vector<int> coded_bits = conv_encode (in_bits);
vector<int> coded_bits = conv_encode (ConvBlockType::a, in_bits);
coded_bit_count = coded_bits.size();
std::default_random_engine generator;
......@@ -130,7 +130,7 @@ main (int argc, char **argv)
for (auto b : coded_bits)
recv_bits.push_back (b + dist (generator));
vector<int> decoded_bits1 = conv_decode_soft (recv_bits);
vector<int> decoded_bits1 = conv_decode_soft (ConvBlockType::a, recv_bits);
vector<int> recv_hard_bits;
for (auto b : recv_bits)
......@@ -139,7 +139,7 @@ main (int argc, char **argv)
for (size_t x = 0; x < recv_hard_bits.size(); x++)
local_be += coded_bits[x] ^ recv_hard_bits[x];
vector<int> decoded_bits2 = conv_decode_hard (recv_hard_bits);
vector<int> decoded_bits2 = conv_decode_hard (ConvBlockType::a, recv_hard_bits);
assert (decoded_bits1.size() == 128);
assert (decoded_bits2.size() == 128);
......@@ -171,7 +171,7 @@ main (int argc, char **argv)
const size_t runs = 20;
for (size_t i = 0; i < runs; i++)
{
vector<int> out_bits = conv_decode_hard (conv_encode (in_bits));
vector<int> out_bits = conv_decode_hard (ConvBlockType::a, conv_encode (ConvBlockType::a, in_bits));
assert (out_bits == in_bits);
}
printf ("%.1f ms/block\n", (gettime() - start_t) / runs * 1000.0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment