You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
572 lines
19 KiB
572 lines
19 KiB
/*
|
|
* Copyright 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "audio_utils_statistics_tests"
|
|
#include <audio_utils/Statistics.h>
|
|
|
|
#include <random>
|
|
#include <stdio.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
// create uniform distribution
|
|
template <typename T, typename V>
|
|
static void initUniform(V& data, T rangeMin, T rangeMax) {
|
|
const size_t count = data.capacity();
|
|
std::minstd_rand gen(count);
|
|
std::uniform_real_distribution<T> dis(rangeMin, rangeMax);
|
|
|
|
// for_each works for scalars
|
|
for (auto& datum : data) {
|
|
android::audio_utils::for_each(datum, [&](T &value) { return value = dis(gen);});
|
|
}
|
|
}
|
|
|
|
// create gaussian distribution
|
|
template <typename T, typename V>
|
|
static void initNormal(V& data, T mean, T stddev) {
|
|
const size_t count = data.capacity();
|
|
std::minstd_rand gen(count);
|
|
|
|
// values near the mean are the most likely
|
|
// standard deviation affects the dispersion of generated values from the mean
|
|
std::normal_distribution<> dis{mean, stddev};
|
|
|
|
// for_each works for scalars
|
|
for (auto& datum : data) {
|
|
android::audio_utils::for_each(datum, [&](T &value) { return value = dis(gen);});
|
|
}
|
|
}
|
|
|
|
// Used to create compile-time reference constants for variance testing.
|
|
template <typename T>
|
|
class ConstexprStatistics {
|
|
public:
|
|
template <size_t N>
|
|
explicit constexpr ConstexprStatistics(const T (&a)[N])
|
|
: mN{N}
|
|
, mMax{android::audio_utils::max(a)}
|
|
, mMin{android::audio_utils::min(a)}
|
|
, mMean{android::audio_utils::sum(a) / mN}
|
|
, mM2{android::audio_utils::sumSqDiff(a, mMean)}
|
|
, mPopVariance{mM2 / mN}
|
|
, mPopStdDev{android::audio_utils::sqrt_constexpr(mPopVariance)}
|
|
, mVariance{mM2 / (mN - 1)}
|
|
, mStdDev{android::audio_utils::sqrt_constexpr(mVariance)}
|
|
{ }
|
|
|
|
constexpr int64_t getN() const { return mN; }
|
|
constexpr T getMin() const { return mMin; }
|
|
constexpr T getMax() const { return mMax; }
|
|
constexpr double getWeight() const { return (double)mN; }
|
|
constexpr double getMean() const { return mMean; }
|
|
constexpr double getVariance() const { return mVariance; }
|
|
constexpr double getStdDev() const { return mStdDev; }
|
|
constexpr double getPopVariance() const { return mPopVariance; }
|
|
constexpr double getPopStdDev() const { return mPopStdDev; }
|
|
|
|
private:
|
|
const size_t mN;
|
|
const T mMax;
|
|
const T mMin;
|
|
const double mMean;
|
|
const double mM2;
|
|
const double mPopVariance;
|
|
const double mPopStdDev;
|
|
const double mVariance;
|
|
const double mStdDev;
|
|
};
|
|
|
|
class StatisticsTest : public testing::TestWithParam<const char *>
|
|
{
|
|
};
|
|
|
|
// find power of 2 that is small enough that it doesn't add to 1. due to finite mantissa.
|
|
template <typename T>
|
|
constexpr T smallp2() {
|
|
T smallOne{};
|
|
for (smallOne = T{1.}; smallOne + T{1.} > T{1.}; smallOne *= T(0.5));
|
|
return smallOne;
|
|
}
|
|
|
|
// Our near expectation is 16x the bit that doesn't fit the mantissa.
|
|
// this works so long as we add values close in exponent with each other
|
|
// realizing that errors accumulate as the sqrt of N (random walk, lln, etc).
|
|
#define TEST_EXPECT_NEAR(e, v) \
|
|
EXPECT_NEAR((e), (v), abs((e) * std::numeric_limits<decltype(e)>::epsilon() * 8))
|
|
|
|
#define PRINT_AND_EXPECT_EQ(expected, expr) { \
|
|
auto value = (expr); \
|
|
printf("(%s): %s\n", #expr, std::to_string(value).c_str()); \
|
|
if ((expected) == (expected)) { EXPECT_EQ((expected), (value)); } \
|
|
EXPECT_EQ((expected) != (expected), (value) != (value)); /* nan check */\
|
|
}
|
|
|
|
#define PRINT_AND_EXPECT_NEAR(expected, expr) { \
|
|
auto ref = (expected); \
|
|
auto value = (expr); \
|
|
printf("(%s): %s\n", #expr, std::to_string(value).c_str()); \
|
|
TEST_EXPECT_NEAR(ref, value); \
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static void verify(const T &stat, const S &refstat) {
|
|
EXPECT_EQ(refstat.getN(), stat.getN());
|
|
EXPECT_EQ(refstat.getMin(), stat.getMin());
|
|
EXPECT_EQ(refstat.getMax(), stat.getMax());
|
|
TEST_EXPECT_NEAR(refstat.getWeight(), stat.getWeight());
|
|
TEST_EXPECT_NEAR(refstat.getMean(), stat.getMean());
|
|
TEST_EXPECT_NEAR(refstat.getVariance(), stat.getVariance());
|
|
TEST_EXPECT_NEAR(refstat.getStdDev(), stat.getStdDev());
|
|
TEST_EXPECT_NEAR(refstat.getPopVariance(), stat.getPopVariance());
|
|
TEST_EXPECT_NEAR(refstat.getPopStdDev(), stat.getPopStdDev());
|
|
}
|
|
|
|
// Test against fixed reference
|
|
|
|
TEST(StatisticsTest, high_precision_sums)
|
|
{
|
|
static const double simple[] = { 1., 2., 3. };
|
|
|
|
double rssum = android::audio_utils::sum<double, double>(simple);
|
|
PRINT_AND_EXPECT_EQ(6., rssum);
|
|
double kssum =
|
|
android::audio_utils::sum<double, android::audio_utils::KahanSum<double>>(simple);
|
|
PRINT_AND_EXPECT_EQ(6., kssum);
|
|
double nmsum =
|
|
android::audio_utils::sum<double, android::audio_utils::NeumaierSum<double>>(simple);
|
|
PRINT_AND_EXPECT_EQ(6., nmsum);
|
|
|
|
double rs{};
|
|
android::audio_utils::KahanSum<double> ks{};
|
|
android::audio_utils::NeumaierSum<double> ns{};
|
|
|
|
// add 1.
|
|
rs += 1.;
|
|
ks += 1.;
|
|
ns += 1.;
|
|
|
|
static constexpr double smallOne = std::numeric_limits<double>::epsilon() * 0.5;
|
|
// add lots of small values
|
|
static const int loop = 1000;
|
|
for (int i = 0; i < loop; ++i) {
|
|
rs += smallOne;
|
|
ks += smallOne;
|
|
ns += smallOne;
|
|
}
|
|
|
|
// remove 1.
|
|
rs += -1.;
|
|
ks += -1.;
|
|
ns += -1.;
|
|
|
|
const double totalAdded = smallOne * loop;
|
|
printf("totalAdded: %lg\n", totalAdded);
|
|
PRINT_AND_EXPECT_EQ(0., rs); // normal count fails
|
|
PRINT_AND_EXPECT_EQ(totalAdded, ks); // kahan succeeds
|
|
PRINT_AND_EXPECT_EQ(totalAdded, ns); // neumaier succeeds
|
|
|
|
// test case where kahan fails and neumaier method succeeds.
|
|
static const double tricky[] = { 1e100, 1., -1e100 };
|
|
|
|
rssum = android::audio_utils::sum<double, double>(tricky);
|
|
PRINT_AND_EXPECT_EQ(0., rssum);
|
|
kssum = android::audio_utils::sum<double, android::audio_utils::KahanSum<double>>(tricky);
|
|
PRINT_AND_EXPECT_EQ(0., kssum);
|
|
nmsum = android::audio_utils::sum<double, android::audio_utils::NeumaierSum<double>>(tricky);
|
|
PRINT_AND_EXPECT_EQ(1., nmsum);
|
|
}
|
|
|
|
TEST(StatisticsTest, minmax_bounds)
|
|
{
|
|
// range based min and max use iterator forms of min and max.
|
|
|
|
static constexpr double one[] = { 1. };
|
|
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
|
android::audio_utils::min(&one[0], &one[0]));
|
|
|
|
PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
|
|
android::audio_utils::max(&one[0], &one[0]));
|
|
|
|
static constexpr int un[] = { 1 };
|
|
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<int>::max(),
|
|
android::audio_utils::min(&un[0], &un[0]));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<int>::min(),
|
|
android::audio_utils::max(&un[0], &un[0]));
|
|
|
|
double nanarray[] = { nan(""), nan(""), nan("") };
|
|
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
|
android::audio_utils::min(nanarray));
|
|
|
|
PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
|
|
android::audio_utils::max(nanarray));
|
|
|
|
android::audio_utils::Statistics<double> s(nanarray);
|
|
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
|
s.getMin());
|
|
|
|
PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
|
|
s.getMax());
|
|
}
|
|
|
|
/*
|
|
TEST(StatisticsTest, sqrt_convergence)
|
|
{
|
|
union {
|
|
int i;
|
|
float f;
|
|
} u;
|
|
|
|
for (int i = 0; i < INT_MAX; ++i) {
|
|
u.i = i;
|
|
const float f = u.f;
|
|
if (!android::audio_utils::isnan(f)) {
|
|
const float sf = android::audio_utils::sqrt(f);
|
|
if ((i & (1 << 16) - 1) == 0) {
|
|
printf("i: %d f:%f sf:%f\n", i, f, sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
TEST(StatisticsTest, minmax_simple_array)
|
|
{
|
|
static constexpr double ary[] = { -1.5, 1.5, -2.5, 2.5 };
|
|
|
|
PRINT_AND_EXPECT_EQ(-2.5, android::audio_utils::min(ary));
|
|
|
|
PRINT_AND_EXPECT_EQ(2.5, android::audio_utils::max(ary));
|
|
|
|
static constexpr int ray[] = { -1, 1, -2, 2 };
|
|
|
|
PRINT_AND_EXPECT_EQ(-2, android::audio_utils::min(ray));
|
|
|
|
PRINT_AND_EXPECT_EQ(2, android::audio_utils::max(ray));
|
|
}
|
|
|
|
TEST(StatisticsTest, sqrt)
|
|
{
|
|
// check doubles
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
|
android::audio_utils::sqrt(std::numeric_limits<double>::infinity()));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nan(""),
|
|
android::audio_utils::sqrt(-std::numeric_limits<double>::infinity()));
|
|
|
|
PRINT_AND_EXPECT_NEAR(sqrt(std::numeric_limits<double>::epsilon()),
|
|
android::audio_utils::sqrt(std::numeric_limits<double>::epsilon()));
|
|
|
|
PRINT_AND_EXPECT_EQ(3.,
|
|
android::audio_utils::sqrt(9.));
|
|
|
|
PRINT_AND_EXPECT_EQ(0.,
|
|
android::audio_utils::sqrt(0.));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nan(""),
|
|
android::audio_utils::sqrt(-1.));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nan(""),
|
|
android::audio_utils::sqrt(std::nan("")));
|
|
|
|
// check floats
|
|
PRINT_AND_EXPECT_EQ(std::numeric_limits<float>::infinity(),
|
|
android::audio_utils::sqrt(std::numeric_limits<float>::infinity()));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nanf(""),
|
|
android::audio_utils::sqrt(-std::numeric_limits<float>::infinity()));
|
|
|
|
PRINT_AND_EXPECT_NEAR(sqrtf(std::numeric_limits<float>::epsilon()),
|
|
android::audio_utils::sqrt(std::numeric_limits<float>::epsilon()));
|
|
|
|
PRINT_AND_EXPECT_EQ(2.f,
|
|
android::audio_utils::sqrt(4.f));
|
|
|
|
PRINT_AND_EXPECT_EQ(0.f,
|
|
android::audio_utils::sqrt(0.f));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nanf(""),
|
|
android::audio_utils::sqrt(-1.f));
|
|
|
|
PRINT_AND_EXPECT_EQ(std::nanf(""),
|
|
android::audio_utils::sqrt(std::nanf("")));
|
|
}
|
|
|
|
TEST(StatisticsTest, stat_reference)
|
|
{
|
|
// fixed reference compile time constants.
|
|
static constexpr double data[] = {0.1, -0.1, 0.2, -0.3};
|
|
static constexpr ConstexprStatistics<double> rstat(data); // use alpha = 1.
|
|
static constexpr android::audio_utils::Statistics<double> stat{data};
|
|
|
|
verify(stat, rstat);
|
|
}
|
|
|
|
TEST(StatisticsTest, stat_variable_alpha)
|
|
{
|
|
constexpr size_t TEST_SIZE = 1 << 20;
|
|
std::vector<double> data(TEST_SIZE);
|
|
std::vector<double> alpha(TEST_SIZE);
|
|
|
|
initUniform(data, -1., 1.);
|
|
initUniform(alpha, .95, .99);
|
|
|
|
android::audio_utils::ReferenceStatistics<double> rstat;
|
|
android::audio_utils::Statistics<double> stat;
|
|
|
|
static_assert(std::is_trivially_copyable<decltype(stat)>::value,
|
|
"basic statistics must be trivially copyable");
|
|
|
|
for (size_t i = 0; i < TEST_SIZE; ++i) {
|
|
rstat.setAlpha(alpha[i]);
|
|
rstat.add(data[i]);
|
|
|
|
stat.setAlpha(alpha[i]);
|
|
stat.add(data[i]);
|
|
}
|
|
|
|
printf("statistics: %s\n", stat.toString().c_str());
|
|
printf("ref statistics: %s\n", rstat.toString().c_str());
|
|
verify(stat, rstat);
|
|
}
|
|
|
|
TEST(StatisticsTest, stat_vector)
|
|
{
|
|
// for operator overloading...
|
|
using namespace android::audio_utils;
|
|
|
|
using data_t = std::tuple<double, double>;
|
|
using covariance_t = std::tuple<double, double, double, double>;
|
|
using covariance_ut_t = std::tuple<double, double, double>;
|
|
|
|
constexpr size_t TEST_SIZE = 1 << 20;
|
|
std::vector<data_t> data(TEST_SIZE);
|
|
// std::vector<double> alpha(TEST_SIZE);
|
|
|
|
initUniform(data, -1., 1.);
|
|
|
|
std::cout << "sample data[0]: " << data[0] << "\n";
|
|
|
|
Statistics<data_t, data_t, data_t, double, double, innerProduct_scalar<data_t>> stat;
|
|
Statistics<data_t, data_t, data_t, double,
|
|
covariance_t, outerProduct_tuple<data_t>> stat_outer;
|
|
Statistics<data_t, data_t, data_t, double,
|
|
covariance_ut_t, outerProduct_UT_tuple<data_t>> stat_outer_ut;
|
|
|
|
using pair_t = std::pair<double, double>;
|
|
std::vector<pair_t> pairs(TEST_SIZE);
|
|
initUniform(pairs, -1., 1.);
|
|
Statistics<pair_t, pair_t, pair_t, double, double, innerProduct_scalar<pair_t>> stat_pair;
|
|
|
|
using array_t = std::array<double, 2>;
|
|
using array_covariance_ut_t = std::array<double, 3>;
|
|
std::vector<array_t> arrays(TEST_SIZE);
|
|
initUniform(arrays, -1., 1.);
|
|
Statistics<array_t, array_t, array_t, double,
|
|
double, innerProduct_scalar<array_t>> stat_array;
|
|
Statistics<array_t, array_t, array_t, double,
|
|
array_covariance_ut_t, outerProduct_UT_array<array_t>> stat_array_ut;
|
|
|
|
for (size_t i = 0; i < TEST_SIZE; ++i) {
|
|
stat.add(data[i]);
|
|
stat_outer.add(data[i]);
|
|
stat_outer_ut.add(data[i]);
|
|
stat_pair.add(pairs[i]);
|
|
stat_array.add(arrays[i]);
|
|
stat_array_ut.add(arrays[i]);
|
|
}
|
|
|
|
#if 0
|
|
// these aren't trivially copyable
|
|
static_assert(std::is_trivially_copyable<decltype(stat)>::value,
|
|
"tuple based inner product not trivially copyable");
|
|
static_assert(std::is_trivially_copyable<decltype(stat_outer)>::value,
|
|
"tuple based outer product not trivially copyable");
|
|
static_assert(std::is_trivially_copyable<decltype(stat_outer_ut)>::value,
|
|
"tuple based outer product not trivially copyable");
|
|
#endif
|
|
static_assert(std::is_trivially_copyable<decltype(stat_array)>::value,
|
|
"array based inner product not trivially copyable");
|
|
static_assert(std::is_trivially_copyable<decltype(stat_array_ut)>::value,
|
|
"array based inner product not trivially copyable");
|
|
|
|
// inner product variance should be same as outer product diagonal sum
|
|
const double variance = stat.getPopVariance();
|
|
EXPECT_NEAR(variance,
|
|
std::get<0>(stat_outer.getPopVariance()) +
|
|
std::get<3>(stat_outer.getPopVariance()),
|
|
variance * std::numeric_limits<double>::epsilon() * 128);
|
|
|
|
// outer product covariance should be identical
|
|
PRINT_AND_EXPECT_NEAR(std::get<1>(stat_outer.getPopVariance()),
|
|
std::get<2>(stat_outer.getPopVariance()));
|
|
|
|
// upper triangular computation should be identical to outer product
|
|
PRINT_AND_EXPECT_NEAR(std::get<0>(stat_outer.getPopVariance()),
|
|
std::get<0>(stat_outer_ut.getPopVariance()));
|
|
PRINT_AND_EXPECT_NEAR(std::get<1>(stat_outer.getPopVariance()),
|
|
std::get<1>(stat_outer_ut.getPopVariance()));
|
|
PRINT_AND_EXPECT_NEAR(std::get<3>(stat_outer.getPopVariance()),
|
|
std::get<2>(stat_outer_ut.getPopVariance()));
|
|
|
|
PRINT_AND_EXPECT_EQ(variance, stat_pair.getPopVariance());
|
|
|
|
EXPECT_TRUE(equivalent(stat_array_ut.getPopVariance(), stat_outer_ut.getPopVariance()));
|
|
|
|
printf("statistics_inner: %s\n", stat.toString().c_str());
|
|
printf("statistics_outer: %s\n", stat_outer.toString().c_str());
|
|
printf("statistics_outer_ut: %s\n", stat_outer_ut.toString().c_str());
|
|
}
|
|
|
|
TEST(StatisticsTest, stat_linearfit)
|
|
{
|
|
using namespace android::audio_utils; // for operator overload
|
|
LinearLeastSquaresFit<double> fit;
|
|
|
|
static_assert(std::is_trivially_copyable<decltype(fit)>::value,
|
|
"LinearLeastSquaresFit must be trivially copyable");
|
|
|
|
using array_t = std::array<double, 2>;
|
|
array_t data{0.0, 1.5};
|
|
|
|
for (size_t i = 0; i < 10; ++i) {
|
|
fit.add(data);
|
|
data = data + array_t{0.1, 0.2};
|
|
}
|
|
|
|
// check the y line equation
|
|
{
|
|
double a, b, r2;
|
|
fit.computeYLine(a, b, r2);
|
|
printf("y line - a:%lf b:%lf r2:%lf\n", a, b, r2);
|
|
PRINT_AND_EXPECT_NEAR(1.5, a); // y intercept
|
|
PRINT_AND_EXPECT_NEAR(2.0, b); // y slope
|
|
PRINT_AND_EXPECT_NEAR(1.0, r2); // correlation coefficient.
|
|
|
|
// check same as static variant
|
|
double ac, bc, r2c;
|
|
computeYLineFromStatistics(ac, bc, r2c,
|
|
std::get<0>(fit.getMean()), /* mean_x */
|
|
std::get<1>(fit.getMean()), /* mean_y */
|
|
std::get<0>(fit.getPopVariance()), /* var_x */
|
|
std::get<1>(fit.getPopVariance()), /* cov_xy */
|
|
std::get<2>(fit.getPopVariance())); /* var_y */
|
|
|
|
EXPECT_EQ(a, ac);
|
|
EXPECT_EQ(b, bc);
|
|
EXPECT_EQ(r2, r2c);
|
|
|
|
TEST_EXPECT_NEAR(1.9, fit.getYFromX(0.2));
|
|
TEST_EXPECT_NEAR(0.2, fit.getXFromY(1.9));
|
|
TEST_EXPECT_NEAR(1.0, fit.getR2());
|
|
}
|
|
|
|
// check the x line equation
|
|
{
|
|
double a, b, r2;
|
|
fit.computeXLine(a, b, r2);
|
|
printf("x line - a:%lf b:%lf r2:%lf\n", a, b, r2);
|
|
PRINT_AND_EXPECT_NEAR(-0.75, a); // x intercept
|
|
PRINT_AND_EXPECT_NEAR(0.5, b); // x slope
|
|
PRINT_AND_EXPECT_NEAR(1.0, r2); // correlation coefficient.
|
|
}
|
|
}
|
|
|
|
TEST(StatisticsTest, stat_linearfit_noise)
|
|
{
|
|
using namespace android::audio_utils; // for operator overload
|
|
using array_t = std::array<double, 2>;
|
|
LinearLeastSquaresFit<double> fit;
|
|
|
|
// We use 1000 steps for a linear line going from (0, 0) to (1, 1) as true data for
|
|
// our linear fit.
|
|
constexpr size_t ELEMENTS = 1000;
|
|
array_t incr{1. / ELEMENTS, 1. / ELEMENTS};
|
|
|
|
// To simulate additive noise, we use a Gaussian with stddev of 1, and then scale
|
|
// achieve the desired stddev. We precompute our noise here (1000 of them).
|
|
std::vector<array_t> noise(ELEMENTS);
|
|
initNormal(noise, 0. /* mean */, 1. /* stddev */);
|
|
|
|
for (int i = 0; i < 30; ++i) {
|
|
// We run through 30 trials, with noise stddev ranging from 0 to 1.
|
|
// The steps increment linearly from 0.001 to 0.01, linearly from 0.01 to 0.1, and
|
|
// linearly again from 0.1 to 1.0.
|
|
// 0.001, 0.002, ... 0.009, 0.01, 0.02, ....0.09, 0.1, 0.2, .... 1.0
|
|
const double stddev = (i <= 10) ? i / 1000. : (i <= 20) ? (i - 9) / 100. : (i - 19) / 10.;
|
|
fit.reset();
|
|
|
|
for (size_t j = 0; j < ELEMENTS; ++j) {
|
|
array_t data = j * incr + noise[j] * stddev;
|
|
fit.add(data);
|
|
}
|
|
|
|
double a, b, r2;
|
|
fit.computeYLine(a, b, r2);
|
|
printf("stddev: %lf y line - N:%lld a:%lf b:%lf r2:%lf\n",
|
|
stddev, (long long) fit.getN(), a, b, r2);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_P(StatisticsTest, stat_simple_char)
|
|
{
|
|
const char *param = GetParam();
|
|
|
|
android::audio_utils::Statistics<char> stat(0.9);
|
|
android::audio_utils::ReferenceStatistics<char> rstat(0.9);
|
|
|
|
// feed the string character by character to the statistics collectors.
|
|
for (size_t i = 0; param[i] != '\0'; ++i) {
|
|
stat.add(param[i]);
|
|
rstat.add(param[i]);
|
|
}
|
|
|
|
printf("statistics for %s: %s\n", param, stat.toString().c_str());
|
|
printf("ref statistics for %s: %s\n", param, rstat.toString().c_str());
|
|
// verify that the statistics are the same
|
|
verify(stat, rstat);
|
|
}
|
|
|
|
// find the variance of pet names as signed characters.
|
|
const char *pets[] = {"cat", "dog", "elephant", "mountain lion"};
|
|
INSTANTIATE_TEST_CASE_P(PetNameStatistics, StatisticsTest,
|
|
::testing::ValuesIn(pets));
|
|
|
|
TEST(StatisticsTest, simple_stats)
|
|
{
|
|
simple_stats_t ss{};
|
|
|
|
for (const double value : { -1., 1., 3.}) {
|
|
simple_stats_log(&ss, value);
|
|
}
|
|
|
|
PRINT_AND_EXPECT_EQ(3., ss.last);
|
|
PRINT_AND_EXPECT_EQ(1., ss.mean);
|
|
PRINT_AND_EXPECT_EQ(-1., ss.min);
|
|
PRINT_AND_EXPECT_EQ(3., ss.max);
|
|
PRINT_AND_EXPECT_EQ(3, ss.n);
|
|
|
|
char buffer[256];
|
|
simple_stats_to_string(&ss, buffer, sizeof(buffer));
|
|
printf("simple_stats: %s", buffer);
|
|
}
|