aboutsummaryrefslogtreecommitdiffstats
path: root/tests/Transceiver52M/convolve_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Transceiver52M/convolve_test.c')
-rw-r--r--tests/Transceiver52M/convolve_test.c373
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;
}