diff options
Diffstat (limited to 'tests/Transceiver52M/convolve_test.c')
-rw-r--r-- | tests/Transceiver52M/convolve_test.c | 373 |
1 files changed, 277 insertions, 96 deletions
diff --git a/tests/Transceiver52M/convolve_test.c b/tests/Transceiver52M/convolve_test.c index 8ca4b72..cda5385 100644 --- a/tests/Transceiver52M/convolve_test.c +++ b/tests/Transceiver52M/convolve_test.c @@ -1,142 +1,323 @@ +#include <stdint.h> #include <stdio.h> -#include <string.h> #include <stdlib.h> -#include "convolve.h" +#include <string.h> +#include <math.h> -#define TESTVEC_LEN 1000 -#define DO_INIT 1 +#include "convolve.h" -float x_vect[TESTVEC_LEN]; -float y_vect[TESTVEC_LEN]; -float h_vect[TESTVEC_LEN]; -float *x; -float *h; -float *y; +// --------------------------------------------------------------------------- +// Misc utils +// --------------------------------------------------------------------------- /* Generate some random values for testing */ -void gen_floats(float *vect, int len) +static unsigned long rand_state = 0; + +static void +rand_reset(void) { - int i; - for (i = 0; i < len; i++) { - vect[i] = (float)rand()/(float)(RAND_MAX); - } + rand_state = 0; } -/* Reset testvectors */ -static void reset_testvec(int seed) +static unsigned long +rand_int(void) { - srand(seed); - memset(x_vect,0,sizeof(x_vect)); - memset(y_vect,0,sizeof(y_vect)); - memset(h_vect,0,sizeof(h_vect)); + rand_state = (1103515245UL * rand_state + 12345UL) & 0x7fffffffUL; + return rand_state; +} - x=x_vect + TESTVEC_LEN/2; - y=y_vect + TESTVEC_LEN/2; - h=h_vect + TESTVEC_LEN/2; +static float +rand_float(void) +{ + union { + uint32_t u; + float f; + } r; + uint32_t u = rand_int(); + int e = 112 + ((u ^ (u>>8)) & 15); - gen_floats(x_vect,TESTVEC_LEN); - gen_floats(h_vect,TESTVEC_LEN); + r.u = u & 0x007fffffUL; // Mantissa + r.u |= (u & 0x00800000UL) << 8; // Sign + r.u |= (e & 0xffUL) << 23; // Exponent + + return r.f; +} + +static void +gen_floats(float *vect, int len) +{ + int i; + for (i = 0; i < len; i++) + vect[i] = rand_float(); } /* Show float vector data cut and paste friendly */ -static void dump_floats(float *vect, int len, char *name) +static void +dump_floats(float *vect, int len, char *name) { int i; - printf("float %s[] = {", name); + printf("static const float %s[] = {\n\t", name); for(i = 0; i < len; i++) { + char *end; + if (i == len-1) + end = "\n"; + else if ((i&3) == 3) + end = ",\n\t"; + else + end = ", "; + printf("%14.7ef%s", vect[i], end); + } + printf("};\n"); +} - printf("%f",vect[i]); +/* Compare float with tolerance of delta (absolute) and epsilon (relative) */ +static int +compare_floats(const float *v0, const float *v1, int len, float delta, float epsilon) +{ + int i; + + for (i=0; i<len; i++) + { + float a = v0[i]; + float b = v1[i]; + + if (fabsf(a - b) < delta) + continue; + + if (fabsf(1.0f - (a/b)) < epsilon) + continue; - if(i<len-1) - printf(","); + return 1; } - printf("}\n"); + + return 0; } -/* Test complex convolution */ -static void test_convolve_complex(int h_len) + +// --------------------------------------------------------------------------- +// Golden reference results +// --------------------------------------------------------------------------- + +#include "convolve_test_golden.h" + +enum test_type { + CONV_REAL_BASE = 0, + CONV_REAL_OPT = 1, + CONV_COMPLEX_BASE = 2, + CONV_COMPLEX_OPT = 3 +}; + +struct test_data { + enum test_type type; + int h_len; + const float *y_ref; +}; + +static const char *type_name[] = { + "real_base", "real_opt", "complex_base", "complex_opt", +}; + +static const struct test_data tests[] = { + { CONV_REAL_BASE, 4, y_ref_real_base_4 }, + { CONV_REAL_BASE, 8, y_ref_real_base_8 }, + { CONV_REAL_BASE, 12, y_ref_real_base_12 }, + { CONV_REAL_BASE, 16, y_ref_real_base_16 }, + { CONV_REAL_BASE, 20, y_ref_real_base_20 }, + { CONV_REAL_BASE, 24, y_ref_real_base_24 }, + { CONV_COMPLEX_BASE, 4, y_ref_complex_base_4 }, + { CONV_COMPLEX_BASE, 8, y_ref_complex_base_8 }, + { CONV_COMPLEX_BASE, 12, y_ref_complex_base_12 }, + { CONV_COMPLEX_BASE, 16, y_ref_complex_base_16 }, + { CONV_COMPLEX_BASE, 20, y_ref_complex_base_20 }, + { CONV_COMPLEX_BASE, 24, y_ref_complex_base_24 }, + { 0, 0, NULL }, +}; + + +// --------------------------------------------------------------------------- +// Main testing logic +// --------------------------------------------------------------------------- + +struct test_vec { - int x_len; - int y_len; - int start; - int len; - - x_len=34; - y_len=26; - start=8; - len=26; - reset_testvec(0); - dump_floats(x,x_len,"x"); - printf("\n"); - dump_floats(h,h_len,"h"); - printf("\n"); - convolve_complex(x, x_len, h, h_len, y, y_len, start, len); - dump_floats(y,y_len,"y"); - printf("\n"); + float *x; + float *h; + float *y; + + int x_len; /* Theses are in # of _floats_ ! */ + int h_len; /* Theses are in # of _floats_ ! */ + int y_len; /* Theses are in # of _floats_ ! */ +}; + +/* Reset test vectors */ +static void +test_vec_reset(struct test_vec *tv, int seed) +{ + rand_reset(); + + memset(tv->x, 0, tv->x_len * sizeof(float)); + memset(tv->h, 0, tv->h_len * sizeof(float)); + memset(tv->y, 0, tv->y_len * sizeof(float)); + + gen_floats(tv->x, tv->x_len); + gen_floats(tv->h, tv->h_len); } -/* Test real convolution */ -static void test_convolve_real(int h_len) +/* Allocate test vectors */ +static struct test_vec * +test_vec_alloc(int x_len, int h_len) { - int x_len; - int y_len; - int start; - int len; - - x_len=34; - y_len=26; - start=8; - len=26; - reset_testvec(0); - dump_floats(x-30,2*x_len+30,"x"); - printf("\n"); - dump_floats(h,2*h_len,"h"); - printf("\n"); - convolve_real(x, x_len, h, h_len, y, y_len, start, len); - dump_floats(y,y_len,"y"); - printf("\n"); + struct test_vec *tv; + + tv = calloc(1, sizeof(struct test_vec)); + if (!tv) + return NULL; + + tv->x_len = x_len; + tv->h_len = h_len; + tv->y_len = x_len; /* Results can never be longer than x */ + + tv->x = convolve_h_alloc(x_len); + tv->h = convolve_h_alloc(h_len); + tv->y = convolve_h_alloc(tv->y_len); + + test_vec_reset(tv, 0); + + return tv; } -int main(void) +/* Release test vectors */ +static void +test_vec_release(struct test_vec *tv) { -#if DO_INIT == 1 - convolve_init(); -#endif + if (!tv) + return; - printf("==== TEST COMPLEX BASE IMPLEMENTATION ====\n"); - test_convolve_complex(17); + free(tv->x); + free(tv->h); + free(tv->y); - printf("==== TEST COMPLEX SSE3 IMPLEMENTATION: (h_len%%4=0) ====\n"); - test_convolve_complex(20); + free(tv); +} - printf("==== TEST COMPLEX SSE3 IMPLEMENTATION: (h_len%%8=0) ====\n"); - test_convolve_complex(16); +/* Run convolution */ +static int +run_convolve(struct test_vec *tv, int h_len, enum test_type type) +{ + int x_len; + int start, len; - printf("\n"); - printf("\n"); + test_vec_reset(tv, 0); - printf("==== TEST REAL BASE IMPLEMENTATION ====\n"); - test_convolve_real(17); + /* Compute params that fit within our test vectors */ + x_len = tv->x_len / 2; /* float vs complex */ + start = h_len - 1; + len = x_len - start; - printf("==== TEST REAL SSE3 IMPLEMENTATION (hlen=4) ====\n"); - test_convolve_real(4); + /* Run implementation */ + switch (type) { + case CONV_REAL_BASE: + base_convolve_real( + tv->x, x_len, + tv->h, h_len, + tv->y, tv->y_len, + start, len + ); + break; - printf("==== TEST REAL SSE3 IMPLEMENTATION (hlen=8) ====\n"); - test_convolve_real(8); + case CONV_REAL_OPT: + convolve_real( + tv->x, x_len, + tv->h, h_len, + tv->y, tv->y_len, + start, len + ); + break; - printf("==== TEST REAL SSE3 IMPLEMENTATION (hlen=12) ====\n"); - test_convolve_real(12); + case CONV_COMPLEX_BASE: + base_convolve_complex( + tv->x, x_len, + tv->h, h_len, + tv->y, tv->y_len, + start, len + ); + break; - printf("==== TEST REAL SSE3 IMPLEMENTATION (hlen=16) ====\n"); - test_convolve_real(16); + case CONV_COMPLEX_OPT: + convolve_complex( + tv->x, x_len, + tv->h, h_len, + tv->y, tv->y_len, + start, len + ); + break; + } - printf("==== TEST REAL SSE3 IMPLEMENTATION (hlen=20) ====\n"); - test_convolve_real(20); + return len * 2; +} + + +int main(int argc, char *argv[]) +{ + struct test_vec *tv; + int gen_ref_mode = 0; + char name[80]; + int i, j, len; + + convolve_init(); + + /* Mode */ + gen_ref_mode = (argc == 2) && !strcmp("genref", argv[1]); + + /* Alloc test vectors */ + /* All *2 is to account for the facts all vectors are actually + * complex and need two floats */ + tv = test_vec_alloc(100*2, 25*2); + + /* Dump all input data to make sure we work off the same input data */ + if (!gen_ref_mode) { + printf("==== TEST INPUT DATA ====\n"); + dump_floats(tv->x, tv->x_len, "x"); + dump_floats(tv->h, tv->h_len, "h"); + printf("\n"); + printf("\n"); + } + + /* Run through all the tests */ + if (!gen_ref_mode) + printf("==== TEST ====\n"); + + for (i=0; tests[i].h_len; i++) + { + for (j=0; j<(gen_ref_mode ? 1 : 2); j++) + { + len = run_convolve(tv, tests[i].h_len, tests[i].type + j); + + snprintf(name, sizeof(name)-1, "y_ref_%s_%d", type_name[tests[i].type + j], tests[i].h_len); + + if (gen_ref_mode) + { + /* If in generate mode, output data */ + dump_floats(tv->y, len, name); + } else { + /* If in test mode, compare with data */ + printf("%s: %s\n", + name, + compare_floats(tests[i].y_ref, tv->y, len, 1e-5f, 1e-5f) ? "FAIL" : "PASS" + ); + } + } + } + + if (!gen_ref_mode) { + printf("\n"); + printf("\n"); + } - printf("==== TEST REAL SSE3 IMPLEMENTATION (h_len%%4=0) ====\n"); - test_convolve_real(24); + /* All done ! */ + test_vec_release(tv); return 0; } |