예제 #1
0
 /// <summary>
 /// sets the options for this instance.
 /// </summary>
 /// <param name="signalToNoise">sets the threshold signal to noise value.</param>
 /// <param name="thresh">sets the peak intensity threshold.</param>
 /// <param name="thresholded">if the data is thresholded.</param>
 /// <param name="type">sets the type of peak fitting algorithm used.</param>
 public void SetOptions(double signalToNoise, double thresh, bool thresholded, PeakFitType type)
 {
     _isDataThresholded = thresholded;
     // signal to noise should ideally be set before PeakIntensityThreshold
     SetSignalToNoiseThreshold(signalToNoise);
     SetPeakIntensityThreshold(thresh);
     SetPeakFitType(type);
 }
예제 #2
0
 /// <summary>
 /// sets the type of peak fitting used to find m/z values for peaks.
 /// </summary>
 /// <param name="type">specifies the type of peak fitting.</param>
 public void SetPeakFitType(PeakFitType type)
 {
     _peakFit.SetOptions(type);
 }
예제 #3
0
        /// <summary>
        /// Find full width at half maximum value at position specified.
        /// remarks Looks for half height locations at left and right side, and uses twice of that value as the FWHM value. If half height
        /// locations cannot be found (because of say an overlapping neighbouring peak), we perform interpolations.
        /// </summary>
        /// <param name="rawData">data to search in</param>
        /// <param name="centerIndex">location of center points.  Apex of centroided peaks</param>
        /// <param name="centroidPeak">specific peak to find the FWHM of</param>
        /// <param name="shoulderNoiseToLettIndex">return location of local minimum to the left</param>
        /// <param name="shoulderNoiseToRightIndex">return location of local minima to the right</param>
        /// <param name="lowAbundanceFWHMFitType">which algorithm will we use to calculate hald max value on the side of the peak</param>
        /// <returns></returns>
        private double FindFWHM(List <XYData> rawData, int centerIndex, XYData centroidPeak, ref int shoulderNoiseToLeftIndex, ref int shoulderNoiseToRightIndex, PeakFitType lowAbundanceFWHMFitType)
        {
            //this bounds the number of points we can used to determine FWHM
            //int MinimaLeftIndex = (int)storeMinimaData.X;//index lower in mass
            //int MinimaRightIndex = (int)storeMinimaData.Y;//index higher in mass
            var MinimaLeftIndex  = shoulderNoiseToLeftIndex;  //index lower in mass
            var MinimaRightIndex = shoulderNoiseToRightIndex; //index higher in mass

            double deltaXRight;                               //distance of half-width-at-half-maximum to the right
            double deltaXLeft;                                //distance of half-width-at-half-maximum to the left

            //points for steppig through so we can find interpolation bounds
            double X1CurrentPoint;
            double Y1CurrentPoint;
            double X2OnePointAhead; //one less when stepping back from large X and one more when stepping from small X
            double Y2OnePointAhead; //one less when stepping back from large X and one more when stepping from small X

            //double Y2OnePointsAhead;
            //use centroided data for deltaX and halfMaximum calculations
            var Y0CenterHeight = centroidPeak.Y;
            var Y0HalfHeight   = Y0CenterHeight / 2.0;
            var X0CenterMass   = centroidPeak.X;

            //initialize heavily used variables
            double FWHM;  //returned answer
            double A = 0; //ParabolaABC
            double B = 0; //ParabolaABC
            double C = 0; //ParabolaABC

            var detectedMethodLeft  = FullWidthHalfMaximumPeakOptions.Unassigned;
            var detectedMethodRight = FullWidthHalfMaximumPeakOptions.Unassigned;
            var numPoints           = rawData.Count();

            //if there is no data
            if (Y0CenterHeight == 0.0)
            {
                return(0.0);
            }

            //if we are on the ends of the data
            if (centerIndex <= 0 || centerIndex >= numPoints - 1)
            {
                return(0);
            }

            #region look for the Half maximum on the right side
            deltaXRight = rawData[MinimaRightIndex].X - X0CenterMass; //initialize with maximum it can be without calculations//ths may not be necesary

            if (rawData[MinimaRightIndex].Y < Y0HalfHeight)           //is our minima less than half maximum
            {
                #region there are enough data points that we can find the postiion easily.
                for (var i = MinimaRightIndex; i > centerIndex; i--) //TODO check this centerindex+1? to avoid 0
                {
                    Y2OnePointAhead = rawData[i - 1].Y;              //look one point ahead
                    if (Y2OnePointAhead > Y0HalfHeight)              //is the Yfwhm in the range
                    {
                        X1CurrentPoint  = rawData[i].X;
                        Y1CurrentPoint  = rawData[i].Y;
                        X2OnePointAhead = rawData[i - 1].X;
                        //we are in range. i is below the half height and i-1 is above
                        var interpolatedX = X1CurrentPoint - (X1CurrentPoint - X2OnePointAhead) * (Y0HalfHeight - Y1CurrentPoint) / (Y2OnePointAhead - Y1CurrentPoint);//TODO check this
                        deltaXRight         = interpolatedX - X0CenterMass;
                        detectedMethodRight = FullWidthHalfMaximumPeakOptions.Interpolated;
                        break;
                    }
                    X1CurrentPoint = 0;//break point
                    //this is not needed because we will keep iterating till the answer is found
                    //TODO is there a case for this else block or do we use the default deltaXright asigned above
                    //xcoordinateToRight = X0CenterMass + deltaXRight;//notice this is offset from the center mass not the centroid
                }
                #endregion
            }
            else//we need to interpolate beyond the data we have to find a theoretical end point
            {
                //if there are a few points
                if (MinimaRightIndex - centerIndex > 2)//three or more points
                {
                    /// 1.  take log of lorentzian data so we can fit a parabola to the peak
                    /// 2.  fit parabola
                    /// 3.  Use A,B,C from parabola to construct F(log(Y)
                    /// 4.  plug log(FWHM) into F() to get deltaX = F(log(FWHM))

                    #region load up ListXYdata with points from the center so we can fit a parabola
                    double transformedHalfHeight = 0;//this is needed incase the logarithm is taken
                    var    peakRightSideList     = new List <XYData>();

                    switch (lowAbundanceFWHMFitType)//for parabola fit, don't take a log.  For lorentzian, take a log first
                    {
                    case PeakFitType.Parabola:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var pointTransfer = new XYData(rawData[i].X, rawData[i].Y);
                            peakRightSideList.Add(pointTransfer);
                        }
                        transformedHalfHeight = Y0HalfHeight;
                    }
                    break;

                    case PeakFitType.Lorentzian:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var logY          = (float)(Math.Log10(rawData[i].Y));
                            var pointTransfer = new XYData(rawData[i].X, logY);

                            if (rawData[i].Y > 0)        //prevents infinity solution from log10
                            {
                                peakRightSideList.Add(pointTransfer);
                            }
                        }
                        transformedHalfHeight = Math.Log10(Y0HalfHeight);
                    }
                    break;

                    default:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var pointTransfer = new XYData(rawData[i].X, rawData[i].Y);
                            peakRightSideList.Add(pointTransfer);
                        }
                        transformedHalfHeight = Y0HalfHeight;
                    }
                    break;
                    }

                    #endregion

                    //fit parabola to the data so we can extrapolate the missing FWHM
                    var peakTopCalculation = new PeakCentroider();
                    peakTopCalculation.ParabolaABC(peakRightSideList, ref A, ref B, ref C);

                    //calculate right X value for half height
                    var squareRootTest = B * B - 4 * A * C + 4 * A * transformedHalfHeight;//must be positive
                    if (squareRootTest > 0)
                    {
                        deltaXRight = -((B / 2 + Math.Sqrt(squareRootTest) / 2) / A);
                    }
                    else
                    {
                        deltaXRight = deltaXRight / 2;  //deltaXRight was the max distance on the right side
                                                        //so as an approximation, "deltaXRight / 2" should be somewhere half way inbetween
                    }
                    detectedMethodRight = FullWidthHalfMaximumPeakOptions.QuadraticExtrapolation;
                    //xcoordinateToRight = rawData[MinimaLeftIndex].X + deltaXRight;//notice the different start point
                    //this is because the parabola starts at the MinLeftIndex rather than the XOCenterMass
                }
                else//there are not enough points to fit the parabola, extrapolate a line
                {
                    //calculate slope and project a line
                    var slope      = (Y0CenterHeight - rawData[MinimaRightIndex].Y) / (X0CenterMass - rawData[MinimaRightIndex].X);
                    var intecept   = (Y0CenterHeight - slope * X0CenterMass);
                    var regressedX = -((intecept - Y0HalfHeight) / slope);
                    deltaXRight         = regressedX - X0CenterMass;
                    detectedMethodRight = FullWidthHalfMaximumPeakOptions.LinearExtrapolation;
                }
            }
            #endregion

            #region look for the Half maximum on the left side
            deltaXLeft = X0CenterMass - rawData[MinimaLeftIndex].X; //initialize with maximum it can be//ths may not be necesary

            if (rawData[MinimaLeftIndex].Y < Y0HalfHeight)          //is our minima less than half maximum
            {
                #region there are enough data points that we can find the postiion easily
                for (var i = MinimaLeftIndex; i < centerIndex; i++) //TODO check this centerindex-1? to avoid 0
                {
                    Y2OnePointAhead = rawData[i + 1].Y;             //look one point ahead
                    if (Y2OnePointAhead > Y0HalfHeight)             //is the Yfwhm in the range
                    {
                        X1CurrentPoint  = rawData[i].X;
                        Y1CurrentPoint  = rawData[i].Y;
                        X2OnePointAhead = rawData[i + 1].X;
                        //we are in range. i is below the half height and i-1 is above
                        var interpolatedX = X1CurrentPoint - (X1CurrentPoint - X2OnePointAhead) * (Y0HalfHeight - Y1CurrentPoint) / (Y2OnePointAhead - Y1CurrentPoint);//TODO check this
                        deltaXLeft         = X0CenterMass - interpolatedX;
                        detectedMethodLeft = FullWidthHalfMaximumPeakOptions.Interpolated;
                        break;
                    }
                    X1CurrentPoint = 0;//break point
                    //this is not needed because we will keep iterating till the answer is found
                    //TODO is there a case for this else block or do we use the default deltaXright asigned above
                }
                #endregion
            }
            else//we need to interpolate beyond the data we have to find a theoretical end point
            {
                //if there are a few points
                if (centerIndex - MinimaLeftIndex > 2)
                {
                    /// 1.  take log of lorentzian data so we can fit a parabola to the peak
                    /// 2.  fit parabola
                    /// 3.  Use A,B,C from parabola to construct F(log(Y)
                    /// 4.  plug log(FWHM) into F() to get deltaX = F(log(FWHM))

                    #region load up ListXYdata with points from the center so we can fit a parabola
                    double transformedHalfHeight = 0;//this is needed incase the logarithm is taken
                    var    peakLeftSideList      = new List <XYData>();

                    switch (lowAbundanceFWHMFitType)//for parabola fit, don't take a log.  For lorentzian, take a log first
                    {
                    case PeakFitType.Parabola:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var pointTransfer = new XYData(rawData[i].X, rawData[i].Y);
                            peakLeftSideList.Add(pointTransfer);
                        }
                        transformedHalfHeight = Y0HalfHeight;
                    }
                    break;

                    case PeakFitType.Lorentzian:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var logY          = (float)(Math.Log10(rawData[i].Y));
                            var pointTransfer = new XYData(rawData[i].X, logY);

                            if (rawData[i].Y > 0)        //prevents infinity solution from log10
                            {
                                peakLeftSideList.Add(pointTransfer);
                            }
                        }
                        transformedHalfHeight = Math.Log10(Y0HalfHeight);
                    }
                    break;

                    default:
                    {
                        for (var i = MinimaLeftIndex; i <= MinimaRightIndex; i++)
                        {
                            var pointTransfer = new XYData(rawData[i].X, rawData[i].Y);
                            peakLeftSideList.Add(pointTransfer);
                        }
                        transformedHalfHeight = Y0HalfHeight;
                    }
                    break;
                    }
                    #endregion

                    //fit parabola to the data so we can extrapolate the missing FWHM
                    var peakTopCalculation = new PeakCentroider();
                    peakTopCalculation.ParabolaABC(peakLeftSideList, ref A, ref B, ref C);

                    //calculate right X value for half height
                    //deltaXLeft = -((B / 2 + Math.Sqrt(B * B - 4 * A * C + 4 * A * transformedHalfHeight) / 2) / A);
                    var squareRootTest = B * B - 4 * A * C + 4 * A * transformedHalfHeight;//must be positive
                    if (squareRootTest > 0)
                    {
                        deltaXLeft = -((B / 2 + Math.Sqrt(squareRootTest) / 2) / A);
                    }
                    else
                    {
                        deltaXLeft = deltaXLeft / 2;    //deltaXRight was the max distance on the right side
                                                        //so as an approximation, "deltaXRight / 2" should be somewhere half way inbetween
                    }
                    detectedMethodLeft = FullWidthHalfMaximumPeakOptions.QuadraticExtrapolation;
                    //xcoordinateToLeft = rawData[MinimaLeftIndex].X + deltaXLeft;//notice the different start point
                    //this is because the parabola starts at the MinLeftIndex rather than the XOCenterMass
                }
                else//there are not enough points to fit the parabola, extrapolate a line
                {
                    //calculate slope and project a line
                    var slope      = (Y0CenterHeight - rawData[MinimaLeftIndex].Y) / (X0CenterMass - rawData[MinimaLeftIndex].X);
                    var intecept   = (Y0CenterHeight - slope * X0CenterMass);
                    var regressedX = -((intecept - Y0HalfHeight) / slope);
                    deltaXLeft         = X0CenterMass - regressedX;
                    detectedMethodLeft = FullWidthHalfMaximumPeakOptions.LinearExtrapolation;
                }
            }
            #endregion


            if (deltaXRight == 0.0)//if we only have half the data
            {
                FWHM = 2 * deltaXLeft;
                return(FWHM);
            }

            if (deltaXLeft == 0.0)
            {
                FWHM = 2 * deltaXLeft;
                return(FWHM);
            }

            //If we have a weak linear extrapolation on one half of the peak and a stronger iterpolation or quadratic extrapolation
            //on the other side it is better to double the interpolation or quadratic extrapolation.
            if (detectedMethodLeft == FullWidthHalfMaximumPeakOptions.LinearExtrapolation)
            {
                if (detectedMethodRight == FullWidthHalfMaximumPeakOptions.QuadraticExtrapolation || detectedMethodRight == FullWidthHalfMaximumPeakOptions.Interpolated)
                {
                    deltaXLeft = deltaXRight;
                }
            }

            if (detectedMethodRight == FullWidthHalfMaximumPeakOptions.LinearExtrapolation)
            {
                if (detectedMethodLeft == FullWidthHalfMaximumPeakOptions.QuadraticExtrapolation || detectedMethodLeft == FullWidthHalfMaximumPeakOptions.Interpolated)
                {
                    deltaXRight = deltaXLeft;
                }
            }

            FWHM = deltaXLeft + deltaXRight;
            return(FWHM);
        }
예제 #4
0
 /// <summary>
 ///     Sets the type of fit.
 /// </summary>
 /// <param name="type">sets the type of fit function that this instance uses.</param>
 public void SetOptions(PeakFitType type)
 {
     _peakFitType = type;
 }
예제 #5
0
 /// <summary>
 ///     Default constructor.
 /// </summary>
 /// <remarks>By default uses Quadratic fit.</remarks>
 public PeakFitter()
 {
     _peakFitType = PeakFitType.Quadratic;
 }
예제 #6
0
 /// <summary>
 /// default constructor that loads default values
 /// </summary>
 public PeakCentroiderParameters(PeakFitType fitType)
 {
     Clear();
     FWHMPeakFitType = fitType;
 }