package gdsc.smlm.function; import org.apache.commons.math3.special.Erf; import org.apache.commons.math3.util.FastMath; /** * Calculate the value of the Skew Normal distribution * <p> * See http://en.wikipedia.org/wiki/Skew_normal_distribution */ public class SkewNormalFunction { protected double amplitude, location, scale, alpha; /** * Create a function with the given parameters * * @param parameters * [amplitude, location, scale, alpha] */ public SkewNormalFunction(double[] parameters) { setParameters(parameters); } /** * Set the parameters * * @param parameters * [amplitude, location, scale, alpha] */ public void setParameters(double[] parameters) { amplitude = parameters[0]; location = parameters[1]; scale = parameters[2]; alpha = parameters[3]; } /** * @return The mean of the function */ public double getMean() { return location + scale * getSigma() * Math.sqrt(2.0 / Math.PI); } /** * @return The variance of the function */ public double getVariance() { final double sigma = getSigma(); return scale * scale * (1.0 - (2.0 * sigma * sigma / Math.PI)); } public double getSkewness() { final double sigma = getSigma(); return ((4.0 - Math.PI) / 2.0) * (Math.pow((sigma * Math.sqrt(2.0 / Math.PI)), 3) / Math.pow(1 - 2 * sigma * sigma / Math.PI, 1.5)); } private double getSigma() { return alpha / Math.sqrt(1 + alpha * alpha); } /** * Evaluates the skewed Gaussian at the given point * @param x * * @return */ public double evaluate(double x) { return evaluate(x, amplitude, location, scale, alpha); } /** * Evaluates the skewed Gaussian at the given point * * @param x * @param parameters * [amplitude, location, scale, alpha] * @return */ public static double evaluate(double x, double[] parameters) { return evaluate(x, parameters[0], parameters[1], parameters[2], parameters[3]); } /** * Evaluates the skewed Gaussian at the given point * * @param x * @param amplitude * @param location * @param scale * @param alpha * @return */ public static double evaluate(double x, double amplitude, double location, double scale, double alpha) { //return (2 * amplitude / scale) * normal((x - location) / scale) * cumul(alpha * (x - location) / scale); // Do not normalise the area under the graph to 1. This allows the amplitude to be correctly modelled. return (2 * amplitude) * normal((x - location) / scale) * cumul(alpha * (x - location) / scale); } /** * Probability density function of the Gaussian * * @param x * @return */ private static double normal(double x) { // 1/sqrt(2*pi) = 0.39894228 //return 0.39894228 * FastMath.exp(-0.5 * x*x); // Do not normalise the area under the graph to 1. This allows the amplitude to be correctly modelled. return FastMath.exp(-0.5 * x * x); } /** * Cumulative distribution function of the gaussian * * @param x * @return */ private static double cumul(double x) { // 1/sqrt(2) = 0.707106781 return 0.5 * (1 + Erf.erf(x * 0.707106781)); } }