All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.psambit9791.jdsp.signal.peaks.Peak Maven / Gradle / Ivy

Go to download

JDSP is a library of signal processing tools aimed at providing functionalities as available in scipy-signal package for Python. The goal is to provide easy-to-use APIs for performing complex operation on signals eliminating the necessity of understanding the low-level complexities in the processing pipeline.

There is a newer version: 3.1.0
Show newest version
/*
 * Copyright (c) 2020 Sambit Paul
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.github.psambit9791.jdsp.signal.peaks;

import com.github.psambit9791.jdsp.misc.UtilMethods;
import org.apache.commons.math3.stat.StatUtils;

import java.util.*;

/**
 * 

PeakObject

* Calculates Peak Properties and allows filtering based on the properties. * This is used by the FindPeak class in the detect() method. *

* * @author Sambit Paul * @version 1.1 */ public class Peak { private double[] signal; private int[] midpoints; private double[] height; private int[] plateau_size; private double[] width; private double[] prominence; private int[] distance; private double[][] sharpness; private double[][] prominenceData; private double[][] widthData; private double relative_height; public Peak(double[] s, int[] m, int[] l, int[] r, String mode) { this.signal = s; // Peak Information this.midpoints = m; // Peak Height and Plateau Information this.height = new double[m.length]; //(Equivalent to scipy.signal.find_peaks() plateau_size parameter) this.plateau_size = new int[m.length]; for (int i=0; i temp = new ArrayList(); // Calculate left prominence double[] partSignal = new double[0]; for (int j=peaks[i]-1; j>=0; j--) { temp.add(this.signal[j]); if (this.signal[j] > threshold) { break; } partSignal = UtilMethods.reverse(UtilMethods.convertToPrimitiveDouble(temp)); } leftProm = threshold - StatUtils.min(partSignal); left_base[i] = peaks[i] - (partSignal.length - UtilMethods.argmin(partSignal, true)); temp.clear(); // Calculate right prominence for (int j=peaks[i]+1; j threshold) { break; } partSignal = UtilMethods.convertToPrimitiveDouble(temp); } rightProm = threshold - StatUtils.min(partSignal); right_base[i] = peaks[i] + UtilMethods.argmin(partSignal, false) + 1; prominence[i] = Math.min(leftProm, rightProm); } double[][] promData = new double[3][peaks.length]; promData[0] = prominence; promData[1] = left_base; promData[2] = right_base; return promData; } /** * This method calculates the width of the peaks provided as an argument * (Equivalent to scipy.signal.find_peaks() width parameter) * @param peaks Peaks for which prominence needs to be calculated * @param rel_height the relative height at which the peak width is measured as a percentage of its prominence * @throws java.lang.IllegalArgumentException if rel_height is not between 0.0 and 1.0 * @return double[][] The width of the input peaks. 0: Contains the widths, 1: Contains the Left Intersection Points, 2: Contains the Right Intersection Points */ public double[][] findPeakWidth(int[] peaks, double rel_height) throws IllegalArgumentException { getIndexFromPeak(peaks); if (rel_height > 1.0 || rel_height < 0.0) { throw new IllegalArgumentException("rel_height can be between 0.0 and 1.0"); } double[] width = new double[peaks.length]; double[][] promData = this.findPeakProminence(peaks); double[] prominence = promData[0]; double[] left_bases = promData[1]; double[] right_bases = promData[2]; double[] widthHeight = new double[peaks.length]; double[] leftIntersectPoint = new double[peaks.length]; double[] rightIntersectPoint = new double[peaks.length]; for (int i=0; i newPeaks = new ArrayList(); double[] height = this.findPeakHeights(peaks); if (lower_threshold == null && upper_threshold == null) { throw new IllegalArgumentException("All thresholds cannot be null"); } else if (lower_threshold != null && upper_threshold == null) { for (int i=0; i= lower_threshold) { newPeaks.add(peaks[i]); } } } else if (lower_threshold == null && upper_threshold != null) { for (int i=0; i= lower_threshold && height[i] <= upper_threshold) { newPeaks.add(peaks[i]); } } } return UtilMethods.convertToPrimitiveInt(newPeaks); } /** * This method allows filtering the total peaks by plateau size using both the upper and lower threshold * @param lower_threshold The lower threshold of plateau size to check against. Use null to omit. * @param upper_threshold The upper threshold of plateau size to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByPlateauSize(Double lower_threshold, Double upper_threshold) { return this.filterByPlateauSize(this.midpoints, lower_threshold, upper_threshold); } /** * This method allows filtering all the peaks by plateau size using both the upper and lower threshold * @throws java.lang.IllegalArgumentException If both upper and lower threshold is null * @param peaks List of peaks to be filtered * @param lower_threshold The lower threshold of plateau size to check against. Use null to omit. * @param upper_threshold The upper threshold of plateau size to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByPlateauSize(int[] peaks, Double lower_threshold, Double upper_threshold) { ArrayList newPeaks = new ArrayList(); int[] plateau_size = this.findPlateauSize(peaks); if (lower_threshold == null && upper_threshold == null) { throw new IllegalArgumentException("All thresholds cannot be null"); } else if (lower_threshold != null && upper_threshold == null) { for (int i=0; i= lower_threshold) { newPeaks.add(peaks[i]); } } } else if (lower_threshold == null && upper_threshold != null) { for (int i=0; i= lower_threshold && plateau_size[i] <= upper_threshold) { newPeaks.add(peaks[i]); } } } return UtilMethods.convertToPrimitiveInt(newPeaks); } /** * This method allows filtering all the peaks by prominence using both the upper and lower threshold * @param lower_threshold The lower threshold of prominence to check against. Use null to omit. * @param upper_threshold The upper threshold of prominence to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByProminence(Double lower_threshold, Double upper_threshold) { return this.filterByProminence(this.midpoints, lower_threshold, upper_threshold); } /** * This method allows filtering the list of peaks by prominence using both the upper and lower threshold * @throws java.lang.IllegalArgumentException If both upper and lower threshold is null * @param peaks List of peaks to be filtered * @param lower_threshold The lower threshold of prominence to check against. Use null to omit. * @param upper_threshold The upper threshold of prominence to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByProminence(int[] peaks, Double lower_threshold, Double upper_threshold) { ArrayList newPeaks = new ArrayList(); double[] prominence = this.findPeakProminence(peaks)[0]; if (lower_threshold == null && upper_threshold == null) { throw new IllegalArgumentException("All thresholds cannot be null"); } else if (lower_threshold != null && upper_threshold == null) { for (int i=0; i= lower_threshold) { newPeaks.add(peaks[i]); } } } else if (lower_threshold == null && upper_threshold != null) { for (int i=0; i= lower_threshold && prominence[i] <= upper_threshold) { newPeaks.add(peaks[i]); } } } return UtilMethods.convertToPrimitiveInt(newPeaks); } /** * This method allows filtering all the peaks by width using both the upper and lower threshold * @param lower_threshold The lower threshold of width to check against. Use null to omit. * @param upper_threshold The upper threshold of width to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByWidth(Double lower_threshold, Double upper_threshold) { return this.filterByWidth(this.midpoints, lower_threshold, upper_threshold); } /** * This method allows filtering the list of peaks by width using both the upper and lower threshold * @throws java.lang.IllegalArgumentException If both upper and lower threshold is null * @param peaks List of peaks to be filtered * @param lower_threshold The lower threshold of width to check against. Use null to omit. * @param upper_threshold The upper threshold of width to check against. Use null to omit. * @return int[] The list of filtered peaks */ public int[] filterByWidth(int[] peaks, Double lower_threshold, Double upper_threshold) { ArrayList newPeaks = new ArrayList(); double[] width = this.findPeakWidth(peaks, this.relative_height)[0]; if (lower_threshold == null && upper_threshold == null) { throw new IllegalArgumentException("All thresholds cannot be null"); } else if (lower_threshold != null && upper_threshold == null) { for (int i=0; i= lower_threshold) { newPeaks.add(peaks[i]); } } } else if (lower_threshold == null && upper_threshold != null) { for (int i=0; i= lower_threshold && width[i] <= upper_threshold) { newPeaks.add(peaks[i]); } } } return UtilMethods.convertToPrimitiveInt(newPeaks); } /** * This method allows filtering all the peaks by distance * @param distance The threshold of distance to check against * @return int[] The list of filtered peaks */ public int[] filterByPeakDistance(int distance) { return this.filterByPeakDistance(this.midpoints, distance); } /** * This method allows filtering the list of peaks by distance * @param peaks List of peaks to be filtered * @param distance The threshold of distance to check against * @return int[] The list of filtered peaks */ public int[] filterByPeakDistance(int[] peaks, int distance) { int[] keep = new int[peaks.length]; Arrays.fill(keep, 1); double[] heights = this.findPeakHeights(peaks); int[] priority = UtilMethods.argsort(heights, true); for (int i=peaks.length-1; i>=0; i--) { int j = priority[i]; if (keep[j] == 0) { continue; } int k = j - 1; while (0 <= k && peaks[j] - peaks[k] < distance) { keep[k] = 0; k--; } k = j + 1; while (k < peaks.length && peaks[k] - peaks[j] < distance) { keep[k] = 0; k++; } } ArrayList newPeaks = new ArrayList(); for (int i=0; i newPeaks = new ArrayList(); double[][] sharpness = this.findPeakSharpness(peaks); int[] keep = new int[peaks.length]; Arrays.fill(keep, 1); if (lower_threshold == null && upper_threshold == null) { throw new IllegalArgumentException("All thresholds cannot be null"); } else if (lower_threshold != null && upper_threshold == null) { for (int i=0; i upper_threshold) { keep[i] = 0; } } } else { for (int i=0; i upper_threshold) { keep[i] = 0; } } } for (int i=0; i





© 2015 - 2025 Weber Informatics LLC | Privacy Policy