/// <summary> /// /// </summary> /// <param name="peakFinderOptions"></param> /// <param name="xyData"></param> /// <param name="originalPeakLocationIndex"> /// Data point index in the x values that should be a part of the peak /// Used for determining the best peak</param> /// <param name="smoothedYData">Smoothed Y values</param> /// <returns></returns> public List <clsPeak> FindPeaks( udtSICPeakFinderOptionsType peakFinderOptions, List <KeyValuePair <int, double> > xyData, int originalPeakLocationIndex, out List <double> smoothedYData) { if (xyData.Count == 0) { smoothedYData = new List <double>(); return(new List <clsPeak>()); } // Compute the potential peak area for this SIC var udtSICPotentialAreaStatsForPeak = FindMinimumPotentialPeakArea(xyData, peakFinderOptions); // Estimate the noise level var noiseAnalyzer = new NoiseLevelAnalyzer(); const bool ignoreNonPositiveData = false; var intensityData = new double[xyData.Count]; var scanNumbers = new int[xyData.Count]; for (var index = 0; index < xyData.Count; index++) { scanNumbers[index] = xyData[index].Key; intensityData[index] = xyData[index].Value; } noiseAnalyzer.ComputeTrimmedNoiseLevel(intensityData, 0, intensityData.Length - 1, peakFinderOptions.SICBaselineNoiseOptions, ignoreNonPositiveData, out var udtBaselineNoiseStats); // Find maximumPotentialPeakArea and dataPointCountAboveThreshold var maximumPotentialPeakArea = FindMaximumPotentialPeakArea(intensityData, peakFinderOptions, udtBaselineNoiseStats, out var dataPointCountAboveThreshold); if (maximumPotentialPeakArea < 1) { maximumPotentialPeakArea = 1; } var areaBasedSignalToNoise = maximumPotentialPeakArea / udtSICPotentialAreaStatsForPeak.MinimumPotentialPeakArea; if (areaBasedSignalToNoise < 1) { areaBasedSignalToNoise = 1; } var peakDetector = new PeakFinder(); var peakData = new PeakDataContainer(); peakData.SetData(xyData); if (Math.Abs(peakFinderOptions.ButterworthSamplingFrequency) < float.Epsilon) { peakFinderOptions.ButterworthSamplingFrequency = 0.25f; } peakData.PeakWidthPointsMinimum = (int)Math.Round(peakFinderOptions.InitialPeakWidthScansScaler * Math.Log10(Math.Floor(areaBasedSignalToNoise)) * 10); // Assure that .InitialPeakWidthScansMaximum is no greater than .InitialPeakWidthScansMaximum // and no greater than dataPointCountAboveThreshold/2 (rounded up) peakData.PeakWidthPointsMinimum = Math.Min(peakData.PeakWidthPointsMinimum, peakFinderOptions.InitialPeakWidthScansMaximum); peakData.PeakWidthPointsMinimum = Math.Min(peakData.PeakWidthPointsMinimum, (int)Math.Ceiling(dataPointCountAboveThreshold / 2.0)); if (peakData.PeakWidthPointsMinimum > peakData.DataCount * 0.8) { peakData.PeakWidthPointsMinimum = (int)Math.Floor(peakData.DataCount * 0.8); } if (peakData.PeakWidthPointsMinimum < MINIMUM_PEAK_WIDTH) { peakData.PeakWidthPointsMinimum = MINIMUM_PEAK_WIDTH; } peakData.OriginalPeakLocationIndex = originalPeakLocationIndex; var peakFoundContainingOriginalPeakLocation = FindPeaksWork( peakDetector, scanNumbers, peakData, peakFinderOptions); smoothedYData = peakData.SmoothedYData.ToList(); return(peakData.Peaks); }