c-gaborator/lib/gaborator/gaborator/gaussian.h
2022-01-23 17:28:23 +01:00

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