Files
qtmultimedia/demos/spectrum/3rdparty/fftreal/TestAccuracy.hpp
Qt by Nokia 60941c2741 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

473 lines
10 KiB
C++

/*****************************************************************************
TestAccuracy.hpp
Copyright (c) 2005 Laurent de Soras
--- Legal stuff ---
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*Tab=3***********************************************************************/
#if defined (TestAccuracy_CURRENT_CODEHEADER)
#error Recursive inclusion of TestAccuracy code header.
#endif
#define TestAccuracy_CURRENT_CODEHEADER
#if ! defined (TestAccuracy_CODEHEADER_INCLUDED)
#define TestAccuracy_CODEHEADER_INCLUDED
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
#include "def.h"
#include "test_fnc.h"
#include "TestWhiteNoiseGen.h"
#include <typeinfo>
#include <vector>
#include <cmath>
#include <cstdio>
static const double TestAccuracy_LN10 = 2.3025850929940456840179914546844;
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
template <class FO>
int TestAccuracy <FO>::perform_test_single_object (FO &fft)
{
assert (&fft != 0);
using namespace std;
int ret_val = 0;
const std::type_info & ti = typeid (fft);
const char * class_name_0 = ti.name ();
if (ret_val == 0)
{
ret_val = perform_test_d (fft, class_name_0);
}
if (ret_val == 0)
{
ret_val = perform_test_i (fft, class_name_0);
}
if (ret_val == 0)
{
ret_val = perform_test_di (fft, class_name_0);
}
if (ret_val == 0)
{
printf ("\n");
}
return (ret_val);
}
template <class FO>
int TestAccuracy <FO>::perform_test_d (FO &fft, const char *class_name_0)
{
assert (&fft != 0);
assert (class_name_0 != 0);
using namespace std;
int ret_val = 0;
const long len = fft.get_length ();
const long nbr_tests = limit (
NBR_ACC_TESTS / len / len,
1L,
static_cast <long> (MAX_NBR_TESTS)
);
printf ("Testing %s::do_fft () [%ld samples]... ", class_name_0, len);
fflush (stdout);
TestWhiteNoiseGen <DataType> noise;
std::vector <DataType> x (len);
std::vector <DataType> s1 (len);
std::vector <DataType> s2 (len);
BigFloat err_avg = 0;
for (long test = 0; test < nbr_tests && ret_val == 0; ++ test)
{
noise.generate (&x [0], len);
fft.do_fft (&s1 [0], &x [0]);
compute_tf (&s2 [0], &x [0], len);
BigFloat max_err;
compare_vect_display (&s1 [0], &s2 [0], len, max_err);
err_avg += max_err;
}
err_avg /= NBR_ACC_TESTS;
printf ("done.\n");
printf (
"Average maximum error: %.6f %% (%f dB)\n",
static_cast <double> (err_avg * 100),
static_cast <double> ((20 / TestAccuracy_LN10) * log (err_avg))
);
return (ret_val);
}
template <class FO>
int TestAccuracy <FO>::perform_test_i (FO &fft, const char *class_name_0)
{
assert (&fft != 0);
assert (class_name_0 != 0);
using namespace std;
int ret_val = 0;
const long len = fft.get_length ();
const long nbr_tests = limit (
NBR_ACC_TESTS / len / len,
10L,
static_cast <long> (MAX_NBR_TESTS)
);
printf ("Testing %s::do_ifft () [%ld samples]... ", class_name_0, len);
fflush (stdout);
TestWhiteNoiseGen <DataType> noise;
std::vector <DataType> s (len);
std::vector <DataType> x1 (len);
std::vector <DataType> x2 (len);
BigFloat err_avg = 0;
for (long test = 0; test < nbr_tests && ret_val == 0; ++ test)
{
noise.generate (&s [0], len);
fft.do_ifft (&s [0], &x1 [0]);
compute_itf (&x2 [0], &s [0], len);
BigFloat max_err;
compare_vect_display (&x1 [0], &x2 [0], len, max_err);
err_avg += max_err;
}
err_avg /= NBR_ACC_TESTS;
printf ("done.\n");
printf (
"Average maximum error: %.6f %% (%f dB)\n",
static_cast <double> (err_avg * 100),
static_cast <double> ((20 / TestAccuracy_LN10) * log (err_avg))
);
return (ret_val);
}
template <class FO>
int TestAccuracy <FO>::perform_test_di (FO &fft, const char *class_name_0)
{
assert (&fft != 0);
assert (class_name_0 != 0);
using namespace std;
int ret_val = 0;
const long len = fft.get_length ();
const long nbr_tests = limit (
NBR_ACC_TESTS / len / len,
1L,
static_cast <long> (MAX_NBR_TESTS)
);
printf (
"Testing %s::do_fft () / do_ifft () / rescale () [%ld samples]... ",
class_name_0,
len
);
fflush (stdout);
TestWhiteNoiseGen <DataType> noise;
std::vector <DataType> x (len);
std::vector <DataType> s (len);
std::vector <DataType> y (len);
BigFloat err_avg = 0;
for (long test = 0; test < nbr_tests && ret_val == 0; ++ test)
{
noise.generate (&x [0], len);
fft.do_fft (&s [0], &x [0]);
fft.do_ifft (&s [0], &y [0]);
fft.rescale (&y [0]);
BigFloat max_err;
compare_vect_display (&x [0], &y [0], len, max_err);
err_avg += max_err;
}
err_avg /= NBR_ACC_TESTS;
printf ("done.\n");
printf (
"Average maximum error: %.6f %% (%f dB)\n",
static_cast <double> (err_avg * 100),
static_cast <double> ((20 / TestAccuracy_LN10) * log (err_avg))
);
return (ret_val);
}
/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
// Positive transform
template <class FO>
void TestAccuracy <FO>::compute_tf (DataType s [], const DataType x [], long length)
{
assert (s != 0);
assert (x != 0);
assert (length >= 2);
assert ((length & 1) == 0);
const long nbr_bins = length >> 1;
// DC and Nyquist
BigFloat dc = 0;
BigFloat ny = 0;
for (long pos = 0; pos < length; pos += 2)
{
const BigFloat even = x [pos ];
const BigFloat odd = x [pos + 1];
dc += even + odd;
ny += even - odd;
}
s [0 ] = static_cast <DataType> (dc);
s [nbr_bins] = static_cast <DataType> (ny);
// Regular bins
for (long bin = 1; bin < nbr_bins; ++ bin)
{
BigFloat sum_r = 0;
BigFloat sum_i = 0;
const BigFloat m = bin * static_cast <BigFloat> (2 * PI) / length;
for (long pos = 0; pos < length; ++pos)
{
using namespace std;
const BigFloat phase = pos * m;
const BigFloat e_r = cos (phase);
const BigFloat e_i = sin (phase);
sum_r += x [pos] * e_r;
sum_i += x [pos] * e_i;
}
s [ bin] = static_cast <DataType> (sum_r);
s [nbr_bins + bin] = static_cast <DataType> (sum_i);
}
}
// Negative transform
template <class FO>
void TestAccuracy <FO>::compute_itf (DataType x [], const DataType s [], long length)
{
assert (s != 0);
assert (x != 0);
assert (length >= 2);
assert ((length & 1) == 0);
const long nbr_bins = length >> 1;
// DC and Nyquist
BigFloat dc = s [0 ];
BigFloat ny = s [nbr_bins];
// Regular bins
for (long pos = 0; pos < length; ++pos)
{
BigFloat sum = dc + ny * (1 - 2 * (pos & 1));
const BigFloat m = pos * static_cast <BigFloat> (-2 * PI) / length;
for (long bin = 1; bin < nbr_bins; ++ bin)
{
using namespace std;
const BigFloat phase = bin * m;
const BigFloat e_r = cos (phase);
const BigFloat e_i = sin (phase);
sum += 2 * ( e_r * s [bin ]
- e_i * s [bin + nbr_bins]);
}
x [pos] = static_cast <DataType> (sum);
}
}
template <class FO>
int TestAccuracy <FO>::compare_vect_display (const DataType x_ptr [], const DataType y_ptr [], long len, BigFloat &max_err_rel)
{
assert (x_ptr != 0);
assert (y_ptr != 0);
assert (len > 0);
assert (&max_err_rel != 0);
using namespace std;
int ret_val = 0;
BigFloat power = compute_power (&x_ptr [0], &y_ptr [0], len);
BigFloat power_dif;
long max_err_pos;
compare_vect (&x_ptr [0], &y_ptr [0], power_dif, max_err_pos, len);
if (power == 0)
{
power = power_dif;
}
const BigFloat power_err_rel = power_dif / power;
BigFloat max_err = 0;
max_err_rel = 0;
if (max_err_pos >= 0)
{
max_err = y_ptr [max_err_pos] - x_ptr [max_err_pos];
max_err_rel = 2 * fabs (max_err) / ( fabs (y_ptr [max_err_pos])
+ fabs (x_ptr [max_err_pos]));
}
if (power_err_rel > 0.001)
{
printf ("Power error : %f (%.6f %%)\n",
static_cast <double> (power_err_rel),
static_cast <double> (power_err_rel * 100)
);
if (max_err_pos >= 0)
{
printf (
"Maximum error: %f - %f = %f (%f)\n",
static_cast <double> (y_ptr [max_err_pos]),
static_cast <double> (x_ptr [max_err_pos]),
static_cast <double> (max_err),
static_cast <double> (max_err_pos)
);
}
}
return (ret_val);
}
template <class FO>
typename TestAccuracy <FO>::BigFloat TestAccuracy <FO>::compute_power (const DataType x_ptr [], long len)
{
assert (x_ptr != 0);
assert (len > 0);
BigFloat power = 0;
for (long pos = 0; pos < len; ++pos)
{
const BigFloat val = x_ptr [pos];
power += val * val;
}
using namespace std;
power = sqrt (power) / len;
return (power);
}
template <class FO>
typename TestAccuracy <FO>::BigFloat TestAccuracy <FO>::compute_power (const DataType x_ptr [], const DataType y_ptr [], long len)
{
assert (x_ptr != 0);
assert (y_ptr != 0);
assert (len > 0);
return ((compute_power (x_ptr, len) + compute_power (y_ptr, len)) * 0.5);
}
template <class FO>
void TestAccuracy <FO>::compare_vect (const DataType x_ptr [], const DataType y_ptr [], BigFloat &power, long &max_err_pos, long len)
{
assert (x_ptr != 0);
assert (y_ptr != 0);
assert (len > 0);
assert (&power != 0);
assert (&max_err_pos != 0);
power = 0;
BigFloat max_dif2 = 0;
max_err_pos = -1;
for (long pos = 0; pos < len; ++pos)
{
const BigFloat x = x_ptr [pos];
const BigFloat y = y_ptr [pos];
const BigFloat dif = y - x;
const BigFloat dif2 = dif * dif;
power += dif2;
if (dif2 > max_dif2)
{
max_err_pos = pos;
max_dif2 = dif2;
}
}
using namespace std;
power = sqrt (power) / len;
}
#endif // TestAccuracy_CODEHEADER_INCLUDED
#undef TestAccuracy_CURRENT_CODEHEADER
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/