124 lines
3.3 KiB
C++
124 lines
3.3 KiB
C++
//
|
|
// The Gaussian and related functions
|
|
//
|
|
// Copyright (C) 2015-2021 Andreas Gustafsson. This file is part of
|
|
// the Gaborator library source distribution. See the file LICENSE at
|
|
// the top level of the distribution for license information.
|
|
//
|
|
|
|
#ifndef _GABORATOR_GAUSSIAN_H
|
|
#define _GABORATOR_GAUSSIAN_H
|
|
|
|
#include <math.h>
|
|
|
|
namespace gaborator {
|
|
|
|
// A rough approximation of erfc_inv(), the inverse complementary
|
|
// error function. This is good for arguments in the range 1e-8 to 1,
|
|
// to within a few percent.
|
|
|
|
inline float erfc_inv(float x) {
|
|
return sqrtf(-logf(x)) - 0.3f;
|
|
}
|
|
|
|
// Gaussian with peak = 1
|
|
|
|
inline double norm_gaussian(double sd, double x) {
|
|
return exp(-(x * x) / (2 * sd * sd));
|
|
}
|
|
|
|
// Gaussian with integral = 1
|
|
|
|
inline double gaussian(double sd, double x) {
|
|
double a = 1.0 / (sd * sqrt(2.0 * M_PI));
|
|
return a * norm_gaussian(sd, x);
|
|
}
|
|
|
|
// The convolution of a Heaviside step function with a Gaussian of
|
|
// standard deviation sd. Goes smoothly from 0 to 1, with the 0.5
|
|
// point at x=0.
|
|
|
|
static inline
|
|
double gaussian_edge(double sd, double x) {
|
|
double erf_arg = x / (sd * M_SQRT2);
|
|
if (erf_arg < -7)
|
|
return 0; // error < 5e-23
|
|
if (erf_arg > 7)
|
|
return 1; // error < 5e-23
|
|
return (erf(erf_arg) + 1) * 0.5;
|
|
}
|
|
|
|
// Translate the time-domain standard deviation of a Gaussian
|
|
// (in samples) into the corresponding frequency-domain standard
|
|
// deviation (as a fractional frequency), or vice versa.
|
|
|
|
static inline double sd_t2f(double st_sd) {
|
|
return 1.0 / (2.0 * M_PI * st_sd);
|
|
}
|
|
|
|
static inline double sd_f2t(double ff_sd) {
|
|
return sd_t2f(ff_sd);
|
|
}
|
|
|
|
// Given a Gaussian with standard deviation "sd" and a maximum error
|
|
// "max_error", calculate the support needed on each side to keep the
|
|
// area below the curve within max_error of the exact value.
|
|
|
|
static inline
|
|
double gaussian_area_support(double sd, double max_error) {
|
|
return sd * M_SQRT2 * erfc_inv(max_error);
|
|
}
|
|
|
|
// Inverse of the above: given a support and maximum error, calculate
|
|
// the standard deviation.
|
|
|
|
static inline
|
|
double gaussian_area_support_inv(double support, double max_error) {
|
|
return support / (M_SQRT2 * erfc_inv(max_error));
|
|
}
|
|
|
|
// Given a gaussian with standard deviation "sd" and a maximum error
|
|
// "max_error", calculate the support needed on each side for the
|
|
// value to fall to a factor of "max_error" of the peak.
|
|
|
|
static inline
|
|
double gaussian_value_support(double sd, double max_error) {
|
|
return sd * M_SQRT2 * sqrt(-log(max_error));
|
|
}
|
|
|
|
// Inverse of the above: given a support and maximum error, calculate
|
|
// the standard deviation.
|
|
|
|
static inline
|
|
double gaussian_value_support_inv(double support, double max_error) {
|
|
return support / (M_SQRT2 * sqrt(-log(max_error)));
|
|
}
|
|
|
|
// Choose which criterion to use
|
|
|
|
#if 1
|
|
static inline
|
|
double gaussian_support(double support, double max_error) {
|
|
return gaussian_area_support(support, max_error);
|
|
};
|
|
|
|
static inline
|
|
double gaussian_support_inv(double support, double max_error) {
|
|
return gaussian_area_support_inv(support, max_error);
|
|
};
|
|
#else
|
|
static inline
|
|
double gaussian_support(double support, double max_error) {
|
|
return gaussian_value_support(support, max_error);
|
|
};
|
|
|
|
static inline
|
|
double gaussian_support_inv(double support, double max_error) {
|
|
return gaussian_value_support_inv(support, max_error);
|
|
};
|
|
#endif
|
|
|
|
} // namespace
|
|
|
|
#endif
|