mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-06-25 12:07:49 +02:00
Bugfix + added M17 decoder to the linux CI
This commit is contained in:
54
core/libcorrect/tests/CMakeLists.txt
Normal file
54
core/libcorrect/tests/CMakeLists.txt
Normal file
@ -0,0 +1,54 @@
|
||||
include_directories("include")
|
||||
|
||||
|
||||
add_executable(convolutional_test_runner EXCLUDE_FROM_ALL convolutional.c $<TARGET_OBJECTS:error_sim>)
|
||||
target_link_libraries(convolutional_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(convolutional_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_test_runner)
|
||||
|
||||
if(HAVE_SSE)
|
||||
add_executable(convolutional_sse_test_runner EXCLUDE_FROM_ALL convolutional-sse.c $<TARGET_OBJECTS:error_sim_sse>)
|
||||
target_link_libraries(convolutional_sse_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(convolutional_sse_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_sse_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_sse_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_sse_test_runner)
|
||||
endif()
|
||||
|
||||
if(HAVE_LIBFEC)
|
||||
add_executable(convolutional_fec_test_runner EXCLUDE_FROM_ALL convolutional-fec.c $<TARGET_OBJECTS:error_sim_fec>)
|
||||
target_link_libraries(convolutional_fec_test_runner correct_static FEC "${LIBM}")
|
||||
set_target_properties(convolutional_fec_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_fec_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_fec_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_fec_test_runner)
|
||||
endif()
|
||||
|
||||
add_executable(convolutional_shim_test_runner EXCLUDE_FROM_ALL convolutional-shim.c $<TARGET_OBJECTS:error_sim_shim>)
|
||||
target_link_libraries(convolutional_shim_test_runner correct_static fec_shim_static "${LIBM}")
|
||||
set_target_properties(convolutional_shim_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME convolutional_shim_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND convolutional_shim_test_runner)
|
||||
set(all_test_runners ${all_test_runners} convolutional_shim_test_runner)
|
||||
|
||||
add_executable(reed_solomon_test_runner EXCLUDE_FROM_ALL reed-solomon.c rs_tester.c)
|
||||
target_link_libraries(reed_solomon_test_runner correct_static "${LIBM}")
|
||||
set_target_properties(reed_solomon_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_test_runner)
|
||||
|
||||
if(HAVE_LIBFEC)
|
||||
add_executable(reed_solomon_interop_test_runner EXCLUDE_FROM_ALL reed-solomon-fec-interop.c rs_tester.c rs_tester_fec.c)
|
||||
target_link_libraries(reed_solomon_interop_test_runner correct_static FEC "${LIBM}")
|
||||
set_target_properties(reed_solomon_interop_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_interop_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_interop_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_interop_test_runner)
|
||||
endif()
|
||||
|
||||
add_executable(reed_solomon_shim_interop_test_runner EXCLUDE_FROM_ALL reed-solomon-shim-interop.c rs_tester.c rs_tester_fec_shim.c)
|
||||
target_link_libraries(reed_solomon_shim_interop_test_runner correct_static fec_shim_static "${LIBM}")
|
||||
set_target_properties(reed_solomon_shim_interop_test_runner PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
|
||||
add_test(NAME reed_solomon_shim_interop_test WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests" COMMAND reed_solomon_shim_interop_test_runner)
|
||||
set(all_test_runners ${all_test_runners} reed_solomon_shim_interop_test_runner)
|
||||
|
||||
add_custom_target(test_runners DEPENDS ${all_test_runners})
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS test_runners)
|
||||
enable_testing()
|
123
core/libcorrect/tests/convolutional-fec.c
Normal file
123
core/libcorrect/tests/convolutional-fec.c
Normal file
@ -0,0 +1,123 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <fec.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "correct/util/error-sim-fec.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, void *fec,
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench_ptr, size_t msg_len, double eb_n0,
|
||||
double bpsk_bit_energy, double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr =
|
||||
resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = fec;
|
||||
testbench->decode = decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, void *fec,
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench, size_t test_length, size_t rate, size_t order,
|
||||
double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0 / sqrt(2.0);
|
||||
double bpsk_sym_energy = 2 * pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count =
|
||||
test_conv(conv, fec, decode, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count / ((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf(
|
||||
"test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf(
|
||||
"test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
void *fec;
|
||||
uint16_t *poly;
|
||||
|
||||
poly = (uint16_t[]){V27POLYA, V27POLYB};
|
||||
conv = correct_convolutional_create(2, 7, poly);
|
||||
fec = create_viterbi27(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, 4.5, 8e-06);
|
||||
assert_test_result(conv, fec, conv_fec27_decode, &testbench, 1000000, 2, 6, 4.0, 5e-05);
|
||||
delete_viterbi27(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V29POLYA, V29POLYB};
|
||||
conv = correct_convolutional_create(2, 9, poly);
|
||||
fec = create_viterbi29(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec29_decode, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
delete_viterbi29(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V39POLYA, V39POLYB, V39POLYC};
|
||||
conv = correct_convolutional_create(3, 9, poly);
|
||||
fec = create_viterbi39(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec39_decode, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
delete_viterbi39(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF};
|
||||
conv = correct_convolutional_create(6, 15, poly);
|
||||
fec = create_viterbi615(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, 3.0, 3e-06);
|
||||
assert_test_result(conv, fec, conv_fec615_decode, &testbench, 100000, 6, 15, 2.5, 1e-05);
|
||||
delete_viterbi615(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
122
core/libcorrect/tests/convolutional-shim.c
Normal file
122
core/libcorrect/tests/convolutional-shim.c
Normal file
@ -0,0 +1,122 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "fec_shim.h"
|
||||
#include "correct/util/error-sim-shim.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, void *fec,
|
||||
ssize_t (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench_ptr, size_t msg_len, double eb_n0,
|
||||
double bpsk_bit_energy, double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr =
|
||||
resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = fec;
|
||||
testbench->decode = decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, void *fec,
|
||||
ssize_t (*decode)(void *, uint8_t *, size_t, uint8_t *),
|
||||
conv_testbench **testbench, size_t test_length, size_t rate, size_t order,
|
||||
double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0 / sqrt(2.0);
|
||||
double bpsk_sym_energy = 2 * pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count =
|
||||
test_conv(conv, fec, decode, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count / ((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf(
|
||||
"test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf(
|
||||
"test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu "
|
||||
"order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
void *fec;
|
||||
uint16_t *poly;
|
||||
|
||||
poly = (uint16_t[]){V27POLYA, V27POLYB};
|
||||
conv = correct_convolutional_create(2, 7, poly);
|
||||
fec = create_viterbi27(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, 4.5, 8e-06);
|
||||
assert_test_result(conv, fec, conv_shim27_decode, &testbench, 1000000, 2, 6, 4.0, 5e-05);
|
||||
delete_viterbi27(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V29POLYA, V29POLYB};
|
||||
conv = correct_convolutional_create(2, 9, poly);
|
||||
fec = create_viterbi29(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_shim29_decode, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
delete_viterbi29(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V39POLYA, V39POLYB, V39POLYC};
|
||||
conv = correct_convolutional_create(3, 9, poly);
|
||||
fec = create_viterbi39(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, fec, conv_shim39_decode, &testbench, 1000000, 3, 9, 4.0, 9e-06);
|
||||
delete_viterbi39(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
poly = (uint16_t[]){V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF};
|
||||
conv = correct_convolutional_create(6, 15, poly);
|
||||
fec = create_viterbi615(8 * max_block_len);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, INFINITY, 0);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, 3.0, 2e-05);
|
||||
assert_test_result(conv, fec, conv_shim615_decode, &testbench, 100000, 6, 15, 2.5, 4e-05);
|
||||
delete_viterbi615(fec);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
132
core/libcorrect/tests/convolutional-sse.c
Normal file
132
core/libcorrect/tests/convolutional-sse.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct/util/error-sim-sse.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional_sse *conv, conv_testbench **testbench_ptr,
|
||||
size_t msg_len, double eb_n0, double bpsk_bit_energy,
|
||||
double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr = resize_conv_testbench(*testbench_ptr, conv_correct_sse_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_sse_encode;
|
||||
testbench->decoder = conv;
|
||||
testbench->decode = conv_correct_sse_decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional_sse *conv, conv_testbench **testbench,
|
||||
size_t test_length, size_t rate, size_t order, double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0/sqrt(2.0);
|
||||
double bpsk_sym_energy = 2*pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count = test_conv(conv, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count/((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf("test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional_sse *conv;
|
||||
|
||||
// n.b. the error rates below are at 5.0dB/4.5dB for order 6 polys
|
||||
// and 4.5dB/4.0dB for order 7-9 polys. this can be easy to miss.
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 6, correct_conv_r12_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 5.0, 8e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 4.5, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 7, correct_conv_r12_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.5, 1e-05);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.0, 5e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 8, correct_conv_r12_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.0, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(2, 9, correct_conv_r12_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.0, 8e-06);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 6, correct_conv_r13_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 4.5, 2e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 7, correct_conv_r13_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.0, 3e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 8, correct_conv_r13_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.5, 4e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.0, 1e-05);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_sse_create(3, 9, correct_conv_r13_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
correct_convolutional_sse_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
133
core/libcorrect/tests/convolutional.c
Normal file
133
core/libcorrect/tests/convolutional.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
#include "correct/util/error-sim.h"
|
||||
|
||||
size_t max_block_len = 4096;
|
||||
|
||||
size_t test_conv(correct_convolutional *conv, conv_testbench **testbench_ptr,
|
||||
size_t msg_len, double eb_n0, double bpsk_bit_energy,
|
||||
double bpsk_voltage) {
|
||||
uint8_t *msg = malloc(max_block_len);
|
||||
|
||||
size_t num_errors = 0;
|
||||
|
||||
while (msg_len) {
|
||||
size_t block_len = (max_block_len < msg_len) ? max_block_len : msg_len;
|
||||
msg_len -= block_len;
|
||||
|
||||
for (unsigned int j = 0; j < block_len; j++) {
|
||||
msg[j] = rand() % 256;
|
||||
}
|
||||
|
||||
*testbench_ptr = resize_conv_testbench(*testbench_ptr, conv_correct_enclen, conv, block_len);
|
||||
conv_testbench *testbench = *testbench_ptr;
|
||||
testbench->encoder = conv;
|
||||
testbench->encode = conv_correct_encode;
|
||||
testbench->decoder = conv;
|
||||
testbench->decode = conv_correct_decode;
|
||||
build_white_noise(testbench->noise, testbench->enclen, eb_n0, bpsk_bit_energy);
|
||||
num_errors += test_conv_noise(testbench, msg, block_len, bpsk_voltage);
|
||||
}
|
||||
free(msg);
|
||||
return num_errors;
|
||||
}
|
||||
|
||||
void assert_test_result(correct_convolutional *conv, conv_testbench **testbench,
|
||||
size_t test_length, size_t rate, size_t order, double eb_n0, double error_rate) {
|
||||
double bpsk_voltage = 1.0/sqrt(2.0);
|
||||
double bpsk_sym_energy = 2*pow(bpsk_voltage, 2.0);
|
||||
double bpsk_bit_energy = bpsk_sym_energy * rate;
|
||||
|
||||
size_t error_count = test_conv(conv, testbench, test_length, eb_n0, bpsk_bit_energy, bpsk_voltage);
|
||||
double observed_error_rate = error_count/((double)test_length * 8);
|
||||
if (observed_error_rate > error_rate) {
|
||||
printf("test failed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("test passed, expected error rate=%.2e, observed error rate=%.2e @%.1fdB for rate %zu order %zu\n",
|
||||
error_rate, observed_error_rate, eb_n0, rate, order);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
conv_testbench *testbench = NULL;
|
||||
|
||||
correct_convolutional *conv;
|
||||
|
||||
// n.b. the error rates below are at 5.0dB/4.5dB for order 6 polys
|
||||
// and 4.5dB/4.0dB for order 7-9 polys. this can be easy to miss.
|
||||
|
||||
conv = correct_convolutional_create(2, 6, correct_conv_r12_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 6, 4.5, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.5, 1e-05);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 7, 4.0, 5e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 8, correct_conv_r12_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 8, 4.0, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(2, 9, correct_conv_r12_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 2, 9, 4.0, 1e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 6, correct_conv_r13_6_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 5.0, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 6, 4.5, 2e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 7, correct_conv_r13_7_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.5, 5e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 7, 4.0, 3e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 8, correct_conv_r13_8_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.5, 4e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 8, 4.0, 1e-05);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
conv = correct_convolutional_create(3, 9, correct_conv_r13_9_polynomial);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, INFINITY, 0);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.5, 3e-06);
|
||||
assert_test_result(conv, &testbench, 1000000, 3, 9, 4.0, 5e-06);
|
||||
correct_convolutional_destroy(conv);
|
||||
|
||||
printf("\n");
|
||||
|
||||
free_scratch(testbench);
|
||||
return 0;
|
||||
}
|
41
core/libcorrect/tests/include/rs_tester.h
Normal file
41
core/libcorrect/tests/include/rs_tester.h
Normal file
@ -0,0 +1,41 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "correct.h"
|
||||
|
||||
void rs_correct_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_correct_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
||||
|
||||
typedef struct {
|
||||
size_t block_length;
|
||||
size_t message_length;
|
||||
size_t min_distance;
|
||||
unsigned char *msg;
|
||||
uint8_t *encoded;
|
||||
int *indices;
|
||||
uint8_t *corrupted_encoded;
|
||||
uint8_t *erasure_locations;
|
||||
unsigned char *recvmsg;
|
||||
} rs_testbench;
|
||||
|
||||
typedef struct {
|
||||
void (*encode)(void *, uint8_t *, size_t, uint8_t *);
|
||||
void *encoder;
|
||||
void (*decode)(void *, uint8_t *, size_t, uint8_t *, size_t, uint8_t *, size_t, size_t);
|
||||
void *decoder;
|
||||
} rs_test;
|
||||
|
||||
rs_testbench *rs_testbench_create(size_t block_length, size_t min_distance);
|
||||
void rs_testbench_destroy(rs_testbench *testbench);
|
||||
|
||||
typedef struct {
|
||||
bool output_matches;
|
||||
} rs_test_run;
|
||||
|
||||
rs_test_run test_rs_errors(rs_test *test, rs_testbench *testbench, size_t msg_length,
|
||||
size_t num_errors, size_t num_erasures);
|
10
core/libcorrect/tests/include/rs_tester_fec.h
Normal file
10
core/libcorrect/tests/include/rs_tester_fec.h
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fec.h>
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
10
core/libcorrect/tests/include/rs_tester_fec_shim.h
Normal file
10
core/libcorrect/tests/include/rs_tester_fec_shim.h
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fec_shim.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out);
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots);
|
138
core/libcorrect/tests/reed-solomon-fec-interop.c
Normal file
138
core/libcorrect/tests/reed-solomon-fec-interop.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
#include "rs_tester_fec.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, void *fec_rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
// run both ways, correct->fec and fec->correct
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.encoder = rs;
|
||||
test.decode = rs_fec_decode;
|
||||
test.decoder = fec_rs;
|
||||
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length,
|
||||
num_errors, num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
|
||||
test.encode = rs_fec_encode;
|
||||
test.encoder = fec_rs;
|
||||
test.decode = rs_correct_decode;
|
||||
test.decoder = rs;
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length,
|
||||
num_errors, num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
size_t pad_length;
|
||||
void *fec_rs;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
138
core/libcorrect/tests/reed-solomon-shim-interop.c
Normal file
138
core/libcorrect/tests/reed-solomon-shim-interop.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
#include "rs_tester_fec_shim.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, void *fec_rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
// run both ways, correct->fec and fec->correct
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.encoder = rs;
|
||||
test.decode = rs_fec_decode;
|
||||
test.decoder = fec_rs;
|
||||
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
|
||||
test.encode = rs_fec_encode;
|
||||
test.encoder = fec_rs;
|
||||
test.decode = rs_correct_decode;
|
||||
test.decoder = rs;
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
size_t pad_length;
|
||||
void *fec_rs;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
pad_length = message_length / 2;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
pad_length = 0;
|
||||
fec_rs = init_rs_char(8, correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance,
|
||||
pad_length);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 2, 0, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
0, min_distance, 20000);
|
||||
run_tests(rs, fec_rs, testbench, block_length, message_length - pad_length,
|
||||
min_distance / 4, min_distance / 2, 20000);
|
||||
free_rs_char(fec_rs);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
146
core/libcorrect/tests/reed-solomon.c
Normal file
146
core/libcorrect/tests/reed-solomon.c
Normal file
@ -0,0 +1,146 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rs_tester.h"
|
||||
|
||||
void print_test_type(size_t block_length, size_t message_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
printf(
|
||||
"testing reed solomon block length=%zu, message length=%zu, "
|
||||
"errors=%zu, erasures=%zu...",
|
||||
block_length, message_length, num_errors, num_erasures);
|
||||
}
|
||||
|
||||
void fail_test() {
|
||||
printf("FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void pass_test() { printf("PASSED\n"); }
|
||||
|
||||
void run_tests(correct_reed_solomon *rs, rs_testbench *testbench,
|
||||
size_t block_length, size_t test_msg_length, size_t num_errors,
|
||||
size_t num_erasures, size_t num_iterations) {
|
||||
rs_test test;
|
||||
test.encode = rs_correct_encode;
|
||||
test.decode = rs_correct_decode;
|
||||
test.encoder = rs;
|
||||
test.decoder = rs;
|
||||
print_test_type(block_length, test_msg_length, num_errors, num_erasures);
|
||||
for (size_t i = 0; i < num_iterations; i++) {
|
||||
rs_test_run run = test_rs_errors(&test, testbench, test_msg_length, num_errors,
|
||||
num_erasures);
|
||||
if (!run.output_matches) {
|
||||
fail_test();
|
||||
}
|
||||
}
|
||||
pass_test();
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time(NULL));
|
||||
|
||||
size_t block_length = 255;
|
||||
size_t min_distance = 32;
|
||||
size_t message_length = block_length - min_distance;
|
||||
|
||||
correct_reed_solomon *rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
rs_testbench *testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 16;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 8;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
min_distance = 4;
|
||||
message_length = block_length - min_distance;
|
||||
rs = correct_reed_solomon_create(
|
||||
correct_rs_primitive_polynomial_ccsds, 1, 1, min_distance);
|
||||
testbench = rs_testbench_create(block_length, min_distance);
|
||||
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, 0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 2,
|
||||
0, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 2, 0,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length, 0, min_distance,
|
||||
20000);
|
||||
run_tests(rs, testbench, block_length, message_length / 2, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
run_tests(rs, testbench, block_length, message_length, min_distance / 4,
|
||||
min_distance / 2, 20000);
|
||||
|
||||
rs_testbench_destroy(testbench);
|
||||
correct_reed_solomon_destroy(rs);
|
||||
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
102
core/libcorrect/tests/rs_tester.c
Normal file
102
core/libcorrect/tests/rs_tester.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include "rs_tester.h"
|
||||
|
||||
void shuffle(int *a, size_t len) {
|
||||
for (size_t i = 0; i < len - 2; i++) {
|
||||
size_t j = rand() % (len - i) + i;
|
||||
int temp = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void rs_correct_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
correct_reed_solomon_encode((correct_reed_solomon *)encoder, msg,
|
||||
msg_length, msg_out);
|
||||
}
|
||||
|
||||
void rs_correct_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
correct_reed_solomon_decode_with_erasures(
|
||||
(correct_reed_solomon *)decoder, encoded, encoded_length,
|
||||
erasure_locations, erasure_length, msg);
|
||||
}
|
||||
|
||||
rs_testbench *rs_testbench_create(size_t block_length, size_t min_distance) {
|
||||
rs_testbench *testbench = calloc(1, sizeof(rs_testbench));
|
||||
|
||||
size_t message_length = block_length - min_distance;
|
||||
testbench->message_length = message_length;
|
||||
testbench->block_length = block_length;
|
||||
testbench->min_distance = min_distance;
|
||||
|
||||
testbench->msg = calloc(message_length, sizeof(unsigned char));
|
||||
testbench->encoded = malloc(block_length * sizeof(uint8_t));
|
||||
|
||||
testbench->indices = malloc(block_length * sizeof(int));
|
||||
|
||||
testbench->corrupted_encoded = malloc(block_length * sizeof(uint8_t));
|
||||
testbench->erasure_locations = malloc(min_distance * sizeof(uint8_t));
|
||||
testbench->recvmsg = malloc(sizeof(unsigned char) * message_length);
|
||||
|
||||
return testbench;
|
||||
}
|
||||
|
||||
void rs_testbench_destroy(rs_testbench *testbench) {
|
||||
free(testbench->msg);
|
||||
free(testbench->encoded);
|
||||
free(testbench->indices);
|
||||
free(testbench->corrupted_encoded);
|
||||
free(testbench->erasure_locations);
|
||||
free(testbench->recvmsg);
|
||||
free(testbench);
|
||||
}
|
||||
|
||||
rs_test_run test_rs_errors(rs_test *test, rs_testbench *testbench, size_t msg_length,
|
||||
size_t num_errors, size_t num_erasures) {
|
||||
rs_test_run run;
|
||||
run.output_matches = false;
|
||||
|
||||
if (msg_length > testbench->message_length) {
|
||||
return run;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < msg_length; i++) {
|
||||
testbench->msg[i] = rand() % 256;
|
||||
}
|
||||
|
||||
size_t block_length = msg_length + testbench->min_distance;
|
||||
size_t pad_length = testbench->message_length - msg_length;
|
||||
|
||||
test->encode(test->encoder, testbench->msg, msg_length, testbench->encoded);
|
||||
|
||||
memcpy(testbench->corrupted_encoded, testbench->encoded, block_length);
|
||||
|
||||
for (int i = 0; i < block_length; i++) {
|
||||
testbench->indices[i] = i;
|
||||
}
|
||||
|
||||
shuffle(testbench->indices, block_length);
|
||||
|
||||
for (unsigned int i = 0; i < num_erasures; i++) {
|
||||
int index = testbench->indices[i];
|
||||
uint8_t corruption_mask = (rand() % 255) + 1;
|
||||
testbench->corrupted_encoded[index] ^= corruption_mask;
|
||||
testbench->erasure_locations[i] = index;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_errors; i++) {
|
||||
int index = testbench->indices[i + num_erasures];
|
||||
uint8_t corruption_mask = (rand() % 255) + 1;
|
||||
testbench->corrupted_encoded[index] ^= corruption_mask;
|
||||
}
|
||||
|
||||
test->decode(test->decoder, testbench->corrupted_encoded, block_length,
|
||||
testbench->erasure_locations, num_erasures,
|
||||
testbench->recvmsg, pad_length, testbench->min_distance);
|
||||
|
||||
run.output_matches = (bool)(memcmp(testbench->msg, testbench->recvmsg, msg_length) == 0);
|
||||
|
||||
return run;
|
||||
}
|
30
core/libcorrect/tests/rs_tester_fec.c
Normal file
30
core/libcorrect/tests/rs_tester_fec.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "rs_tester_fec.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
// XXX make sure that pad length used to build encoder corresponds to this
|
||||
// msg_length
|
||||
memcpy(msg_out, msg, msg_length);
|
||||
encode_rs_char(encoder, msg_out, msg_out + msg_length);
|
||||
}
|
||||
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
// XXX make sure that pad length used to build decoder corresponds to this
|
||||
// encoded_length
|
||||
if (erasure_length) {
|
||||
static size_t locations_len = 0;
|
||||
static int *locations = NULL;
|
||||
if (locations_len < erasure_length) {
|
||||
locations = realloc(locations, erasure_length * sizeof(int));
|
||||
locations_len = erasure_length;
|
||||
}
|
||||
for (size_t i = 0; i < erasure_length; i++) {
|
||||
locations[i] = (unsigned int)(erasure_locations[i]) + pad_length;
|
||||
}
|
||||
decode_rs_char(decoder, encoded, locations, erasure_length);
|
||||
} else {
|
||||
decode_rs_char(decoder, encoded, NULL, 0);
|
||||
}
|
||||
memcpy(msg, encoded, encoded_length - num_roots);
|
||||
}
|
26
core/libcorrect/tests/rs_tester_fec_shim.c
Normal file
26
core/libcorrect/tests/rs_tester_fec_shim.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include "rs_tester_fec_shim.h"
|
||||
void rs_fec_encode(void *encoder, uint8_t *msg, size_t msg_length,
|
||||
uint8_t *msg_out) {
|
||||
// XXX make sure that pad length used to build encoder corresponds to this
|
||||
// msg_length
|
||||
memcpy(msg_out, msg, msg_length);
|
||||
encode_rs_char(encoder, msg_out, msg_out + msg_length);
|
||||
}
|
||||
|
||||
void rs_fec_decode(void *decoder, uint8_t *encoded, size_t encoded_length,
|
||||
uint8_t *erasure_locations, size_t erasure_length,
|
||||
uint8_t *msg, size_t pad_length, size_t num_roots) {
|
||||
// XXX make sure that pad length used to build decoder corresponds to this
|
||||
// encoded_length
|
||||
if (erasure_length) {
|
||||
int *locations = malloc(erasure_length * sizeof(int));
|
||||
for (size_t i = 0; i < erasure_length; i++) {
|
||||
locations[i] = (unsigned int)(erasure_locations[i]) + pad_length;
|
||||
}
|
||||
decode_rs_char(decoder, encoded, locations, erasure_length);
|
||||
free(locations);
|
||||
} else {
|
||||
decode_rs_char(decoder, encoded, NULL, 0);
|
||||
}
|
||||
memcpy(msg, encoded, encoded_length - num_roots);
|
||||
}
|
Reference in New Issue
Block a user