/// <summary>
        /// Return tonic statistic.
        /// </summary>
        ///
        /// <param name="tonicCoordinates">List of SCL tonic signal values.</param>
        /// <param name="numberOfAffectedPoints">Number of affected points.</param>
        ///
        /// <returns>
        /// Tonic statistic for a specified lst of SCL tonic signal values.
        /// </returns>
        public TonicStatistics GetTonicStatistic(List <SignalDataByTime> tonicCoordinates, int numberOfAffectedPoints)
        {
            InflectionLine         inflectionLinesHandler = new InflectionLine();
            List <InflectionPoint> inflectionPoints       = inflectionLinesHandler.GetInflectionPoints(AffectedCoordinatePoints(tonicCoordinates, numberOfAffectedPoints), "lowPass");

            return(GetTonicStatisticsForPoints(inflectionPoints));
        }
        /// <summary>
        /// Calculate arousal statistics for the passed time window.
        /// </summary>
        ///
        /// <param name="highPassCoordinates">List of all signal values stored in the cache.</param>
        /// <param name="numberOfAffectedPoints">Number of affected points.</param>
        /// <param name="timeWindow">Time wondow.</param>
        ///
        /// <returns>
        /// Arousal statistics for the passed time window.
        /// </returns>
        private ArousalStatistics GetArousalInfoForCoordinates(List <SignalDataByTime> highPassCoordinates, int numberOfAffectedPoints, double timeWindow)
        {
            InflectionLine          inflectionLinesHandler          = new InflectionLine();
            List <SignalDataByTime> highPassCoordinatesByTimeWindow = AffectedCoordinatePoints(highPassCoordinates, numberOfAffectedPoints);
            List <InflectionPoint>  inflectionPoints = inflectionLinesHandler.GetInflectionPoints(highPassCoordinatesByTimeWindow, "highPass");
            ArousalStatistics       result           = new ArousalStatistics();

            result = GetArousalInfoForInflectionPoints(inflectionPoints, timeWindow);
            result.SCRArousalArea          = GetArousalArea(highPassCoordinatesByTimeWindow, timeWindow);
            result.MovingAverage           = GetMovingAverage(signalValues, numberOfAffectedPoints);
            result.GeneralArousalLevel     = GetGeneralArousalLevel(result.MovingAverage);
            result.SCRAchievedArousalLevel = GetPhasicLevel(result.SCRArousalArea);
            result.LastValue          = highPassCoordinates.ElementAt(highPassCoordinates.Count - 1).HighPassValue;
            result.LastRawSignalValue = signalValues.ElementAt(signalValues.Length - 1).SignalValue;

            return(result);
        }
        /// <summary>
        /// Calculate following arousal features:
        /// - SCR Amplitude;
        /// - SCR Rise
        /// - SCR Recovery
        /// </summary>
        ///
        /// <param name="inflectionPoints"> List of inflection points. </param>
        /// <param name="timeWindow"> Time window. </param>
        ///
        /// <returns>
        /// Arousal statistic with information for SCR Amplitude, SCR Rise, and SCR Recovery.
        /// </returns>
        public ArousalStatistics GetArousalInfoForInflectionPoints(List <InflectionPoint> inflectionPoints, double timeWindow)
        {
            InflectionLine inflectionLinesHandler = new InflectionLine();

            ArousalStatistics arousalStat      = new ArousalStatistics();
            ArousalFeature    scrAmplitude     = new ArousalFeature("Amplitude");
            ArousalFeature    scrRise          = new ArousalFeature("Rise time");
            ArousalFeature    scrRecovery      = new ArousalFeature("Recovery time");
            List <double>     allMaximums      = new List <double>();
            List <double>     allRises         = new List <double>();
            List <double>     allRecoveryTimes = new List <double>();
            double            sumMaximums      = 0;
            double            sumRises         = 0;
            double            sumRecoveryTime  = 0;
            int  indexPreviousMinimum          = -1;
            int  indexNextMinimum       = -1;
            bool passInitialization     = false;
            bool passInitializationRice = false;
            bool isRecoveryExist        = false;

            for (int i = 0; i < (inflectionPoints.Count); i++)
            {
                if (inflectionPoints.ElementAt(i).ExtremaType.Equals(ExtremaType.Minimum))
                {
                    indexPreviousMinimum = i;
                }

                if (inflectionPoints.ElementAt(i).ExtremaType.Equals(ExtremaType.Maximum))
                {
                    //for rise statistics we have to find previous min. current maximum and next minimum
                    double x0 = (indexPreviousMinimum > -1) ? inflectionPoints.ElementAt(indexPreviousMinimum).CoordinateX : inflectionPoints.ElementAt(0).CoordinateX;
                    double x1 = inflectionPoints.ElementAt(i).CoordinateX;
                    double y1 = inflectionPoints.ElementAt(i).CoordinateY;

                    //searching for the next minimum
                    for (int j = (i + 1); j < inflectionPoints.Count; j++)
                    {
                        if (inflectionPoints.ElementAt(j).ExtremaType.Equals(ExtremaType.Minimum))
                        {
                            indexNextMinimum     = j;
                            indexPreviousMinimum = indexNextMinimum;
                            isRecoveryExist      = true;
                            break;
                        }
                    }

                    double x2 = (isRecoveryExist) ? inflectionPoints.ElementAt(indexNextMinimum).CoordinateX : 0.0;
                    isRecoveryExist = isRecoveryExist && (x2 - x1).CompareTo(0.1) > 0;

                    double currentAmplitude = y1;

                    double currentRise      = x1 - x0;
                    double currentRecouvery = (isRecoveryExist) ? (x2 - x1) / 2 : 0.0;

                    if (!passInitialization)
                    {
                        scrAmplitude.Maximum = currentAmplitude;
                        scrAmplitude.Minimum = currentAmplitude;

                        if (isRecoveryExist && currentRecouvery.CompareTo(0.0) > 0)
                        {
                            scrRecovery.Maximum = currentRecouvery;
                            scrRecovery.Minimum = currentRecouvery;
                        }

                        passInitialization = true;
                    }
                    else
                    {
                        scrAmplitude.Maximum = (scrAmplitude.Maximum.CompareTo(currentAmplitude) < 0) ? currentAmplitude : scrAmplitude.Maximum;
                        scrAmplitude.Minimum = (scrAmplitude.Minimum.CompareTo(currentAmplitude) > 0 && currentAmplitude.CompareTo(0.0) != 0) ? currentAmplitude : scrAmplitude.Minimum;

                        if (isRecoveryExist && currentRecouvery.CompareTo(0.0) > 0)
                        {
                            scrRecovery.Maximum = (scrRecovery.Maximum.CompareTo(currentRecouvery) < 0) ? currentRecouvery : scrRecovery.Maximum;
                            scrRecovery.Minimum = (scrRecovery.Minimum.CompareTo(currentRecouvery) > 0) ? currentRecouvery : scrRecovery.Minimum;
                        }
                    }

                    if (i > 0 && !passInitializationRice && (currentRise.CompareTo(0.1) > 0))
                    {
                        scrRise.Maximum = currentRise;
                        scrRise.Minimum = currentRise;

                        passInitializationRice = true;
                    }
                    else if (i > 0 && passInitializationRice && (currentRise.CompareTo(0.1) > 0))
                    {
                        scrRise.Maximum = (scrRise.Maximum.CompareTo(currentRise) < 0) ? currentRise : scrRise.Maximum;
                        scrRise.Minimum = (scrRise.Minimum.CompareTo(currentRise) > 0) ? currentRise : scrRise.Minimum;
                    }

                    if (isRecoveryExist && currentRecouvery.CompareTo(0.0) > 0)
                    {
                        allRecoveryTimes.Add(currentRecouvery);
                        sumRecoveryTime += currentRecouvery;
                    }

                    allMaximums.Add(currentAmplitude);
                    sumMaximums += currentAmplitude;

                    if ((i > 0) && (currentRise.CompareTo(0.1) > 0))
                    {
                        allRises.Add(currentRise);
                        sumRises += currentRise;
                    }

                    if (isRecoveryExist)
                    {
                        i = indexNextMinimum;
                    }
                }

                isRecoveryExist = false;
            }

            scrAmplitude.Mean         = (allMaximums != null && allMaximums.Count > 0) ? Convert.ToDecimal(sumMaximums / allMaximums.Count, CultureInfo.InvariantCulture) : 0;
            scrAmplitude.Count        = allMaximums.Count / timeWindow;
            scrAmplitude.StdDeviation = GetStandardDeviation(allMaximums, scrAmplitude.Mean);
            arousalStat.SCRAmplitude  = scrAmplitude;

            scrRise.Mean         = (allRises != null && allRises.Count > 0) ? Convert.ToDecimal(sumRises / allRises.Count, CultureInfo.InvariantCulture) : 0;
            scrRise.Count        = allRises.Count / timeWindow;
            scrRise.StdDeviation = GetStandardDeviation(allRises, scrRise.Mean);
            arousalStat.SCRRise  = scrRise;

            scrRecovery.Mean            = (allRecoveryTimes != null && allRecoveryTimes.Count > 0) ? Convert.ToDecimal(sumRecoveryTime / allRecoveryTimes.Count, CultureInfo.InvariantCulture) : 0;
            scrRecovery.Count           = allRecoveryTimes.Count / timeWindow;
            scrRecovery.StdDeviation    = GetStandardDeviation(allRecoveryTimes, scrRecovery.Mean);
            arousalStat.SCRRecoveryTime = scrRecovery;

            return(arousalStat);
        }