protected PointIndexPair Find(int fromIndex, ExtremaSearchConfig config, double[] intervals, double[] amplitude, Func <double, double, bool> isMatchingCriteria) { int maxSmoothSize = 5; double extremaAmplitude = config.StartAmplitude.HasValue ? config.StartAmplitude.Value : amplitude[fromIndex]; // begin with initial search amplitude int extremaInterval = fromIndex; int extremaCount = 0; if ((fromIndex + maxSmoothSize) >= intervals.Length) { maxSmoothSize = 1; } // look at the average of a group of points rather than a single point to determine min/max LinkedList <double> smoothedData = new LinkedList <double>(Enumerable.Range(0, maxSmoothSize).Select(i => amplitude[fromIndex + i])); // find the first local min/max bool indexOutOfRange = false; for (int i = (fromIndex + maxSmoothSize - 1), j = 0; i < amplitude.Length; i++, j++) { if (config.SearchIndexLimit.HasValue && j > config.SearchIndexLimit.Value) { Console.WriteLine("MISSING POINT!!!"); indexOutOfRange = true; break; } double smoothedAverage = smoothedData.Average(); if (isMatchingCriteria.Invoke(smoothedAverage, extremaAmplitude)) { extremaAmplitude = smoothedAverage; extremaInterval = (i - (int)Math.Floor(maxSmoothSize / 2.0)); extremaCount = 0; } else { // if sensitivity readings are lower then the previous min/max then the first local min/max was reached extremaCount++; if (extremaCount > config.Sensitivity) { break; } } // remove the first force value for the list and add the next smoothedData.RemoveFirst(); if ((i + 1) < amplitude.Length) { smoothedData.AddLast(amplitude[(i + 1)]); } } return(new PointIndexPair(extremaAmplitude, extremaInterval, indexOutOfRange)); }
protected PointIndexPair Find(ExtremaPointType type, int fromIndex, ExtremaSearchConfig config, double[] intervals, double[] amplitude) { if (type == ExtremaPointType.LOCAL_MAX) { return(Find(fromIndex, config, intervals, amplitude, (smoothedValue, extremaAmplitide) => smoothedValue > extremaAmplitide)); } else { return(Find(fromIndex, config, intervals, amplitude, (smoothedValue, extremaAmplitide) => smoothedValue < extremaAmplitide)); } }
protected override double[] Extract(double[] intervals, double[] amplitude) { ExtremaPointType nextLocalPoint = start; int fromIndex = 0; List <double[]> pointFeatures = new List <double[]>(); using (IEnumerator <ExtremaSearchConfig> iterator = searchConfig.GetEnumerator()) { while (iterator.MoveNext()) { ExtremaSearchConfig config = iterator.Current; PointIndexPair extremaPoint = Find(nextLocalPoint, fromIndex, config, intervals, amplitude); if (extremaPoint.IndexOutOfRange && config.GeometricRecoveryConfig != null) { GeometricRecoveryConfig recoveryConfig = config.GeometricRecoveryConfig; // use triangular approximation to attempt missing point recovery (need to do 2 points - this + next to approximate missing point) extremaPoint = FindTriangular(nextLocalPoint, fromIndex, recoveryConfig.FirstPointSensitivity, recoveryConfig.FirstTriangleLength, intervals, amplitude); // add first recovered point pointFeatures.Add(GetFeatures(extremaPoint, intervals, config.DataModel)); // skip forward one if we can since we've already found the next point if (!iterator.MoveNext()) { break; } config = iterator.Current; // recover the second point (which would also be "missing") nextLocalPoint = Alternate(nextLocalPoint); extremaPoint = FindTriangular(nextLocalPoint, extremaPoint.PointIndex, recoveryConfig.SecondPointSensitivity, recoveryConfig.SecondTriangleLength, intervals, amplitude); } pointFeatures.Add(GetFeatures(extremaPoint, intervals, config.DataModel)); fromIndex = extremaPoint.PointIndex; nextLocalPoint = Alternate(nextLocalPoint); } } return(pointFeatures.SelectMany(p => p).ToArray()); }