using MathNet.Numerics.LinearAlgebra.Double; // 引入 Math.NET Numerics 库进行多项式拟合 using MathNet.Numerics; using MathNet.Numerics.LinearAlgebra; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms.DataVisualization.Charting; using Hydro.CommonBase; using Hydro.CommonBase; using Newtonsoft.Json; namespace Hydro.MapView { [Serializable] public class Dataset { public static List listString = new List() { "流量扬程曲线", "流量功率曲线", "流量效率曲线" }; public Dataset(string name, PumpViewModel pump, int Degree = 2) { Name = name; this.pump = pump; this.degree = Degree; } public override string ToString() { StringBuilder txt = new StringBuilder(); foreach (PointF point in _data) { txt.AppendLine($"{Name}\t{point.X}\t{point.Y}"); } return txt.ToString(); } //public Dataset() //{ //} public Color Color { get { switch (Name) { case "流量扬程曲线": return Color.Blue; //break; case "流量功率曲线": return Color.Orange; //break; case "流量效率曲线": return Color.Red; //break; default: return Color.Blue; } } } public string Name { get; set; } public List _data = new List(); int FitTimes = 2; public List Data { get { if (pump == null || pump.额定转速 == 0) return _data; float eg = (float)pump.当前转速 / (float)pump.额定转速; if (eg >= 1) return _data; else { switch (Name) { case "流量扬程曲线": return _data.Select(p => { p.X *= eg; p.Y *= eg * eg; return p; }).ToList(); break; case "流量功率曲线": return _data.Select(p => { p.X *= eg; p.Y *= eg * eg * eg; return p; }).ToList(); break; case "流量效率曲线": var c1 = pump.Datasets["流量扬程曲线"]; var c2 = pump.Datasets["流量功率曲线"]; if (c1.IsFitted && c2.IsFitted && c1.Data.Count == c2.Data.Count) { List points = new List(); for (int i = 0; i < c1.Data.Count; i++) { float x = c1.Data[i].X; float y = x * c1.Data[i].Y / c2.Data[i].Y / 3.6f; points.Add(new PointF(x, y)); //功率=流量* 扬程 / 效率 / 3.6f //效率=流量* 扬程 / 功率 / 3.6f } return points; } else { return _data; } break; default: return _data; } } } set { //float eg = (float)pump.当前转速 / (float)pump.额定转速; //if (eg < 1) //{ // MessageBox.Show("非额定转速,拒绝修改"); // return; //} IsFitted = false; _data = value; } } public int degree { get { return FitTimes; } set { if (FitTimes != value) this.IsFitted = false; FitTimes = value; } } public List ForumParams = null; [JsonIgnore] public DenseVector coefficients = null; // 存储多项式系数 public static double ErrNum { get { return -1; } } public static double stepNum { get { return 800; } } private double step { get { return (range_X.Max - range_X.Min) / stepNum; } } [NonSerialized] [JsonIgnore] public PumpViewModel pump = null; /// /// 不需要读取 /// public string Legend { get { switch (Name) { case "流量扬程曲线": return "Legend1"; case "流量功率曲线": return "Legend1"; case "流量效率曲线": return "Legend1"; } return "Legend1"; } } public AxisType axisType { get { switch (Name) { case "流量扬程曲线": return AxisType.Primary; default: return AxisType.Secondary; } } } public void CurveFit() { if (!HasData) { IsFitted = false; return; } coefficients = MathNet.Numerics.Fit.Polynomial(Data.Select(p => (double)p.X).ToArray(), Data.Select(p => (double)p.Y).ToArray(), degree); if (range_X == null) { range_X = new DRange(double.MaxValue, double.MinValue); Data.ForEach(p => { if (range_X.Min > p.X) range_X.Min = p.X; if (range_X.Max < p.X) range_X.Max = p.X; }); } IsFitted = true; } public double Evaluate(double x) { if (!IsFitted) return ErrNum; // 计算多项式在点 x 处的取值 double y = 0; for (int i = 0; i < coefficients.Count; i++) { y += coefficients[i] * Math.Pow(x, i); } return y; } // 定义 solve 方法来解多项式方程 //double Solve(double y) //{ // FittedCurve //} double Solve(double y) { List points = FittedCurve.ToList(); PointF prevPoint = PointF.Empty; PointF nextPoint = PointF.Empty; foreach (var point in points) { if (point.Y == y) { return point.X; } else if (point.Y > y) { nextPoint = point; } else { prevPoint = point; break; } } if (prevPoint.IsEmpty) { return points[points.Count - 1].X; //throw new Exception("No valid interpolation range found."); } else if (nextPoint.IsEmpty) { return points[0].X; } double xDiff = nextPoint.X - prevPoint.X; double yDiff = nextPoint.Y - prevPoint.Y; double slope = yDiff / xDiff; double x = prevPoint.X + (y - prevPoint.Y) / slope; if (double.IsNaN(x)) return ErrNum; else return x; } public double Evaluate_Solve(double y) { if (!IsFitted) return ErrNum; if (degree == 2) // 多项式次数 { if (!is_Yvalue_validate(y)) return ErrNum; double a = coefficients[degree]; // 二次项系数 double b = coefficients[degree - 1]; // 一次项系数 double c = coefficients[0] - y; // 常数项系数减去给定的 y 值 // 求解二次方程 ax^2 + bx + c = 0 double delta = b * b - 4 * a * c; double x1 = (-b + Math.Sqrt(delta)) / (2 * a); double x2 = (-b - Math.Sqrt(delta)) / (2 * a); // 取两个解中符合实际情况的那个(可以根据具体应用场景来确定) double x = (x2 >= x1) ? x2 : x1; if (double.IsNaN(x)) return ErrNum; else return x; } else { return Solve(y); } } public string getForum { get { if (coefficients == null) return null; // 生成多项式的字符串表示形式 string polyStr = "y="; for (int i = coefficients.Count - 1; i >= 0; i--) { if (coefficients[i] == 0) continue; if (i == coefficients.Count - 1) { polyStr += coefficients[i].ToString() + "x^" + i; } else if (i == 1) { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString() + "x"; } else { polyStr += " - " + (-coefficients[i]).ToString() + "x"; } } else if (i == 0) { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString(); } else { polyStr += " - " + (-coefficients[i]).ToString(); } } else { if (coefficients[i] > 0) { if (polyStr != "") polyStr += " + "; polyStr += coefficients[i].ToString() + "x^" + i; } else { polyStr += " - " + (-coefficients[i]).ToString() + "x^" + i; } } } if (polyStr == "") polyStr = "0"; if (degree == 2) { double a = coefficients[degree]; double b = coefficients[degree - 1]; double c = coefficients[0]; double delta = b * b - 4 * a * c; double minExtremePoint = -b / (2 * a); // 计算导函数的零点 polyStr += $" maxX:{minExtremePoint.ToString("0.0")}"; } return polyStr; } } public double[] getForumNum { get { if (coefficients == null) return null; List list = new List(); for (int i = coefficients.Count - 1; i >= 0; i--) { list.Add(coefficients[i]); } return list.ToArray(); } } public double YMax { get { if (!IsFitted) return ErrNum; double a = coefficients[degree]; double b = coefficients[degree - 1]; double c = coefficients[0]; double delta = b * b - 4 * a * c; double minExtremePoint = -b / (2 * a); // 计算导函数的零点 double maxValue = 0; if (a < 0) maxValue = -delta / (4 * a) + c; else maxValue = a * minExtremePoint * minExtremePoint + b * minExtremePoint + c; // 计算最小值 return maxValue; } } public double YdataMax { get { double max = -99999; foreach (var p in Data) { if (max < p.Y) max = p.Y; } return max; } } public bool is_Yvalue_validate(double y) { if (!IsFitted) return false; double a = coefficients[degree]; if (a < 0) return y <= YMax; else return y >= YMax; } /// /// X显示的范围 /// public DRange range_X; /// /// Y显示的范围 /// public DRange range_Y; public bool HasData { get { return Data.Count >= 3; } } public bool IsFitted = false; public List FittedCurve { get { if (range_X == null) return null; List doubles = new List(); for (double x = range_X.Min; x <= range_X.Max; x += step) { double y = Evaluate(x); //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF((float)x, (float)y)); } return doubles; } } public List FittedCurvebyRange(DRange range) { List doubles = new List(); if (range == null) { range = new DRange(); range.Min = range_X.Min; range.Max = range_X.Max; } var step = (range.Max - range.Min) / stepNum; for (double x = range.Min; x <= range.Max; x += step) { double y = Evaluate(x); //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF((float)x, (float)y)); } return doubles; } } }