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
26int verbose = 0;
27int signal_value = 32767;
28int scale_factor = 0;
29
30int 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
72void 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
91float 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
181float 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