예제 #1
0
        public HrvResults ProcessData(HrvRawData rawHrvData)
        {
            base.ProcessData(rawHrvData);

            double[] valid_intervals_durations    = null;
            List <CardioInterval> valid_intervals = null;

            // recorded data contains cardio intervals
            // this is the case when the inspection was performed
            // using a cardio intervals sensor
            // (e.g. Bluetooth HR sensor with RR intervals)
            if (InputDataContainsCardioIntervals(rawHrvData))
            {
                var heartRythmData = ReadCardioIntervalsFromResultSet(rawHrvData);
                valid_intervals           = heartRythmData.Item1;
                HrvResults.RATED_HR_MARKS = heartRythmData.Item2.ToArray();
            }
            else
            {
                ChannelData data = null, adc_data = null;
                double[]    hrv_marks = null;

                SelectAndProcessSignal(m_settings.RejectLowQualitySignalAreas, rawHrvData, out hrv_marks, out data, out adc_data);

                if ((null == data) || (null == adc_data))
                {
                    throw new DataProcessingException(strings.NoSignalInSourceData);
                }

                HrvResults.CRV_CARDIO_SIGNAL = new PhysioSignalView(
                    data.GetDataAsFloat(),
                    (int)data.BitsPerSample,
                    (float)data.SamplingRate,
                    data.PhysioSignalType
                    );

                HrvResults.CRV_CARDIO_SIGNAL_ADC = new PhysioSignalView(
                    adc_data.GetDataAsFloat(),
                    (int)adc_data.BitsPerSample,
                    (float)adc_data.SamplingRate,
                    adc_data.PhysioSignalType
                    );

                // отметки пульса с оценкой достоверности
                var hc_marks_to_rate = new List <RatedContractionMark>(hrv_marks.Length);
                for (int i = 0; i < hrv_marks.Length; ++i)
                {
                    var mark = new RatedContractionMark
                    {
                        Position = hrv_marks[i],
                        Valid    = false
                    };
                    hc_marks_to_rate.Add(mark);
                }

                // получаем достоверные интервалы в миллисекундах,
                // "хорошие" сокращения будут помечены как хорошие (по обоим параметрам),
                var converted_peaks =
                    PeaksFilter.ConvertPeaksToIntervalsWithRejectionAndRatePeaks(
                        hc_marks_to_rate,
                        data.SamplingRate,
                        m_settings.GetApplicableMinIntervalLength(),
                        m_settings.GetApplicableMaxIntervalLength(),
                        m_settings.GetApplicableMaxIntervalDeltaRelative(),
                        adc_data);

                valid_intervals = converted_peaks.extracted_intervals;
                if (converted_peaks.extracted_intervals.Count < 5)
                {
                    throw new DataProcessingException(string.Format(strings.too_few_intervals_detected_in_signal, valid_intervals.Count));
                }

                // это все отметки пульса
                HrvResults.CRV_HR_MARKS = hrv_marks;

                // это отметки пульса с оценками качества
                HrvResults.RATED_HR_MARKS = converted_peaks.rated_heart_contraction_marks.ToArray();

                // Спектр сигнала ФПГ
                HrvResults.SignalSpectrum = PpgSpectrumAnalyzer.CalculateSpectrum(data.Data, data.SamplingRate);
            }

            // только длительности интервалов
            valid_intervals_durations = (from interval in valid_intervals select interval.duration).ToArray();

            var peakAmoDistrib = default(MinMaxModeDescriptor);

            // кардио-интервалы подготовлены
            try
            {
                var mathStatData = new StatData();
                // считаем статистику по кардио-интервалам
                Calculator.CalcStatistics(valid_intervals_durations, mathStatData);
                Calculator.MakeProbabilityDensity(valid_intervals_durations, mathStatData, 440, 2000, 4);

                // The standard approach
                Calculator.MakeDistribution(valid_intervals_durations, mathStatData, 0, 2500, 50);

                // Find the maximized & minimized mode amplitude values
                peakAmoDistrib = MinMaxModeAmpFinder.GetPeakAmoDistrib(valid_intervals_durations, 50, 0, 2500, 1);

                HrvResults.CRV_STAT = _mapper.Map <Methods.ObjectModel.Statistics.StatData>(mathStatData);
            }
            catch (ArgumentException)
            {
                throw new DataProcessingException(
                          string.Format(strings.too_few_valid_intervals_detected_in_signal, valid_intervals_durations.Length));
            }

            HrvResults.Indicators.HRV_Triangular_Index = CalcHrvTriangularIndex(valid_intervals_durations);

            double AMo = Statistics.distribution.mode_amplitude; // Безразмерная -- в долях от 1
            double Mo  = Statistics.distribution.mode / 1000;    // В секундах!!!
            //double AMo = peakAmoDistrib.ModeAmp;   // Безразмерная -- в долях от 1
            //double Mo = peakAmoDistrib.Mode / 1000;       // В секундах!!!
            double M     = Statistics.m / 1000;                        // В секундах!!!
            double dNN   = Statistics.varRange / 1000;                 // В секундах!!!
            double Sigma = Statistics.sigma / 1000;                    // В секундах!!!

            var _AMo = Statistics.distribution.mode_amplitude;         // Безразмерная -- в долях от 1
            var _Mo  = Statistics.distribution.mode / 1000;            // В секундах!!!

            var AmoMax = peakAmoDistrib.MaxModeDescriptor.ModeAmp;     // maximized Mode Amplitude
            var MoMax  = peakAmoDistrib.MaxModeDescriptor.Mode / 1000; // Mode when the Mode amplitude is maximized

            var AmoMin = peakAmoDistrib.MinModeDescriptor.ModeAmp;     // minimized Mode Amplitude
            var MoMin  = peakAmoDistrib.MinModeDescriptor.Mode / 1000; // Mode when the Mode amplitude is minimized

            var AmoMid = peakAmoDistrib.MidModeDescriptor.ModeAmp;     // mean Mode Amplitude
            var MoMid  = peakAmoDistrib.MidModeDescriptor.Mode / 1000; // Mode when the Mode amplitude is close to mean

            // Вычислим индексы Баевского
            // умножаем на 100, т.к. "по Баевскому" АМо указывается в %%.
            HrvResults.Indicators.IN = AMo * 100 / (2.0 * Mo * dNN);

            HrvResults.Indicators.IN_Max     = AmoMax * 100 / (2.0 * MoMax * dNN);
            HrvResults.Indicators.IN_MaxMode = MoMax;

            HrvResults.Indicators.IN_Min     = AmoMin * 100 / (2.0 * MoMin * dNN);
            HrvResults.Indicators.IN_MinMode = MoMin;

            HrvResults.Indicators.IN_Mid     = AmoMid * 100 / (2.0 * MoMid * dNN);
            HrvResults.Indicators.IN_MidMode = MoMid;

            // TODO: выяснить, что правильно, что нет: m_BaevskyStatistics._VPR = 1.f / (fM * fX);
            HrvResults.Indicators.VPR  = 1.0 / (Mo * dNN);
            HrvResults.Indicators.PAPR = AMo * 100 / Mo;
            HrvResults.Indicators.IVR  = AMo * 100 / dNN;

            // Психофизиологическая цена [адаптации]
            // АМ [%%] / ( Мат. ожидание [с] * сигма [с] )
            // умножаем на 100, т.к. АМо д.б. в %%.
            HrvResults.Indicators.PPPA = AMo * 100 / (M * Sigma);

            // Передать в результаты теста также и сами кардиоинтервалы
            // с моментами их появления в записи
            HrvResults.CRV_INTERVALS = valid_intervals.ToArray();

            // Спектр кардиоинтервалов
            HrvResults.IntervalsSpectrum = HrvSpectrumAnalyzer.MakeCardioIntervalsSpectrum(valid_intervals);

            double sum = 0.0;
            double n50 = (valid_intervals[0].duration > 50) ? 1 : 0;

            for (int i = 1; i < valid_intervals.Count; i++)
            {
                double diff = valid_intervals[i].duration - valid_intervals[i - 1].duration;
                sum += Math.Pow(diff, 2);
                if (diff > 50)
                {
                    n50++;
                }
            }

            HrvResults.Indicators.pNN50 = 100.0 * n50 / (valid_intervals.Count - 1);
            HrvResults.Indicators.RMSSD = Math.Sqrt(sum);

            HrvResults.CRV_SCATTEROGRAMM_PARAMETERS = GetScatterParams(valid_intervals_durations);

            HrvResults.ResultsReliability = GetResultsReliability(HrvResults);

            return((HrvResults)ProcessorOutputData);
        }
예제 #2
0
        private static double Estimate_AverageInterval(
            List <RatedContractionMark> hr_marks_to_rate,
            double data_rate,
            double min_interval_length,
            double max_interval_length,
            double max_relative_delta
            )
        {
            double[] coordinates = new double[hr_marks_to_rate.Count];
            for (int i = 0; i < coordinates.Length; ++i)
            {
                coordinates[i] = hr_marks_to_rate[i].Position;
            }

            // это черновой список интервалов, учитывающий всю последовательность
            // интервалов, получающихся из всей последовательности сокращений за исключением
            // интервалов, не удовлетворяющих ограничениям min_interval_length, max_interval_length
            // и max_relative_delta.
            // при проверке первого интервала на относительное изменение величина предыдущего интервала
            // принимается равной значению моды черновой последовательности кардио-интервалов.
            var draft_intervals = PeaksFilter.CoordinatesToIntervals(coordinates, data_rate);

            var draft_durations = new List <double>(draft_intervals.Count);

            foreach (CardioInterval draft_interval_1 in draft_intervals)
            {
                draft_durations.Add(draft_interval_1.duration);
            }
            double[] draft_durations_array = draft_durations.ToArray();
            var      stat = new PskOnline.Math.Statistics.StatData();

            PskOnline.Math.Statistics.Calculator.CalcStatistics(draft_durations_array, stat);
            PskOnline.Math.Statistics.Calculator.MakeProbabilityDensity(draft_durations_array, stat, 400, 2000, 4);

            double ave = 0;
            double prev_interval_duration = stat.probability_density.mode;
            int    draft_count            = 0;
            bool   bLengthOk = false;
            bool   bRDeltaOk = false;

            foreach (CardioInterval draft_interval in draft_intervals)
            {
                bLengthOk = (draft_interval.duration >= min_interval_length) &&
                            (draft_interval.duration <= max_interval_length);

                bRDeltaOk = (max_relative_delta >= (System.Math.Abs(prev_interval_duration - draft_interval.duration) / prev_interval_duration));

                if (bLengthOk && bRDeltaOk)
                {
                    // учтем "хороший" интервал
                    ave += draft_interval.duration;
                    ++draft_count;
                    prev_interval_duration = draft_interval.duration;
                }
            }

            if (draft_count == 0)
            {
                throw new DataProcessingException(
                          string.Format(strings.too_few_valid_intervals_detected_in_signal, draft_count));
            }

            return(ave / ((double)draft_count));
        }