using MathNet.Numerics;
|
using MathNet.Numerics.LinearAlgebra.Double;
|
|
namespace PBS.WinFrmUI.Hydro
|
{
|
public class CurveFitHelper
|
{
|
public DenseVector coefficients;
|
|
private int degree;
|
|
private double xMax;
|
|
private double xMin;
|
|
private List<Yw.Geometry.Point2d> data;
|
|
private bool isFitted;
|
|
public CurveFitHelper(List<Yw.Geometry.Point2d> data, int degree = 2)
|
{
|
this.degree = degree;
|
this.data = data;
|
double[] array = data.Select(((Yw.Geometry.Point2d p) => p.X)).ToArray();
|
if (data.Count > 2)
|
{
|
coefficients = Fit.Polynomial(array, (data).Select((Yw.Geometry.Point2d p) => p.Y).ToArray(), 2);
|
isFitted = true;
|
}
|
else if (data.Count == 2)
|
{
|
var tuple = Fit.Line(array, data.Select((Yw.Geometry.Point2d p) => p.Y).ToArray());
|
coefficients = new DenseVector(new double[2] { tuple.Item1, tuple.Item2 });
|
isFitted = true;
|
}
|
else if (data.Count == 1)
|
{
|
coefficients = new DenseVector(new double[1] { data[0].Y });
|
isFitted = true;
|
}
|
else
|
{
|
coefficients = new DenseVector(new double[1]);
|
isFitted = true;
|
}
|
|
List<double> source = array.ToList();
|
xMax = source.Max();
|
xMin = source.Min();
|
}
|
|
public double Evaluate(double x)
|
{
|
if (!isFitted)
|
{
|
return double.NaN;
|
}
|
|
double num = 0.0;
|
for (int i = 0; i < coefficients.Count; i++)
|
{
|
num += (double)(float)(coefficients[i] * Math.Pow(x, i));
|
}
|
|
return num;
|
}
|
|
public List<Yw.Geometry.Point2d> GetFitCurve(int count)
|
{
|
List<Yw.Geometry.Point2d> list = new List<Yw.Geometry.Point2d>();
|
for (double num = xMin; num <= xMax; num += (xMax - xMin) / (double)count)
|
{
|
if (list.Count >= count)
|
{
|
break;
|
}
|
|
double num2 = Evaluate(num);
|
list.Add(new Yw.Geometry.Point2d((float)num, (float)num2));
|
}
|
|
return list;
|
}
|
|
public List<List<Yw.Geometry.Point2d>> GetConfidenceCurve(int count)
|
{
|
List<Yw.Geometry.Point2d> list = new List<Yw.Geometry.Point2d>();
|
List<Yw.Geometry.Point2d> list2 = new List<Yw.Geometry.Point2d>();
|
List<Yw.Geometry.Point2d> list3 = new List<Yw.Geometry.Point2d>();
|
double num = 0.0;
|
double num2 = 0.0;
|
double x;
|
for (x = xMin; x < xMax; x += (xMax - xMin) / (double)count)
|
{
|
List<double> list4 = ((IEnumerable<Yw.Geometry.Point2d>)data.FindAll((Yw.Geometry.Point2d p) => x - (xMax - xMin) / (double)count / 2.0 <= (double)p.X && (double)p.X < x + (xMax - xMin) / (double)count / 2.0)).Select((Func<Yw.Geometry.Point2d, double>)((Yw.Geometry.Point2d p) => p.Y)).ToList();
|
if (list4.Count >= 3)
|
{
|
double[] confidenceRange = GetConfidenceRange(list4, 95.0);
|
double num3 = x;
|
if (confidenceRange[0] != double.NaN && confidenceRange[1] != double.NaN)
|
{
|
list2.Add(new Yw.Geometry.Point2d((float)num3, (float)confidenceRange[0]));
|
list.Add(new Yw.Geometry.Point2d((float)num3, (float)confidenceRange[1]));
|
num = x;
|
num2 = (confidenceRange[0] + confidenceRange[1]) / 2.0;
|
list3.Add(new Yw.Geometry.Point2d((float)num3, (float)num2));
|
}
|
}
|
else if (list4.Count == 2)
|
{
|
double num4 = x;
|
list2.Add(new Yw.Geometry.Point2d((float)num4, (float)list4.Min()));
|
list.Add(new Yw.Geometry.Point2d((float)num4, (float)list4.Max()));
|
num = x;
|
num2 = (list4.Min() + list4.Max()) / 2.0;
|
list3.Add(new Yw.Geometry.Point2d((float)num4, (float)num2));
|
}
|
else if (list4.Count == 1)
|
{
|
double num5 = x;
|
list2.Add(new Yw.Geometry.Point2d((float)num5, (float)list4[0]));
|
list.Add(new Yw.Geometry.Point2d((float)num5, (float)list4[0]));
|
num = x;
|
num2 = list4[0];
|
list3.Add(new Yw.Geometry.Point2d((float)num5, (float)num2));
|
}
|
else if (list4.Count == 0)
|
{
|
list2.Add(new Yw.Geometry.Point2d((float)num, (float)num2));
|
list.Add(new Yw.Geometry.Point2d((float)num, (float)num2));
|
list3.Add(new Yw.Geometry.Point2d((float)num, (float)num2));
|
}
|
}
|
|
return new List<List<Yw.Geometry.Point2d>> { list2, list, list3 };
|
}
|
|
public static double[] GetConfidenceRange(List<double> data, double confidenceLevel = 90.0, bool mode = true)
|
{
|
if (mode)
|
{
|
data.Sort();
|
int num = (int)Math.Round((double)data.Count * confidenceLevel / 100.0);
|
int num2 = (int)Math.Round((double)data.Count * (1.0 - confidenceLevel / 100.0));
|
if (num == data.Count)
|
{
|
num = data.Count - 1;
|
}
|
|
if (num2 < 0)
|
{
|
num2 = 0;
|
}
|
|
return new double[2]
|
{
|
data[num2],
|
data[num]
|
};
|
}
|
|
double num3 = double.MaxValue;
|
double num4 = double.MinValue;
|
foreach (double datum in data)
|
{
|
if (datum < num3)
|
{
|
num3 = datum;
|
}
|
|
if (datum > num4)
|
{
|
num4 = datum;
|
}
|
}
|
|
double num5 = 0.0;
|
foreach (double datum2 in data)
|
{
|
num5 += datum2;
|
}
|
|
double num6 = num5 / (double)data.Count;
|
double num7 = 0.0;
|
foreach (double datum3 in data)
|
{
|
num7 += Math.Pow(datum3 - num6, 2.0);
|
}
|
|
double num8 = Math.Sqrt(num7 / (double)(data.Count - 1));
|
double num9 = GetZValueOneTail((1.0 - confidenceLevel / 100.0) / 2.0) * num8;
|
double num10 = num6 - num9;
|
double num11 = num6 + num9;
|
return new double[2] { num10, num11 };
|
}
|
|
private static double GetZValueOneTail(double alpha)
|
{
|
if (alpha == 0.5)
|
{
|
return 0.0;
|
}
|
|
if (alpha > 0.5)
|
{
|
return 0.0 - GetZValueOneTail(1.0 - alpha);
|
}
|
|
double[] array = new double[6] { 0.1, 0.05, 0.025, 0.01, 0.005, 0.001 };
|
double[] array2 = new double[6] { 1.28, 1.645, 1.96, 2.33, 2.575, 3.09 };
|
int num = array.Length;
|
int i;
|
for (i = 0; i < num && alpha < array[i]; i++)
|
{
|
}
|
|
if (i == 0)
|
{
|
return 0.0;
|
}
|
|
if (i == num)
|
{
|
return array2[num - 1];
|
}
|
|
double num2 = array[i - 1];
|
double num3 = array[i];
|
double num4 = array2[i - 1];
|
return (array2[i] - num4) / (num3 - num2) * (alpha - num2) + num4;
|
}
|
|
|
private static bool isValid(double value)
|
{
|
if (value == (double)(int)value && value < 0.0)
|
{
|
return false;
|
}
|
|
if (!double.IsNaN(value))
|
{
|
return !double.IsInfinity(value);
|
}
|
|
return false;
|
}
|
}
|
|
|
}
|