namespace IStation.Curve { /// /// 样条曲线(三次拟合):使用MathNet /// public class TwinRelateCurve3M : IFitPoint { /// /// /// public TwinRelateCurve3M(CurveExpress express) { _express = express; } /// /// /// public TwinRelateCurve3M(List points) { if (points == null || points.Count < 4) { throw new Exception("出现数值计算问题 ,无法解出三次样条曲线!"); } _express = BuildCurveExpress(points); } //曲线表达式 private CurveExpress _express = null; /// /// 获取拟合点Y /// public double GetFitPointY(double x) { if (_express == null) return default; var dx = x;// - _express.Min; //不用减掉最小值, 和alglib有点不一样 return _express.Index3 * dx * dx * dx + _express.Index2 * dx * dx + _express.Index1 * dx + _express.Index0; } /// /// 获取拟合点列表 /// public List GetFitPoints(int pointNumber) { if (_express == null) { return null; } if (pointNumber < 1) { pointNumber = 12; } if (pointNumber > 10000) { pointNumber = 10000; } double space = (_express.Max - _express.Min) / (pointNumber - 1); if (space < 0.0001) { return null; } List points = new List(); for (int i = 0; i < pointNumber; i++) { double x = space * i + _express.Min; double y = GetFitPointY(x); points.Add(new CurvePoint(x, y)); } return points; } /// /// 通过X区间获取拟合点列表 /// public List GetFitPointsByXRange(double minX, double maxX, int pointNumber) { if (pointNumber < 1) { pointNumber = 12; } if (pointNumber > 10000) { pointNumber = 10000; } if (minX >= maxX) {//交换大小 var x_m = maxX; maxX = minX; minX = x_m; } double space = (maxX - minX) / (pointNumber - 1); if (space < 0.0001) { return default; } if (_express == null) { return null; } if (pointNumber < 1) { pointNumber = 12; } if (pointNumber > 10000) { pointNumber = 10000; } if (space < 0.0001) { return null; } List points = new List(); for (int i = 0; i < pointNumber; i++) { double x = space * i + minX; double y = GetFitPointY(x); points.Add(new CurvePoint(x, y)); } return points; } /// /// 创建曲线表达式 /// public static CurveExpress BuildCurveExpress(List points) { if (points == null || points.Count < 4) return null; var express = new CurveExpress(); express.DefinePoints = points; var X = (from x in points select x.X).ToArray(); var Y = (from x in points select x.Y).ToArray(); var min = X.Min(); var max = X.Max(); var res = Fit.Polynomial(X, Y, 3); //曲线类型 express.FitType = eFitType.CubicCurve; express.DefinePoints = points.Select(x => new CurvePoint(x)).ToList(); //范围 express.Min = X.Min(); //最小值 express.Max = X.Max();//最大值 //0次方 express.Index0 = res[0]; //1次方 express.Index1 = res[1]; //2次方 express.Index2 = res[2]; //3次方 express.Index3 = res[3]; return express; } } }