public PairDouble evaluateResonanceFrequency(ChartTypes type, SignalUnits targetUnits, double approximationResonanceFrequency = 0.0) { int kNumSteps = 4096; // Only acceleration data is used to estimate the resonance frequency SignalUnits baseUnits = SignalUnits.UNKNOWN; if (data[SignalUnits.METERS_PER_SECOND2] != null) { baseUnits = SignalUnits.METERS_PER_SECOND2; } else if (data.ContainsKey(SignalUnits.METERS_PER_SECOND2_PER_FORCE) && data[SignalUnits.METERS_PER_SECOND2_PER_FORCE] != null) { baseUnits = SignalUnits.METERS_PER_SECOND2_PER_FORCE; } if (baseUnits == SignalUnits.UNKNOWN) { return(null); } double[,] complexData = data[baseUnits]; int nData = frequency.Length; double[] realPart = new double[nData]; double[] imagPart = new double[nData]; for (int i = 0; i != nData; ++i) { realPart[i] = complexData[i, 0]; imagPart[i] = complexData[i, 1]; } LinearSpline splineRealPart = LinearSpline.InterpolateSorted(frequency, realPart); LinearSpline splineImagPart = LinearSpline.InterpolateSorted(frequency, imagPart); List <double> resFrequencies = null; Func <double, double> fun = null; Func <double, double> diffFun = null; switch (type) { case ChartTypes.REAL_FREQUENCY: fun = x => splineRealPart.Interpolate(x); diffFun = x => splineRealPart.Differentiate(x); break; case ChartTypes.IMAG_FREQUENCY: fun = x => splineImagPart.Differentiate(x); diffFun = x => splineImagPart.Differentiate2(x); break; } if (fun == null || diffFun == null) { return(null); } double startFrequency = frequency[0]; double endFrequency = frequency[nData - 1]; resFrequencies = findAllRootsBisection(fun, startFrequency, endFrequency, kNumSteps); if (resFrequencies == null || resFrequencies.Count == 0) { return(null); } double distance; double minDistance = Double.MaxValue; int indClosestResonance = 0; int numFrequencies = resFrequencies.Count; for (int i = 0; i != numFrequencies; ++i) { try { resFrequencies[i] = NewtonRaphson.FindRootNearGuess(fun, diffFun, resFrequencies[i], startFrequency, endFrequency); } catch { } distance = Math.Abs(resFrequencies[i] - approximationResonanceFrequency); if (distance < minDistance) { minDistance = distance; indClosestResonance = i; } } double resonanceFrequency = resFrequencies[indClosestResonance]; // Evaluate the amplitude value by using data of the target type if (baseUnits != targetUnits) { complexData = data[targetUnits]; for (int i = 0; i != nData; ++i) { realPart[i] = complexData[i, 0]; imagPart[i] = complexData[i, 1]; } splineRealPart = LinearSpline.InterpolateSorted(frequency, realPart); splineImagPart = LinearSpline.InterpolateSorted(frequency, imagPart); } double realPeak = splineRealPart.Interpolate(resonanceFrequency); double imagPeak = splineImagPart.Interpolate(resonanceFrequency); double ampPeak = Math.Sqrt(Math.Pow(realPeak, 2.0) + Math.Pow(imagPeak, 2.0)); return(new PairDouble(resonanceFrequency, ampPeak)); }