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 ...@@ -382,7 +382,7 @@ mark_bit_linear (int f, const vector<complex<float>>& fft_out, vector<complex<fl
size_t size_t
mark_data_frame_count() 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 struct MixEntry
...@@ -608,7 +608,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits) ...@@ -608,7 +608,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
printf ("Strength: %.6g\n\n", Params::water_delta * 1000); printf ("Strength: %.6g\n\n", Params::water_delta * 1000);
/* add forward error correction, bitvec will now be a lot larger */ /* 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 */ /* pad with zeros to match block_size */
bitvec.resize (mark_data_frame_count() / Params::frames_per_bit); 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) ...@@ -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) 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); vector<float> soft_bit_vec = normalize_soft_bits (raw_bit_vec);
float decode_error = 0; 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) if (sync_score.index)
{ {
...@@ -1148,7 +1148,7 @@ decode_and_report (const WavData& wav_data, const string& orig_pattern) ...@@ -1148,7 +1148,7 @@ decode_and_report (const WavData& wav_data, const string& orig_pattern)
total_count++; 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 }; SyncFinder::Score score_all { 0, 0 };
for (auto sync_score : sync_scores) for (auto sync_score : sync_scores)
......
...@@ -24,9 +24,9 @@ parity (unsigned int v) ...@@ -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 // rate 1/6 code generator poynomial from "In search of a 2dB Coding Gain", Yuen and Vo
// minimum free distance 56 // minimum free distance 56
constexpr unsigned int rate = 6; constexpr auto ab_generators = std::array<unsigned,6> { 046321, 051271, 070535, 063667, 073277, 076531 };
constexpr unsigned int order = 15; constexpr unsigned int ab_rate = ab_generators.size();
constexpr auto generators = std::array<unsigned,6> { 046321, 051271, 070535, 063667, 073277, 076531 }; constexpr unsigned int order = 15;
/* /*
constexpr unsigned int order = 9; constexpr unsigned int order = 9;
...@@ -43,14 +43,45 @@ constexpr unsigned int state_count = (1 << order); ...@@ -43,14 +43,45 @@ constexpr unsigned int state_count = (1 << order);
constexpr unsigned int state_mask = (1 << order) - 1; constexpr unsigned int state_mask = (1 << order) - 1;
size_t 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> 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> out_vec;
vector<int> vec = in_bits; vector<int> vec = in_bits;
...@@ -75,8 +106,10 @@ conv_encode (const vector<int>& in_bits) ...@@ -75,8 +106,10 @@ conv_encode (const vector<int>& in_bits)
/* decode using viterbi algorithm */ /* decode using viterbi algorithm */
vector<int> 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; vector<int> decoded_bits;
assert (coded_bits.size() % rate == 0); assert (coded_bits.size() % rate == 0);
...@@ -121,7 +154,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out) ...@@ -121,7 +154,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
float delta = old_table[state].delta; float delta = old_table[state].delta;
int sbit_pos = new_state * rate; 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 cbit = coded_bits[i + p];
const float sbit = state2bits[sbit_pos + p]; const float sbit = state2bits[sbit_pos + p];
...@@ -160,7 +193,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out) ...@@ -160,7 +193,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
} }
vector<int> 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 /* 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 * 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) ...@@ -170,5 +203,5 @@ conv_decode_hard (const vector<int>& coded_bits)
for (auto b : coded_bits) for (auto b : coded_bits)
soft_bits.push_back (b ? 1.0f : 0.0f); 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 @@ ...@@ -4,9 +4,11 @@
#include <vector> #include <vector>
#include <string> #include <string>
size_t conv_code_size (size_t msg_size); enum class ConvBlockType { a, b, ab };
std::vector<int> conv_encode (const std::vector<int>& in_bits);
std::vector<int> conv_decode_hard (const std::vector<int>& coded_bits); size_t conv_code_size (ConvBlockType block_type, size_t msg_size);
std::vector<int> conv_decode_soft (const std::vector<float>& coded_bits, float *error_out = nullptr); 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 */ #endif /* AUDIOWMARK_CONV_CODE_HH */
...@@ -46,16 +46,16 @@ main (int argc, char **argv) ...@@ -46,16 +46,16 @@ main (int argc, char **argv)
printf ("%d", b); printf ("%d", b);
printf ("\n"); 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()); printf ("coded vector (n=%zd): ", coded_bits.size());
for (auto b : coded_bits) for (auto b : coded_bits)
printf ("%d", b); printf ("%d", b);
printf ("\n"); printf ("\n");
printf ("coded hex: %s\n", bit_vec_to_str (coded_bits).c_str()); 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()); printf ("output vector (k=%zd): ", decoded_bits.size());
for (auto b : decoded_bits) for (auto b : decoded_bits)
printf ("%d", b); printf ("%d", b);
...@@ -70,7 +70,7 @@ main (int argc, char **argv) ...@@ -70,7 +70,7 @@ main (int argc, char **argv)
} }
if (argc == 2 && string (argv[1]) == "error") 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++) for (size_t bit_errors = 0; bit_errors < max_bit_errors; bit_errors++)
{ {
...@@ -84,14 +84,14 @@ main (int argc, char **argv) ...@@ -84,14 +84,14 @@ main (int argc, char **argv)
while (in_bits.size() != 128) while (in_bits.size() != 128)
in_bits.push_back (rand() & 1); 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(); coded_bit_count = coded_bits.size();
vector<int> error_bits = generate_error_vector (coded_bits.size(), bit_errors); vector<int> error_bits = generate_error_vector (coded_bits.size(), bit_errors);
for (size_t pos = 0; pos < coded_bits.size(); pos++) for (size_t pos = 0; pos < coded_bits.size(); pos++)
coded_bits[pos] ^= error_bits[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); assert (decoded_bits.size() == 128);
...@@ -120,7 +120,7 @@ main (int argc, char **argv) ...@@ -120,7 +120,7 @@ main (int argc, char **argv)
while (in_bits.size() != 128) while (in_bits.size() != 128)
in_bits.push_back (rand() & 1); 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(); coded_bit_count = coded_bits.size();
std::default_random_engine generator; std::default_random_engine generator;
...@@ -130,7 +130,7 @@ main (int argc, char **argv) ...@@ -130,7 +130,7 @@ main (int argc, char **argv)
for (auto b : coded_bits) for (auto b : coded_bits)
recv_bits.push_back (b + dist (generator)); 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; vector<int> recv_hard_bits;
for (auto b : recv_bits) for (auto b : recv_bits)
...@@ -139,7 +139,7 @@ main (int argc, char **argv) ...@@ -139,7 +139,7 @@ main (int argc, char **argv)
for (size_t x = 0; x < recv_hard_bits.size(); x++) for (size_t x = 0; x < recv_hard_bits.size(); x++)
local_be += coded_bits[x] ^ recv_hard_bits[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_bits1.size() == 128);
assert (decoded_bits2.size() == 128); assert (decoded_bits2.size() == 128);
...@@ -171,7 +171,7 @@ main (int argc, char **argv) ...@@ -171,7 +171,7 @@ main (int argc, char **argv)
const size_t runs = 20; const size_t runs = 20;
for (size_t i = 0; i < runs; i++) 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); assert (out_bits == in_bits);
} }
printf ("%.1f ms/block\n", (gettime() - start_t) / runs * 1000.0); 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