private static double[,] getRegularBins(double _firstMz, double _lastMz, quadraticEquation _par)
        {
            ArrayList regularBinsArrayList = new ArrayList();

            double x = _firstMz;

            while (x <= _lastMz)
            {
                regularBinsArrayList.Add(x);
                x += _par.A + _par.B * (x - _par.x0) + _par.C * Math.Pow(x - _par.x0, 2);
            }

            double[,] regularBins = new double[2, regularBinsArrayList.Count];
            for (int i = 0; i < regularBinsArrayList.Count; i++)
            {
                regularBins[0, i] = (double)regularBinsArrayList[i];
            }
            return(regularBins);
        }
        private static quadraticEquation getBinParameters(double[,] firstSpectrum)
        {
            quadraticEquation par = new quadraticEquation();

            par.x0 = firstSpectrum[0, 0];

            int totElements = ((double[, ])firstSpectrum).GetUpperBound(1) + 1;

            double[] mzs = new double[totElements];
            for (int i = 0; i < totElements; i++)
            {
                mzs[i] = firstSpectrum[0, i];
            }

            double[] distances = new double[totElements];
            for (int i = 0; i < totElements - 1; i++)
            {
                distances[i] = mzs[i + 1] - mzs[i];
            }

            // get local median

            int localSize = 200; // this must be an even number

            double[,] medianDistances = new double[2, totElements - localSize];
            for (int i = localSize / 2 + 1; i < totElements - (localSize / 2 - 1); i++)
            {
                double[] localDistances = new double[localSize];
                for (int j = 0; j < localSize; j++)
                {
                    localDistances[j] = distances[j + (i - localSize / 2 - 1)];
                }

                // bubble sort
                for (int k = localSize; k >= 0; k--)
                {
                    for (int l = localSize - 1; l > 0; l--)
                    {
                        if (localDistances[l] < localDistances[l - 1])
                        {
                            double prov = localDistances[l - 1];
                            localDistances[l - 1] = localDistances[l];
                            localDistances[l]     = prov;
                        }
                    }
                }

                // get median

                medianDistances[0, i - (localSize / 2 + 1)] = firstSpectrum[0, i];
                medianDistances[1, i - (localSize / 2 + 1)] = (localDistances[localSize / 2 - 2]
                                                               + localDistances[localSize / 2 - 1]) / 2;
            }

            Smoother smoothy = new Smoother();

            smoothy.original = medianDistances;
            double[] coeffs = smoothy.quadraticCoefficientsABC;

            par.A                 = coeffs[0];
            par.B                 = coeffs[1];
            par.C                 = coeffs[2];
            par.initialValue      = smoothy.initialValue;
            par.hasBeenCalculated = true;
            return(par);
        }
        public double[,] getAveragedSpectrum(int _peakStart,
                                             int _peakEnd,
                                             int _peakMax,
                                             bool _takeInflections, // must be an odd number
                                             int _totSpectraTaken,  // 0 means all of them
                                             double _firstMz,
                                             double _lastMz,
                                             int _maxNumberOfZeros,
                                             ref quadraticEquation _par,
                                             Label _status)
        {
            ArrayList spectra = new ArrayList();

            if (_totSpectraTaken == 0) // 0 means all of them
            {
                spectra = takeAllFullsInRange(_peakStart, _peakEnd);
            }
            else
            {
                double RTstart = getRTfromScanNumber(_peakStart);
                double RTmax   = getRTfromScanNumber(_peakMax);
                double RTend   = getRTfromScanNumber(_peakEnd);

                int totSpectraWithoutInflections = _totSpectraTaken;
                if (_takeInflections)
                {
                    totSpectraWithoutInflections -= 2;
                }
                int lateralTot = (totSpectraWithoutInflections - 1) / 2;

                int lastSN = 0; // to avoid duplications

                // add left inflection if needed
                if (_takeInflections)
                {
                    spectra.Add(getSpectrum(_peakStart));
                    lastSN = _peakStart;
                }

                // add scans before the maximum
                double RTLateralSize = RTmax - RTstart;
                for (int j = lateralTot; j >= 1; j--)
                {
                    double RTnew = RTmax - RTLateralSize * ((double)j / ((double)lateralTot + 1));
                    int    SNnew = getScanNumberOfPrevOrNextSpectrumByType(RTnew,
                                                                           spectrumPosition.sameOrPrevious, spectrumTypes.Full);

                    if (lastSN != SNnew)
                    {
                        spectra.Add(getSpectrum(SNnew));
                        lastSN = SNnew;
                    }
                }

                // add maximum
                if (lastSN != _peakMax)
                {
                    spectra.Add(getSpectrum(_peakMax));
                    lastSN = _peakMax;
                }

                // add scans after the maximum
                RTLateralSize = RTend - RTmax;
                for (int j = 1; j <= lateralTot; j++)
                {
                    double RTnew = RTmax + RTLateralSize * ((double)j / ((double)lateralTot + 1));
                    int    SNnew = getScanNumberOfPrevOrNextSpectrumByType(RTnew,
                                                                           spectrumPosition.sameOrNext, spectrumTypes.Full);

                    if (lastSN != SNnew)
                    {
                        spectra.Add(getSpectrum(SNnew));
                        lastSN = SNnew;
                    }
                }

                // add right inflection if needed
                if (_takeInflections && lastSN != _peakEnd)
                {
                    spectra.Add(getSpectrum(_peakEnd));
                }

                //if (_totSpectraTaken == 3 && _takeInflections)
                //{
                //    spectra.Add(getSpectrum(_peakStart));
                //    spectra.Add(getSpectrum(_peakMax));
                //    spectra.Add(getSpectrum(_peakEnd));
                //}
            }

            double[,] regularBins = new double[0, 0];

            if (spectra == null)
            {
                return(null);
            }

            double[,] firstSpectrum = (double[, ])spectra[0];

            //double[,] secondSpectrum = (double[,])spectra[1];
            //double[,] thirdSpectrum = (double[,])spectra[2];

            if (!_par.hasBeenCalculated)
            {
                _status.Text = "Calculating bin size parameters...";
                Application.DoEvents();
                string rawFile = _par.rawFilePath;
                _par             = getBinParameters(firstSpectrum);
                _par.rawFilePath = rawFile;
            }

            if (regularBins.Length == 0)
            {
                regularBins = getRegularBins(_firstMz, _lastMz, _par);
            }

            int allowedMargin = 4;

            ArrayList spectraNewBins = getSpectraInNewBins(regularBins, spectra, allowedMargin);

            double[,] spectrumAverage = calculateAveragedSpectrum(spectraNewBins, allowedMargin);

            //saveIndividualSpectrum(firstSpectrum, "x1");
            //saveIndividualSpectrum(secondSpectrum, "x2");
            //saveIndividualSpectrum(thirdSpectrum, "x3");
            //saveIndividualSpectrum(spectrumAverage, "xaverage");

            return(spectrumAverage);
        }