OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 #include "dl/sp/src/test/test_util.h" |
| 11 |
| 12 #include <stdio.h> |
| 13 #include <stdlib.h> |
| 14 #include <string.h> |
| 15 #include <unistd.h> |
| 16 |
| 17 #include "dl/sp/api/armSP.h" |
| 18 #include "dl/sp/src/test/compare.h" |
| 19 |
| 20 /* |
| 21 * Test resuls from running either forward or inverse FFT tests |
| 22 */ |
| 23 struct TestResult { |
| 24 /* Number of tests that failed */ |
| 25 int failed_count_; |
| 26 |
| 27 /* Number of tests run */ |
| 28 int test_count_; |
| 29 |
| 30 /* Number of tests that were expected to fail */ |
| 31 int expected_failure_count_; |
| 32 |
| 33 /* The minimum SNR found for all of the tests */ |
| 34 float min_snr_; |
| 35 }; |
| 36 |
| 37 /* |
| 38 * Return the program name, fur usage messages and debugging |
| 39 */ |
| 40 char* ProgramName(char* argv0) { |
| 41 char* slash = strrchr(argv0, '/'); |
| 42 |
| 43 return slash ? slash + 1 : argv0; |
| 44 } |
| 45 |
| 46 /* |
| 47 * Print usage message for the command line options. |
| 48 */ |
| 49 void usage(char* prog, int real_only, int max_fft_order, const char *summary) { |
| 50 fprintf(stderr, "\n%s: [-hTFI] [-n logsize] [-s scale] [-g signal-type] " |
| 51 "[-S signal value]\n\t\t[-v verbose] [-m minFFT] [-M maxFFT]\n", |
| 52 ProgramName(prog)); |
| 53 fprintf(stderr, summary); |
| 54 fprintf(stderr, " -h\t\tThis help\n"); |
| 55 fprintf(stderr, " -T\t\tIndividual test mode, otherwise run all tests\n"); |
| 56 fprintf(stderr, " -F\t\tDo not run forward FFT tests\n"); |
| 57 fprintf(stderr, " -I\t\tDo not run inverse FFT tests\n"); |
| 58 fprintf(stderr, " -m min\tMinium FFT order to test (default 2)\n"); |
| 59 fprintf(stderr, " -M min\tMaximum FFT order to test (default %d)\n", |
| 60 max_fft_order); |
| 61 fprintf(stderr, " -n logsize\tLog2 of FFT size\n"); |
| 62 fprintf(stderr, " -s scale\tScale factor for forward FFT (default = 0)\n"); |
| 63 fprintf(stderr, " -S signal\tBase value for the test signal " |
| 64 "(default = 1024)\n"); |
| 65 fprintf(stderr, " -v level\tVerbose output level (default = 1)\n"); |
| 66 fprintf(stderr, " -g type\tInput signal type:\n"); |
| 67 fprintf(stderr, "\t\t 0 - Constant signal S + i*S. (Default value.)\n"); |
| 68 fprintf(stderr, "\t\t 1 - Real ramp starting at S/N, N = FFT size\n"); |
| 69 fprintf(stderr, "\t\t 2 - Sine wave of amplitude S\n"); |
| 70 if (!real_only) |
| 71 fprintf(stderr, "\t\t 3 - Complex signal whose transform is a sine " |
| 72 "wave.\n"); |
| 73 exit(0); |
| 74 } |
| 75 |
| 76 /* |
| 77 * Set default values for all command line options. |
| 78 */ |
| 79 void SetDefaultOptions(struct Options* options, int real_only, |
| 80 int max_fft_order) { |
| 81 options->real_only_ = real_only; |
| 82 |
| 83 options->verbose_ = 1; |
| 84 |
| 85 /* |
| 86 * Test mode options, defaulting to non-test mode |
| 87 */ |
| 88 options->test_mode_ = 1; |
| 89 options->do_forward_tests_ = 1; |
| 90 options->do_inverse_tests_ = 1; |
| 91 options->min_fft_order_ = 2; |
| 92 options->max_fft_order_ = max_fft_order; |
| 93 |
| 94 /* |
| 95 * Individual test options |
| 96 */ |
| 97 options->fft_log_size_ = 4; |
| 98 options->scale_factor_ = 0; |
| 99 options->signal_type_ = 0; |
| 100 options->signal_value_ = 1024; |
| 101 options->signal_value_given_ = 0; |
| 102 } |
| 103 |
| 104 /* |
| 105 * Print values of command line options, for debugging. |
| 106 */ |
| 107 void DumpOptions(FILE* f, const struct Options* options) { |
| 108 fprintf(f, "real_only = %d\n", options->real_only_); |
| 109 fprintf(f, "verbose = %d\n", options->verbose_); |
| 110 fprintf(f, "test_mode = %d\n", options->test_mode_); |
| 111 fprintf(f, "do_forward_tests = %d\n", options->do_forward_tests_); |
| 112 fprintf(f, "do_inverse_tests = %d\n", options->do_inverse_tests_); |
| 113 fprintf(f, "min_fft_order = %d\n", options->min_fft_order_); |
| 114 fprintf(f, "max_fft_order = %d\n", options->max_fft_order_); |
| 115 fprintf(f, "fft_log_size = %d\n", options->fft_log_size_); |
| 116 fprintf(f, "scale_factor = %d\n", options->scale_factor_); |
| 117 fprintf(f, "signal_type = %d\n", options->signal_type_); |
| 118 fprintf(f, "signal_value = %g\n", options->signal_value_); |
| 119 fprintf(f, "signal_value_given = %d\n", options->signal_value_given_); |
| 120 } |
| 121 |
| 122 /* |
| 123 * Process command line options, returning the values in |options|. |
| 124 */ |
| 125 void ProcessCommandLine(struct Options *options, int argc, char* argv[], |
| 126 const char* summary) { |
| 127 int opt; |
| 128 int max_fft_order = options->max_fft_order_; |
| 129 |
| 130 options->signal_value_given_ = 0; |
| 131 |
| 132 while ((opt = getopt(argc, argv, "hTFIn:s:S:g:v:m:M:")) != -1) { |
| 133 switch (opt) { |
| 134 case 'h': |
| 135 usage(argv[0], options->real_only_, max_fft_order, summary); |
| 136 break; |
| 137 case 'T': |
| 138 options->test_mode_ = 0; |
| 139 break; |
| 140 case 'F': |
| 141 options->do_forward_tests_ = 0; |
| 142 break; |
| 143 case 'I': |
| 144 options->do_inverse_tests_ = 0; |
| 145 break; |
| 146 case 'm': |
| 147 options->min_fft_order_ = atoi(optarg); |
| 148 break; |
| 149 case 'M': |
| 150 options->max_fft_order_ = atoi(optarg); |
| 151 break; |
| 152 case 'n': |
| 153 options->fft_log_size_ = atoi(optarg); |
| 154 break; |
| 155 case 'S': |
| 156 options->signal_value_ = atof(optarg); |
| 157 options->signal_value_given_ = 1; |
| 158 break; |
| 159 case 's': |
| 160 options->scale_factor_ = atoi(optarg); |
| 161 break; |
| 162 case 'g': |
| 163 options->signal_type_ = atoi(optarg); |
| 164 break; |
| 165 case 'v': |
| 166 options->verbose_ = atoi(optarg); |
| 167 break; |
| 168 default: |
| 169 usage(argv[0], options->real_only_, max_fft_order, summary); |
| 170 break; |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 /* |
| 176 * Return true if the given test is known to fail. The array of known |
| 177 * failures is in |knownFailures|. The FFT order is |fft_order|, |
| 178 * |is_inverse_fft| is true, if the test fails for the inverse FFT |
| 179 * (otherwise for forward FFT), and |signal_type| specifies the test |
| 180 * signal used. |
| 181 */ |
| 182 int IsKnownFailure(int fft_order, int is_inverse_fft, int signal_type, |
| 183 struct KnownTestFailures* known_failures) { |
| 184 if (known_failures) { |
| 185 /* |
| 186 * Look through array of known failures and see if an FFT |
| 187 * (forward or inverse) of the given order and signal type |
| 188 * matches. Return true if so. |
| 189 */ |
| 190 while (known_failures->fft_order_ > 0) { |
| 191 if ((fft_order == known_failures->fft_order_) |
| 192 && (is_inverse_fft == known_failures->is_inverse_fft_test_) |
| 193 && (signal_type == known_failures->signal_type_)) { |
| 194 return 1; |
| 195 } |
| 196 ++known_failures; |
| 197 } |
| 198 } |
| 199 return 0; |
| 200 } |
| 201 |
| 202 /* |
| 203 * Run a set of tests, printing out the result of each test. |
| 204 */ |
| 205 void RunTests(struct TestResult* result, |
| 206 float (*test_function)(int, int, float, struct SnrResult*), |
| 207 const char* id, |
| 208 int is_inverse_test, |
| 209 const struct TestInfo* info, |
| 210 float snr_threshold) { |
| 211 int fft_order; |
| 212 int signal_type; |
| 213 float snr; |
| 214 int tests = 0; |
| 215 int failures = 0; |
| 216 int expected_failures = 0; |
| 217 float min_snr = 1e10; |
| 218 struct SnrResult snrResults; |
| 219 |
| 220 for (fft_order = info->min_fft_order_; fft_order <= info->max_fft_order_; |
| 221 ++fft_order) { |
| 222 for (signal_type = 0; signal_type < MaxSignalType(info->real_only_); |
| 223 ++signal_type) { |
| 224 int known_failure = 0; |
| 225 int test_failed = 0; |
| 226 ++tests; |
| 227 snr = test_function(fft_order, signal_type, 1024.0, &snrResults); |
| 228 if (snr < min_snr) |
| 229 min_snr = snr; |
| 230 known_failure = IsKnownFailure(fft_order, is_inverse_test, |
| 231 signal_type, info->known_failures_); |
| 232 if (snr < snr_threshold) { |
| 233 ++failures; |
| 234 test_failed = 1; |
| 235 if (known_failure) { |
| 236 ++expected_failures; |
| 237 printf(" *FAILED: %s ", id); |
| 238 } else { |
| 239 printf("**FAILED: %s ", id); |
| 240 } |
| 241 } else { |
| 242 test_failed = 0; |
| 243 printf(" PASSED: %s ", id); |
| 244 } |
| 245 printf("order %2d signal %d: SNR = %9.3f", |
| 246 fft_order, signal_type, snr); |
| 247 if (known_failure) { |
| 248 if (test_failed) { |
| 249 printf(" (expected failure)"); |
| 250 } else { |
| 251 printf(" (**Expected to fail, but passed)"); |
| 252 } |
| 253 } |
| 254 printf("\n"); |
| 255 } |
| 256 } |
| 257 |
| 258 printf("%sSummary: %d %s tests failed out of %d tests. " |
| 259 "(Success rate %.2f%%.)\n", |
| 260 failures ? "**" : "", |
| 261 failures, |
| 262 id, |
| 263 tests, |
| 264 (100.0 * (tests - failures)) / tests); |
| 265 if (expected_failures) |
| 266 printf(" (%d expected failures)\n", expected_failures); |
| 267 printf(" (Minimum SNR = %.3f dB)\n", min_snr); |
| 268 |
| 269 result->failed_count_ = failures; |
| 270 result->test_count_ = tests; |
| 271 result->expected_failure_count_ = expected_failures; |
| 272 result->min_snr_ = min_snr; |
| 273 } |
| 274 |
| 275 /* |
| 276 * For all FFT orders and signal types, run the forward FFT. |
| 277 * runOneForwardTest must be defined to compute the forward FFT and |
| 278 * return the SNR beween the actual and expected FFT. |
| 279 * |
| 280 * Also finds the minium SNR from all of the tests and returns the |
| 281 * minimum SNR value. |
| 282 */ |
| 283 void RunForwardTests(struct TestResult* result, const struct TestInfo* info, |
| 284 float snr_threshold) { |
| 285 RunTests(result, RunOneForwardTest, "FwdFFT", 0, info, snr_threshold); |
| 286 } |
| 287 |
| 288 /* |
| 289 * For all FFT orders and signal types, run the inverse FFT. |
| 290 * runOneInverseTest must be defined to compute the forward FFT and |
| 291 * return the SNR beween the actual and expected FFT. |
| 292 * |
| 293 * Also finds the minium SNR from all of the tests and returns the |
| 294 * minimum SNR value. |
| 295 */ |
| 296 void RunInverseTests(struct TestResult* result, const struct TestInfo* info, |
| 297 float snr_threshold) { |
| 298 RunTests(result, RunOneInverseTest, "InvFFT", 1, info, snr_threshold); |
| 299 } |
| 300 |
| 301 /* |
| 302 * Run all forward and inverse FFT tests, printing a summary of the |
| 303 * results. |
| 304 */ |
| 305 void RunAllTests(const struct TestInfo* info) { |
| 306 int failed; |
| 307 int total; |
| 308 float min_forward_snr; |
| 309 float min_inverse_snr; |
| 310 struct TestResult forward_results; |
| 311 struct TestResult inverse_results; |
| 312 |
| 313 if (info->do_forward_tests_) |
| 314 RunForwardTests(&forward_results, info, info->forward_threshold_); |
| 315 if (info->do_inverse_tests_) |
| 316 RunInverseTests(&inverse_results, info, info->inverse_threshold_); |
| 317 |
| 318 failed = forward_results.failed_count_ + inverse_results.failed_count_; |
| 319 total = forward_results.test_count_ + inverse_results.test_count_; |
| 320 min_forward_snr = forward_results.min_snr_; |
| 321 min_inverse_snr = inverse_results.min_snr_; |
| 322 |
| 323 if (total) { |
| 324 printf("%sTotal: %d tests failed out of %d tests. " |
| 325 "(Success rate = %.2f%%.)\n", |
| 326 failed ? "**" : "", |
| 327 failed, |
| 328 total, |
| 329 (100.0 * (total - failed)) / total); |
| 330 if (forward_results.expected_failure_count_ |
| 331 + inverse_results.expected_failure_count_) { |
| 332 printf(" (%d expected failures)\n", |
| 333 forward_results.expected_failure_count_ |
| 334 + inverse_results.expected_failure_count_); |
| 335 } |
| 336 printf(" Min forward SNR = %.3f dB, min inverse SNR = %.3f dB\n", |
| 337 min_forward_snr, |
| 338 min_inverse_snr); |
| 339 } else { |
| 340 printf("No tests run\n"); |
| 341 } |
| 342 } |
| 343 |
| 344 /* |
| 345 * Print the contents of an array to stdout, one element per line. |
| 346 * |array_name| is the name of the array to be used in the header |
| 347 * line. |
| 348 * |
| 349 * Arrays with elements of type OMX_S16, OMX_S32, OMX_SC32, OMX_F32, |
| 350 * and OMX_FC32 are supported. |
| 351 */ |
| 352 void DumpArrayReal16(const char* array_name, int count, |
| 353 const OMX_S16* array) { |
| 354 int n; |
| 355 |
| 356 printf("%4s\t%5s[n]\n", "n", array_name); |
| 357 for (n = 0; n < count; ++n) { |
| 358 printf("%4d\t%8d\n", n, array[n]); |
| 359 } |
| 360 } |
| 361 |
| 362 void DumpArrayReal32(const char* array_name, int count, const OMX_S32* array) { |
| 363 int n; |
| 364 |
| 365 printf("%4s\t%5s[n]\n", "n", array_name); |
| 366 for (n = 0; n < count; ++n) { |
| 367 printf("%4d\t%8d\n", n, array[n]); |
| 368 } |
| 369 } |
| 370 |
| 371 void DumpArrayComplex32(const char* array_name, int count, |
| 372 const OMX_SC32* array) { |
| 373 int n; |
| 374 |
| 375 printf("%4s\t%10s.re[n]\t%10s.im[n]\n", "n", array_name); |
| 376 for (n = 0; n < count; ++n) { |
| 377 printf("%4d\t%16d\t%16d\n", n, array[n].Re, array[n].Im); |
| 378 } |
| 379 } |
| 380 |
| 381 void DumpArrayComplex16(const char* array_name, int count, |
| 382 const OMX_SC16* array) { |
| 383 int n; |
| 384 |
| 385 printf("%4s\t%10s.re[n]\t%10s.im[n]\n", "n", array_name); |
| 386 for (n = 0; n < count; ++n) { |
| 387 printf("%4d\t%16d\t%16d\n", n, array[n].Re, array[n].Im); |
| 388 } |
| 389 } |
| 390 |
| 391 void DumpArrayFloat(const char* array_name, int count, const OMX_F32* array) { |
| 392 int n; |
| 393 |
| 394 printf("%4s\t%13s[n]\n", "n", array_name); |
| 395 for (n = 0; n < count; ++n) { |
| 396 printf("%4d\t%16g\n", n, array[n]); |
| 397 } |
| 398 } |
| 399 |
| 400 void DumpArrayComplexFloat(const char* array_name, int count, |
| 401 const OMX_FC32* array) { |
| 402 int n; |
| 403 |
| 404 printf("%4s\t%10s.re[n]\t%10s.im[n]\n", "n", array_name, array_name); |
| 405 for (n = 0; n < count; ++n) { |
| 406 printf("%4d\t%16g\t%16g\n", n, array[n].Re, array[n].Im); |
| 407 } |
| 408 } |
OLD | NEW |