Commit b95f6f1d authored by Stefan Westerfeld's avatar Stefan Westerfeld

Merge branch 'a-b-error-correction'

parents 1e1a673c 10f02230
......@@ -2,10 +2,9 @@
== Description
`audiowmark` is an Open Source solution for audio watermarking. A sound file
(typically wav) is read by the software, and a 128-bit message is stored in a
watermark in the output sound file. For human listeners, the files typically
sound the same.
`audiowmark` is an Open Source solution for audio watermarking. A sound file is
read by the software, and a 128-bit message is stored in a watermark in the
output sound file. For human listeners, the files typically sound the same.
However, the 128-bit message can be retrieved from the output sound file. Our
tests show, that even if the file is converted to mp3 or ogg (with bitrate 128
......@@ -22,17 +21,94 @@ later. The algorithm used here is inspired by
Martin Steinebach: Digitale Wasserzeichen für Audiodaten.
Darmstadt University of Technology 2004, ISBN 3-8322-2507-2
== Adding/Retrieving a Watermark
== Adding a Watermark
To add a watermark to the soundfile in.wav with a 128-bit message (which is
specified as hex-string):
audiowmark add in.wav out.wav 0123456789abcdef0011223344556677
[subs=+quotes]
....
*$ audiowmark add in.wav out.wav 0123456789abcdef0011223344556677*
Input: in.wav
Output: out.wav
Message: 0123456789abcdef0011223344556677
Strength: 10
To get the 128-bit message from the watermarked file, use:
Time: 3:59
Sample Rate: 48000
Channels: 2
Data Blocks: 4
Volume Norm: 0.987 (-0.12 dB)
....
The most important options for adding a watermark are:
--key <filename>::
Use watermarking key from file <filename> (see <<key>>).
audiowmark get out.wav
--strength <s>::
Set the watermarking strength (see <<strength>>).
== Retrieving a Watermark
To get the 128-bit message from the watermarked file, use:
[subs=+quotes]
....
*$ audiowmark get out.wav*
pattern 0:05 0123456789abcdef0011223344556677 1.324 0.059 A
pattern 0:57 0123456789abcdef0011223344556677 1.413 0.112 B
pattern 0:57 0123456789abcdef0011223344556677 1.368 0.086 AB
pattern 1:49 0123456789abcdef0011223344556677 1.302 0.098 A
pattern 2:40 0123456789abcdef0011223344556677 1.361 0.093 B
pattern 2:40 0123456789abcdef0011223344556677 1.331 0.096 AB
pattern all 0123456789abcdef0011223344556677 1.350 0.054
....
The output of `audiowmark get` is designed to be machine readable. Each line
that starts with `pattern` contains one decoded message. The fields are
seperated by one or more space characters. The first field is a *timestamp*
indicating the position of the data block. The second field is the *decoded
message*. For most purposes this is all you need to know.
The software was designed under the assumption that you - the user - will be
able to decide whether a message is correct or not. To do this, on watermarking
song files, you could list each message you embedded in a database. During
retrieval, you should look up each pattern `audiowmark get` outputs in the
database. If the message is not found, then you should assume that a decoding
error occurred. In our example each pattern was decoded correctly, because
the watermark was not damaged at all, but if you for instance use lossy
compression (with a low bitrate), it may happen that only some of the decoded
patterns are correct. Or none, if the watermark was damaged too much.
The third field is the *sync score* (higher is better). The synchronization
algorithm tries to find valid data blocks in the audio file, that become
candidates for decoding.
The fourth field is the *decoding error* (lower is better). During message
decoding, we use convolutional codes for error correction, to make the
watermarking more robust.
The fifth field is the *block type*. There are two types of data blocks,
A blocks and B blocks. A single data block can be decoded alone, as it
contains a complete message. However, if during watermark detection an
A block followed by a B block was found, these two can be decoded
together (then this field will be AB), resulting in even higher error
correction capacity than one block alone would have.
To improve the error correction capacity even further, the `all` pattern
combines all data blocks that are available. The combined decoded
message will often be the most reliable result (meaning that even if all
other patterns were incorrect, this could still be right).
The most important options for getting a watermark are:
--key <filename>::
Use watermarking key from file <filename> (see <<key>>).
--strength <s>::
Set the watermarking strength (see <<strength>>).
[[key]]
== Watermark Key
Since the software is Open Source, a watermarking key should be used to ensure
......@@ -52,6 +128,7 @@ and can be used for the add/get commands as follows:
audiowmark add --key test.key in.wav out.wav 0123456789abcdef0011223344556677
audiowmark get --key test.key out.wav
[[strength]]
== Watermark Strength
The watermark strength parameter affects how much the watermarking algorithm
......@@ -74,7 +151,7 @@ watermark. Fractional strengths (like 7.5) are possible.
== Dependencies
If you compile from source, audiowmark needs the follwing libraries:
If you compile from source, audiowmark needs the following libraries:
* libfftw3
* libsndfile
......
This diff is collapsed.
#!/bin/bash
TRANSFORM=$1
if [ "x$AWM_TRUNCATE" != "x" ]; then
AWM_REPORT=truncv
fi
if [ "x$AWM_SET" == "x" ]; then
AWM_SET=small
fi
......@@ -29,7 +32,7 @@ fi
do
for SEED in $AWM_SEEDS
do
echo $i
echo in_file $i
if [ "x$AWM_RAND_PATTERN" != "x" ]; then
# random pattern, 128 bit
......@@ -43,12 +46,14 @@ do
# pseudo random pattern, 128 bit
PATTERN=4e1243bd22c66e76c2ba9eddc1f91394
fi
echo in_pattern $PATTERN
echo in_flags $AWM_PARAMS --test-key $SEED
audiowmark add "$i" ${AWM_FILE}.wav $PATTERN $AWM_PARAMS --test-key $SEED >/dev/null
if [ "x$AWM_RAND_CUT" != x ]; then
CUT=$RANDOM
audiowmark cut-start "${AWM_FILE}.wav" "${AWM_FILE}.wav" $CUT
TEST_CUT_ARGS="--test-cut $CUT"
echo in_cut $CUT
else
TEST_CUT_ARGS=""
fi
......@@ -85,18 +90,47 @@ do
echo "unknown transform $TRANSFORM" >&2
exit 1
fi
# blind decoding
audiowmark cmp $OUT_FILE $PATTERN $AWM_PARAMS --test-key $SEED $TEST_CUT_ARGS
# decoding with original
# audiowmark cmp-delta "$i" t.wav $PATTERN $AWM_PARAMS --test-key $SEED
echo
if [ "x$AWM_REPORT" == "xtruncv" ]; then
for TRUNC in $AWM_TRUNCATE
do
audiowmark cmp $OUT_FILE $PATTERN $AWM_PARAMS --test-key $SEED $TEST_CUT_ARGS --test-truncate $TRUNC | sed "s/^/$TRUNC /g"
echo
done
else
audiowmark cmp $OUT_FILE $PATTERN $AWM_PARAMS --test-key $SEED $TEST_CUT_ARGS
echo
fi
rm -f ${AWM_FILE}.wav $OUT_FILE # cleanup temp files
done
done | {
if [ "x$AWM_REPORT" == "xfer" ]; then
awk 'BEGIN { bad = n = 0 } $1 == "match_count" { if ($2 == 0) bad++; n++; } END { print bad, n, bad * 100.0 / n; }'
elif [ "x$AWM_REPORT" == "xferv" ]; then
awk 'BEGIN { bad = n = 0 } { print "###", $0; } $1 == "match_count" { if ($2 == 0) bad++; n++; } END { print bad, n, bad * 100.0 / n; }'
elif [ "x$AWM_REPORT" == "xsync" ]; then
awk 'BEGIN { bad = n = 0 } $1 == "sync_match" { bad += (3 - $2) / 3.0; n++; } END { print bad, n, bad * 100.0 / n; }'
elif [ "x$AWM_REPORT" == "xsyncv" ]; then
awk '{ print "###", $0; } $1 == "sync_match" { correct += $2; missing += 3 - $2; incorrect += $3-$2; print "correct:", correct, "missing:", missing, "incorrect:", incorrect; }'
elif [ "x$AWM_REPORT" == "xtruncv" ]; then
awk ' {
print "###", $0;
}
$2 == "match_count" {
if (!n[$1])
{
n[$1] = 0;
bad[$1] = 0;
}
if ($3 == 0)
bad[$1]++;
n[$1]++;
}
END {
for (trunc in n) {
print trunc, bad[trunc], n[trunc], bad[trunc] * 100.0 / n[trunc];
}
}'
else
echo "unknown report $AWM_REPORT" >&2
exit 1
......
......@@ -22,11 +22,14 @@ parity (unsigned int v)
return p;
}
// 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,12>
{
066561, 075211, 071545, 054435, 063635, 052475,
063543, 075307, 052547, 045627, 067657, 051757
};
constexpr unsigned int ab_rate = ab_generators.size();
constexpr unsigned int order = 15;
/*
constexpr unsigned int order = 9;
......@@ -43,14 +46,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)
{
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)
{
return (msg_size + order) * rate;
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 +109,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 +157,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 +196,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 +206,24 @@ 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);
}
void
conv_print_table (ConvBlockType block_type)
{
vector<int> bits (100);
bits[0] = 1;
vector<int> out_bits = conv_encode (block_type, bits);
auto generators = get_block_type_generators (block_type);
unsigned int rate = generators.size();
for (unsigned int r = 0; r < rate; r++)
{
for (unsigned int i = 0; i < order; i++)
printf ("%s%d", i == 0 ? "" : " ", out_bits[i * rate + r]);
printf ("\n");
}
}
......@@ -4,9 +4,13 @@
#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);
void conv_print_table (ConvBlockType block_type);
#endif /* AUDIOWMARK_CONV_CODE_HH */
......@@ -4,10 +4,9 @@ echo ".sync-codec-resistence"
echo '[frame="topbot",options="header",cols="<2,6*>1"]'
echo '|=========================='
echo -n "| "
for D in $(seq 10 -1 5)
for STRENGTH in $(seq 10 -1 5)
do
DELTA=$(printf "0.0%02d\n" $D)
echo -n "| $DELTA"
echo -n "| $STRENGTH"
done
echo
for TEST in mp3 double-mp3 ogg
......@@ -22,10 +21,9 @@ do
echo "error: bad TEST $TEST ???"
exit 1
fi
for D in $(seq 10 -1 5)
for STRENGTH in $(seq 10 -1 5)
do
DELTA=$(printf "0.0%02d\n" $D)
cat $DELTA-$TEST-* | awk '{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
cat $STRENGTH-$TEST-* | grep -v '^#' | awk '{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
......
#!/bin/bash
DELTA_RANGE="0.005 0.006 0.007 0.008 0.009 0.010"
STRENGTH_RANGE=$(seq 5 10)
SEEDS="$(seq 0 19)"
echo -n "all: "
for SEED in $SEEDS
do
for DELTA in $DELTA_RANGE
for STRENGTH in $STRENGTH_RANGE
do
echo -n "$DELTA-ogg-$SEED $DELTA-mp3-$SEED $DELTA-double-mp3-$SEED "
echo -n "$STRENGTH-ogg-$SEED $STRENGTH-mp3-$SEED $STRENGTH-double-mp3-$SEED "
done
done
......@@ -17,23 +17,23 @@ echo
for SEED in $SEEDS
do
for DELTA in $DELTA_RANGE
for STRENGTH in $STRENGTH_RANGE
do
FILE="$DELTA-ogg-$SEED"
FILE="$STRENGTH-ogg-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--water-delta $DELTA' AWM_REPORT=fer AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh ogg 128 ) >x$FILE"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_REPORT=ferv AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh ogg 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="$DELTA-mp3-$SEED"
FILE="$STRENGTH-mp3-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--water-delta $DELTA' AWM_REPORT=fer AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 128 ) >x$FILE"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_REPORT=ferv AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="$DELTA-double-mp3-$SEED"
FILE="$STRENGTH-double-mp3-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--water-delta $DELTA' AWM_REPORT=fer AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh double-mp3 128 ) >x$FILE"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_REPORT=ferv AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh double-mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
......
#!/bin/bash
TRUNCATE="60 110 245"
for TRUNC in 60 110 245
do
echo ".sync-codec-resistence$TRUNC"
echo '[frame="topbot",options="header",cols="<2,6*>1"]'
echo '|=========================='
echo -n "| "
for STRENGTH in $(seq 10 -1 5)
do
echo -n "| $STRENGTH"
done
echo
for TEST in mp3 double-mp3 ogg
do
if [ $TEST == mp3 ]; then
echo -n "| mp3 128kbit/s"
elif [ $TEST == double-mp3 ]; then
echo -n "| double mp3 128kbit/s"
elif [ $TEST == ogg ]; then
echo -n "| ogg 128kbit/s"
else
echo "error: bad TEST $TEST ???"
exit 1
fi
for STRENGTH in $(seq 10 -1 5)
do
cat $STRENGTH-$TEST-* | grep -v '^#' | grep ^$TRUNC | awk '{bad += $2; n += $3} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
echo
echo '|=========================='
done
#!/bin/bash
STRENGTH_RANGE=$(seq 5 10)
SEEDS="$(seq 0 19)"
TRUNCATE="60 110 245"
echo -n "all: "
for SEED in $SEEDS
do
for STRENGTH in $STRENGTH_RANGE
do
echo -n "$STRENGTH-ogg-$SEED $STRENGTH-mp3-$SEED $STRENGTH-double-mp3-$SEED "
done
done
echo
echo
for SEED in $SEEDS
do
for STRENGTH in $STRENGTH_RANGE
do
FILE="$STRENGTH-ogg-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_TRUNCATE='$TRUNCATE' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh ogg 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="$STRENGTH-mp3-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_TRUNCATE='$TRUNCATE' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="$STRENGTH-double-mp3-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_TRUNCATE='$TRUNCATE' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh double-mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
done
......@@ -10,6 +10,31 @@ using std::vector;
using std::regex;
using std::regex_match;
static void
gcrypt_init()
{
static bool init_ok = false;
if (!init_ok)
{
/* version check: start libgcrypt initialization */
if (!gcry_check_version (GCRYPT_VERSION))
{
fprintf (stderr, "audiowmark: libgcrypt version mismatch\n");
exit (1);
}
/* disable secure memory (assume we run in a controlled environment) */
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
/* tell libgcrypt that initialization has completed */
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
init_ok = true;
}
}
static vector<unsigned char> aes_key (16); // 128 bits
static constexpr auto GCRY_CIPHER = GCRY_CIPHER_AES128;
......@@ -55,6 +80,8 @@ print (const string& label, const vector<unsigned char>& data)
Random::Random (uint64_t seed, Stream stream)
{
gcrypt_init();
vector<unsigned char> ctr = get_start_counter (seed, stream);
// print ("CTR", ctr);
......@@ -201,6 +228,8 @@ Random::load_global_key (const string& key_file)
string
Random::gen_key()
{
gcrypt_init();
vector<unsigned char> key (16);
gcry_randomize (&key[0], 16, /* long term key material strength */ GCRY_VERY_STRONG_RANDOM);
return vec_to_hex_str (key);
......
......@@ -15,7 +15,8 @@ public:
sync_up_down = 2,
pad_up_down = 3,
mix = 4,
bit_order = 5
bit_order = 5,
frame_position = 6
};
private:
gcry_cipher_hd_t aes_ctr_cipher;
......
......@@ -34,10 +34,36 @@ generate_error_vector (size_t n, int errors)
}
return ev;
}
static bool
no_case_equal (const string& s1, const string& s2)
{
if (s1.size() != s2.size())
return false;
return std::equal (s1.begin(), s1.end(), s2.begin(),
[] (char c1, char c2) -> bool { return tolower (c1) == tolower (c2);});
}
int
main (int argc, char **argv)
{
if (argc == 1)
string btype = (argc > 1) ? argv[1] : "";
ConvBlockType block_type;
if (no_case_equal (btype, "A"))
block_type = ConvBlockType::a;
else if (no_case_equal (btype, "B"))
block_type = ConvBlockType::b;
else if (no_case_equal (btype, "AB"))
block_type = ConvBlockType::ab;
else
{
printf ("first argument must be A, B, or AB\n");
return 1;
}
if (argc == 2)
{
vector<int> in_bits = bit_str_to_vec ("80f12381");
......@@ -46,16 +72,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 (block_type, 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 (block_type, in_bits.size()));
vector<int> decoded_bits = conv_decode_hard (coded_bits);
vector<int> decoded_bits = conv_decode_hard (block_type, coded_bits);
printf ("output vector (k=%zd): ", decoded_bits.size());
for (auto b : decoded_bits)
printf ("%d", b);
......@@ -68,9 +94,9 @@ main (int argc, char **argv)
errors++;
printf ("decoding errors: %d\n", errors);
}
if (argc == 2 && string (argv[1]) == "error")
if (argc == 3 && string (argv[2]) == "error")
{
size_t max_bit_errors = conv_code_size (128) * 0.5;
size_t max_bit_errors = conv_code_size (block_type, 128) * 0.5;
for (size_t bit_errors = 0; bit_errors < max_bit_errors; bit_errors++)
{
......@@ -84,14 +110,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 (block_type, 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 (block_type, coded_bits);
assert (decoded_bits.size() == 128);
......@@ -105,7 +131,7 @@ main (int argc, char **argv)
printf ("%f %f\n", (100.0 * bit_errors) / coded_bit_count, (100.0 * bad_decode) / test_size);
}
}
if (argc == 2 && string (argv[1]) == "soft-error")
if (argc == 3 && string (argv[2]) == "soft-error")
{
for (double stddev = 0; stddev < 1.5; stddev += 0.01)
{
......@@ -120,7 +146,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 (block_type, in_bits);
coded_bit_count = coded_bits.size();
std::default_random_engine generator;
......@@ -130,7 +156,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 (block_type, recv_bits);
vector<int> recv_hard_bits;
for (auto b : recv_bits)
......@@ -139,7 +165,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 (block_type, recv_hard_bits);
assert (decoded_bits1.size() == 128);
assert (decoded_bits2.size() == 128);
......@@ -161,7 +187,7 @@ main (int argc, char **argv)
printf ("%f %f %f\n", double (100 * local_be) / test_size / coded_bit_count, (100.0 * bad_decode1) / test_size, (100.0 * bad_decode2) / test_size);
}
}
if (argc == 2 && string (argv[1]) == "perf")
if (argc == 3 && string (argv[2]) == "perf")
{
vector<int> in_bits;
while (in_bits.size() != 128)
......@@ -171,9 +197,11 @@ 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 (block_type, conv_encode (block_type, in_bits));
assert (out_bits == in_bits);
}
printf ("%.1f ms/block\n", (gettime() - start_t) / runs * 1000.0);
}
if (argc == 3 && string (argv[2]) == "table")
conv_print_table (block_type);
}
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