package uk.ac.diamond.scisoft.analysis.peakfinding;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IParameter;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DoubleDataset;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.IndexIterator;
import uk.ac.diamond.scisoft.analysis.fitting.functions.AFunction;
import uk.ac.diamond.scisoft.analysis.fitting.functions.CoordinatesIterator;
/**
* Mexican wavelet (Ricker) Wavelet function discrete wavelet
* A (1 - x^2/a^2) exp(-x^2/2 a^2), where A = 2/sqrt(3a)pi^1/4"
*
* @author Dean P. Ottewell
*
*
*TODO: Almost certain should extend APeak... then hav ethe top peak be the amplitude calucalted.
*However, should the humps be classed as peaks too?
*
*TODO: Then after that should have a IWavelet - containg point num
*
*/
public class MexicanHatWavelet extends AFunction {
private static final String NAME = "Mexican Hat";
private static final String DESC = "A Mexican Hat (Ricker) Wavelet."
+ "\n A (1 - x^2/a^2) exp(-x^2/2 a^2), where A = 2/sqrt(3a)pi^1/4";
private static final String[] PARAM_NAMES = new String[]{"width", "posn"};
public MexicanHatWavelet() {
this(PARAM_NAMES);
}
public MexicanHatWavelet(double numPoints,double width ){
super(numPoints,width);
getParameter(0).setValue(numPoints);
getParameter(1).setValue(width);
}
public MexicanHatWavelet(String[] paramNames) {
//Default values
super(100,10);
}
@Override
public double val(double... values) {
double timePos = values[0];
double w = getParameterValue(1);
double tsq = timePos * timePos; //TODO: isnt Math.pow ineffecient?
double variance = w * w;
//the python version said this was a amplitude calulation, however it could be considered a constant...
double c = 2 / (Math.sqrt(3 * w) * (Math.pow(Math.PI, 0.25)));
double mod = 1 - (tsq)/(variance);
double gauss = Math.exp((-tsq) / (2 * variance));
double val = c * mod * gauss;
return val;
}
@Override
protected void setNames() {
setNames(NAME, DESC, PARAM_NAMES);
}
@Override
public void fillWithValues(DoubleDataset data, CoordinatesIterator it) {
//Fills with coords based on data. Centered around a 0 point based on numPoints
double[] coords = it.getCoordinates();
int i = 0;
double[] buffer = data.getData();
double numPoints = getParameterValue(0);
double w = getParameterValue(1);
double variance = w * w;
double c = 2 / (Math.sqrt(3 * w) * (Math.pow(Math.PI, 0.25)));
while (it.hasNext()) {
//TODO: this exits in a world where everything is 1D...
double itVal = it.getCoordinates()[0];
double nVal = itVal - (numPoints-1.0) / 2;
double xsq = nVal*nVal;
double nMod = 1 - (xsq)/(variance);
double nGauss = Math.exp((-xsq) / (2 * variance));
double nTotal = c * nMod * nGauss;
buffer[i++] = nTotal;
}
}
}