/*- * Copyright 2015 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.peakfinding.peakfinders; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IDataset; /** * Contains routines for filtering out points in the significance function * which might be peaks. * * Originally specified in: * "Simple Algorithm Peak Detection Time Series, Palshikar (Tata Research)" */ public abstract class AbstractSignificanceFilter extends AbstractPeakFinder { private String WINDOWSIZE = "Window size"; private String NRSTDDEVS = "Standard deviation filter"; /** * Set's values of parameters needed for filtering significance function. * @throws Exception */ public AbstractSignificanceFilter() { super(); try { initialiseParameter(WINDOWSIZE, true, 50); initialiseParameter(NRSTDDEVS, true, 1); } catch (Exception e) { System.out.println(e); logger.error("Problem initialising "+this.getName()+" peak finder: e"); } } /** * Calculates the significance function specified in "Simple Algorithm Peak * Detection Time Series, Palshikar (Tata Research)". The significance of * each point of a 1D dataset is calculated. * @param position Index of current point * @param windowSize Number of points left and right to consider * @param yData The dataset * @return The significance of the current point (i.e. it's peakiness) */ protected abstract double calculateSignificance(int position, int windowSize, IDataset yData); @Override public Map<Integer, Double> findPeaks(IDataset xData, IDataset yData, Integer nPeaks) { //Put our peak finding parameters into more accessible variables Integer nrStdDevs; Integer windowSize; try { nrStdDevs = (Integer)getParameterValue(NRSTDDEVS); windowSize = (Integer)getParameterValue(WINDOWSIZE); } catch(Exception e) { logger.error("Could not find specified peak finding parameters"); return null; } //Calculate the significance function for this data & its mean & SD int nrPoints = yData.getSize(); Dataset significance = DatasetFactory.zeros(DoubleDataset.class, yData.getShape()); for (int i = windowSize; i <= (nrPoints-windowSize-1); i++) { double posSig = calculateSignificance(i, windowSize, yData); significance.set(posSig, i); } //Filter out significance values less than n*SD Double sigMean = (Double)significance.mean(); Double sigStdDev = (Double)significance.stdDeviation(); Map<Integer, Double> peakPosnsSigs = new TreeMap<Integer, Double>(); for (int i = 0; i < significance.getSize(); i++) { Double currSig = significance.getDouble(i); if ((currSig > 0) && ((currSig-sigMean) > nrStdDevs * sigStdDev)) { peakPosnsSigs.put(i, currSig); } } //Remove significant points less than one windowSize apart Set<Integer> peakIndices = new TreeSet<Integer>(peakPosnsSigs.keySet()); Iterator<Integer> peakIndIter = peakIndices.iterator(); int currInd = peakIndIter.next().intValue(); int nextInd; while (peakIndIter.hasNext()) { nextInd = peakIndIter.next().intValue(); if (Math.abs(currInd - nextInd) <= windowSize) { peakPosnsSigs.remove(currInd); } currInd = nextInd; } return peakPosnsSigs; } }