Home | History | Annotate | Download | only in test
      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 
     11 #include <math.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <time.h>
     15 #include <unistd.h>
     16 
     17 #include "dl/sp/api/armSP.h"
     18 #include "dl/sp/api/omxSP.h"
     19 #include "dl/sp/src/test/aligned_ptr.h"
     20 #include "dl/sp/src/test/compare.h"
     21 #include "dl/sp/src/test/gensig.h"
     22 #include "dl/sp/src/test/test_util.h"
     23 
     24 #define MAX_FFT_ORDER   12
     25 
     26 int verbose = 0;
     27 int signal_value = 32767;
     28 int scale_factor = 0;
     29 
     30 int main(int argc, char* argv[]) {
     31   struct Options options;
     32   struct TestInfo info;
     33 
     34   SetDefaultOptions(&options, 1, MAX_FFT_ORDER);
     35 
     36   options.signal_value_ = signal_value;
     37   options.scale_factor_ = scale_factor;
     38 
     39   ProcessCommandLine(&options, argc, argv, "Test forward and inverse real 16 \
     40                      -bit fixed-point FFT, with 16-bit complex FFT routines\n");
     41 
     42   verbose = options.verbose_;
     43   signal_value = options.signal_value_;
     44   scale_factor = options.scale_factor_;
     45 
     46   if (verbose > 255)
     47     DumpOptions(stderr, &options);
     48 
     49   info.real_only_ = options.real_only_;
     50   info.max_fft_order_ = options.max_fft_order_;
     51   info.min_fft_order_ = options.min_fft_order_;
     52   info.do_forward_tests_ = options.do_forward_tests_;
     53   info.do_inverse_tests_ = options.do_inverse_tests_;
     54   /* No known failures */
     55   info.known_failures_ = 0;
     56   info.forward_threshold_ = 45;
     57   info.inverse_threshold_ = 14;
     58 
     59   if (options.test_mode_) {
     60     RunAllTests(&info);
     61   } else {
     62     TestOneFFT(options.fft_log_size_,
     63                options.signal_type_,
     64                options.signal_value_,
     65                &info,
     66                "16-bit Real FFT using 16-bit complex FFT");
     67   }
     68 
     69   return 0;
     70 }
     71 
     72 void GenerateSignal(struct ComplexFloat* fft,
     73                     float* x_true, int size, int sigtype) {
     74   int k;
     75   struct ComplexFloat *test_signal;
     76 
     77   test_signal = (struct ComplexFloat*) malloc(sizeof(*test_signal) * size);
     78   GenerateTestSignalAndFFT(test_signal, fft, size, sigtype, signal_value, 1);
     79 
     80   /*
     81    * Convert the complex result to what we want
     82    */
     83 
     84   for (k = 0; k < size; ++k) {
     85     x_true[k] = test_signal[k].Re;
     86   }
     87 
     88   free(test_signal);
     89 }
     90 
     91 float RunOneForwardTest(int fft_log_size, int signal_type,
     92                         float unused_signal_value,
     93                         struct SnrResult* snr) {
     94   OMX_S16* x;
     95   OMX_SC16* y;
     96 
     97   struct AlignedPtr* x_aligned;
     98   struct AlignedPtr* y_aligned;
     99 
    100   float* x_true;
    101   struct ComplexFloat* y_true;
    102   OMX_SC16* y_scaled;
    103 
    104   OMX_INT n, fft_spec_buffer_size;
    105   OMXResult status;
    106   OMXFFTSpec_R_S16 * fft_fwd_spec = NULL;
    107   int fft_size;
    108 
    109   /*
    110    * To get good FFT results, set the forward FFT scale factor
    111    * to be the same as the order.
    112    */
    113   scale_factor = fft_log_size;
    114 
    115   fft_size = 1 << fft_log_size;
    116 
    117   status = omxSP_FFTGetBufSize_R_S16(fft_log_size, &fft_spec_buffer_size);
    118   if (verbose > 63) {
    119     printf("fft_spec_buffer_size = %d\n", fft_spec_buffer_size);
    120   }
    121 
    122   fft_fwd_spec = (OMXFFTSpec_R_S16*) malloc(fft_spec_buffer_size);
    123   status = omxSP_FFTInit_R_S16(fft_fwd_spec, fft_log_size);
    124   if (status) {
    125     fprintf(stderr, "Failed to init forward FFT:  status = %d\n", status);
    126     exit(1);
    127   }
    128 
    129   x_aligned = AllocAlignedPointer(32, sizeof(*x) * fft_size);
    130   y_aligned = AllocAlignedPointer(32, sizeof(*y) * (fft_size + 2));
    131 
    132   x = x_aligned->aligned_pointer_;
    133   y = y_aligned->aligned_pointer_;
    134 
    135   x_true = (float*) malloc(sizeof(*x_true) * fft_size);
    136   y_true = (struct ComplexFloat*) malloc(sizeof(*y_true) * (fft_size / 2 + 1));
    137   y_scaled = (OMX_SC16*) malloc(sizeof(*y_true) * (fft_size / 2 + 1));
    138 
    139   GenerateSignal(y_true, x_true, fft_size, signal_type);
    140   for (n = 0; n < fft_size; ++n) {
    141     x[n] = 0.5 + x_true[n];
    142   }
    143 
    144   {
    145     float scale = 1 << fft_log_size;
    146 
    147     for (n = 0; n < fft_size; ++n) {
    148       y_scaled[n].Re = 0.5 + y_true[n].Re / scale;
    149       y_scaled[n].Im = 0.5 + y_true[n].Im / scale;
    150     }
    151   }
    152 
    153   if (verbose > 63) {
    154     printf("Signal\n");
    155     DumpArrayReal16("x", fft_size, x);
    156 
    157     printf("Expected FFT output\n");
    158     DumpArrayComplex16("y", fft_size / 2 + 1, y_scaled);
    159   }
    160 
    161   status = omxSP_FFTFwd_RToCCS_S16_Sfs(x, (OMX_S16*) y, fft_fwd_spec, scale_factor);
    162   if (status) {
    163     fprintf(stderr, "Forward FFT failed: status = %d\n", status);
    164     exit(1);
    165   }
    166 
    167   if (verbose > 63) {
    168     printf("FFT Output\n");
    169     DumpArrayComplex16("y", fft_size / 2 + 1, y);
    170   }
    171 
    172   CompareComplex16(snr, y, y_scaled, fft_size / 2 + 1);
    173 
    174   FreeAlignedPointer(x_aligned);
    175   FreeAlignedPointer(y_aligned);
    176   free(fft_fwd_spec);
    177 
    178   return snr->complex_snr_;
    179 }
    180 
    181 float RunOneInverseTest(int fft_log_size, int signal_type,
    182                         float unused_signal_value,
    183                         struct SnrResult* snr) {
    184   OMX_S16* x_scaled;
    185   OMX_S16* z;
    186   OMX_SC16* y;
    187   OMX_SC16* y_scaled;
    188 
    189   struct AlignedPtr* y_aligned;
    190   struct AlignedPtr* z_aligned;
    191 
    192   float* x_true;
    193   struct ComplexFloat* y_true;
    194 
    195   OMX_INT n, fft_spec_buffer_size;
    196   OMXResult status;
    197   OMXFFTSpec_R_S16 * fft_inv_spec = NULL;
    198   int fft_size;
    199 
    200   fft_size = 1 << fft_log_size;
    201 
    202   status = omxSP_FFTGetBufSize_R_S16(fft_log_size, &fft_spec_buffer_size);
    203   if (verbose > 3) {
    204     printf("fft_spec_buffer_size = %d\n", fft_spec_buffer_size);
    205   }
    206 
    207   fft_inv_spec = (OMXFFTSpec_R_S16*)malloc(fft_spec_buffer_size);
    208   status = omxSP_FFTInit_R_S16(fft_inv_spec, fft_log_size);
    209   if (status) {
    210     fprintf(stderr, "Failed to init backward FFT:  status = %d\n", status);
    211     exit(1);
    212   }
    213 
    214   y_aligned = AllocAlignedPointer(32, sizeof(*y) * (fft_size / 2 + 1));
    215   z_aligned = AllocAlignedPointer(32, sizeof(*z) * fft_size);
    216 
    217   x_true = (float*) malloc(sizeof(*x_true) * fft_size);
    218   x_scaled = (OMX_S16*) malloc(sizeof(*x_scaled) * fft_size);
    219   y_true = (struct ComplexFloat*) malloc(sizeof(*y_true) * fft_size);
    220   y_scaled = y_aligned->aligned_pointer_;
    221   z = z_aligned->aligned_pointer_;
    222 
    223   GenerateSignal(y_true, x_true, fft_size, signal_type);
    224 
    225   {
    226     /*
    227      * To get max accuracy, scale the input to the inverse FFT up
    228      * to use as many bits as we can.
    229      */
    230     float scale = 1;
    231     float max = 0;
    232 
    233     for (n = 0; n < fft_size / 2 + 1; ++n) {
    234       float val;
    235       val = fabs(y_true[n].Re);
    236       if (val > max) {
    237         max = val;
    238       }
    239       val = fabs(y_true[n].Im);
    240       if (val > max) {
    241         max = val;
    242       }
    243     }
    244 
    245     scale = 16384 / max;
    246     if (verbose > 63)
    247       printf("Inverse FFT input scaled factor %g\n", scale);
    248 
    249     /*
    250      * Scale both the true FFT signal and the input so we can
    251      * compare them correctly later
    252      */
    253     for (n = 0; n < fft_size / 2 + 1; ++n) {
    254       y_scaled[n].Re = (OMX_S16)(0.5 + y_true[n].Re * scale);
    255       y_scaled[n].Im = (OMX_S16)(0.5 + y_true[n].Im * scale);
    256     }
    257     for (n = 0; n < fft_size; ++n) {
    258       x_scaled[n] = 0.5 + x_true[n] * scale;
    259     }
    260   }
    261 
    262 
    263   if (verbose > 63) {
    264     printf("Inverse FFT Input Signal\n");
    265     DumpArrayComplex16("y", fft_size / 2 + 1, y_scaled);
    266 
    267     printf("Expected Inverse FFT output\n");
    268     DumpArrayReal16("x", fft_size, x_scaled);
    269   }
    270 
    271   status = omxSP_FFTInv_CCSToR_S16_Sfs((OMX_S16 const *)y_scaled, z, fft_inv_spec, 0);
    272   if (status) {
    273     fprintf(stderr, "Inverse FFT failed: status = %d\n", status);
    274     exit(1);
    275   }
    276 
    277   if (verbose > 63) {
    278     printf("Actual Inverse FFT Output\n");
    279     DumpArrayReal16("z", fft_size, z);
    280   }
    281 
    282   CompareReal16(snr, z, x_scaled, fft_size);
    283 
    284   FreeAlignedPointer(y_aligned);
    285   FreeAlignedPointer(z_aligned);
    286   free(fft_inv_spec);
    287 
    288   return snr->real_snr_;
    289 }
    290