ningshuxia
2025-04-16 a67da735b33be01b24845ce03ae7551cf55ddbbc
02-desktop/Desktop/IStation.Test/Program.cs
@@ -1,802 +1,236 @@
using IStation.Curve;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double;
using IStation.Model;
using System.Data;
using System.Text;
namespace IStation.Test
{
    internal class Program
    {
        // 过滤无效数据
        // 1输模型修正
        // 2输数据修正
        // 修正组合偏差
        static void Main(string[] args)
        {
            var bll = new BLL.StationSignalRecordPacket();
            var projectId = 661070185922629;
            IStation.SettingsD.Project.ID = projectId;
            var monitorDataSourcesId = 606203941007429;
            var dateStart = new DateTime(2024, 1, 1);
            var dateEnd = new DateTime(2025, 1, 1);
            var stationDict = new Dictionary<int, long>
            //Station1Helper.Start();  //1 数据修正
            //Station2Helper.Start();  //2 模型修正
            // 3  python修正
            //Completion();            //4 修正后相似换算修正
            //StationCombineHelper.Start(1);// 5 组合偏差修正
            //StationCombineHelper.Start(2);// 5 组合偏差修正
            StationCombineHelper.Start(3);// 6 分析泵频谱系数
            Console.WriteLine();
            Console.WriteLine("ok");
            Console.ReadKey();
        }
        public static void Completion()
        {
            var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pumpcsv");
            var fileNameList = Directory.GetFiles(fullPath).Select(x => Path.GetFileNameWithoutExtension(x)).ToList();
            fileNameList = fileNameList.Where(x => x.Contains("update_curve")).ToList();
            if (fileNameList == null || fileNameList.Count() < 1)
                return;
            var deleteList = fileNameList.Where(x => x.Contains("similar") || x.Contains("def")).ToList();
            deleteList?.ForEach(x => File.Delete(x));
            var flagCurveDict = GetFlagCurveDict();
            fileNameList.RemoveAll(x => x.Contains("similar") ||x.Contains("def"));
            var group = fileNameList.Where(x => x.Contains("update_curve")).GroupBy(x => x.Substring(0, 2));
            foreach (var flagItem in group)
            {
                { 1, 462958406303813 },
                { 2, 462958422204485 }
            };
            var ptFilterList = new List<PointViewModel>();
            foreach (var station in stationDict)
            {
                var stationIndex = station.Key;
                var stationId = station.Value;
                var packets = bll.Get(monitorDataSourcesId, stationId);
                var ptList = new List<PointViewModel>();
                var records = packets.SelectMany(x => x.StationSignalRecords).ToList();
                foreach (var x in records)
                if (!int.TryParse(flagItem.Key, out int flag))
                    continue;
                var files = flagItem.OrderBy(x => x).ToList();
                var fileInfoList = new List<(int Hz, string FileName)>();
                foreach (var fileName in files)
                {
                    if (x.TotalPressure > 0 && x.TotalFlow > 0)
                    var hz = fileName.Substring(3, 2);
                    if (!int.TryParse(hz, out int hzInt))
                        continue;
                    if (hzInt > 50)
                    {
                        //if (stationIndex == 2 && Math.Abs(x.DiffFlow) > 0)
                        if (stationIndex == 2 && x.DiffFlow > 0)
                        continue;
                    }
                    fileInfoList.Add((hzInt, fileName));
                }
                if (fileInfoList.Count == 1 && fileInfoList[0].Hz==50)
                {
                    continue;
                }
                for (int i = 25; i <= 50; i++)
                {
                    var maxHz = fileInfoList.Max(x => x.Hz);
                    var curvePointList = new List<CurvePoint>();
                    var fileName = string.Empty;
                    var currentHz = i;
                    var newFileName = "";
                    if (fileInfoList.Exists(x => x.Hz == i))
                    {
                        continue;
                    }
                    else if (currentHz == 50)
                    {
                        var curve = flagCurveDict[flag];
                        curvePointList = curve.GetFitPoints(100).ToList();
                        newFileName = $"{flagItem.Key}_{50}_update_curve_def.csv";
                    }
                    else if (currentHz > maxHz)
                    {
                        var curve = flagCurveDict[flag];
                        var similar_qh = Model.CurveCalcuHelper.CalculateSimilarQH(curve, 50, currentHz);
                        if (similar_qh == null)
                        {
                            continue;
                        }
                        ptList.Add(new PointViewModel(x.Time, x.TotalFlow, x.TotalPressure, x.DiffFlow, stationIndex));
                    }
                }
                //var newPtList = DynamicThresholdProcessorHelper.Filter(ptList);
                var newPtList = ptList;
                ptFilterList.AddRange(newPtList);
            }
            var recordList = new List<RecordViewModel>();
            var timeGroup = ptFilterList.GroupBy(x => x.Time);
            foreach (var group in timeGroup)
            {
                if (group.Count() < 2)
                    continue;
                var record = new RecordViewModel
                {
                    Time = group.Key
                };
                foreach (var item in group)
                {
                    if (item.Index == 1)
                    {
                        record.Flow1 = item.X;
                        record.Pressure1 = item.Y;
                        curvePointList = similar_qh.GetFitPoints(100).ToList();
                        newFileName = $"{flagItem.Key}_{currentHz}_update_curve_similar_def.csv";
                    }
                    else
                    {
                        record.Flow2 = item.X;
                        record.Pressure2 = item.Y;
                        record.FlowDiff2 = item.Diff;
                        var (Hz, FileName) = fileInfoList.FirstOrDefault(x => x.Hz > i);
                        if (Hz < 1)
                            continue;
                        var updateCurvePtList = new List<CurvePoint>();
                        var updateCurveFile = Path.Combine(fullPath, $"{flagItem.Key}_{Hz}_update_curve.csv");
                        using (var fs = new FileStream(updateCurveFile, FileMode.Open, FileAccess.Read))
                        using (var sr = new StreamReader(fs, Encoding.UTF8))
                        {
                            var strLine = string.Empty;
                            sr.ReadLine();
                            while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
                            {
                                var strList = strLine.Split(',');
                                var x = double.Parse(strList[0]);
                                var y = double.Parse(strList[1]);
                                updateCurvePtList.Add(new CurvePoint(x, y));
                            }
                        }
                        var similar_qh = Model.CurveCalcuHelper.CalculateSimilarQH(new CurveExpress(updateCurvePtList), Hz, currentHz);
                        if (similar_qh == null)
                        {
                            continue;
                        }
                        curvePointList = similar_qh.GetFitPoints(100).ToList();
                        newFileName = $"{flagItem.Key}_{currentHz}_update_curve_similar_{Hz}.csv";
                    }
                }
                recordList.Add(record);
            }
            var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csv");
            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
            }
            {
                var r_list = recordList.Select(x => new PointViewModel(x.Time, Math.Round(x.Pressure2, 1), x.FlowDiff2, 0, 2)).ToList();
                var group = r_list.GroupBy(x => x.X);
                string filePath = Path.Combine(fullPath, "atest.csv");
                using StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
                string filePathLow = Path.Combine(fullPath, "alow.csv");
                using StreamWriter writerLow = new StreamWriter(filePathLow, false, System.Text.Encoding.UTF8);
                writer.WriteLine($"Pressure2,FlowDiffUpper,FlowDiffAverage,FlowDiffLower");
                writerLow.WriteLine($"Pressure2,FlowDiffLower");
                foreach (var item in group)
                {
                    var fList = DynamicThresholdProcessorHelper.Filter(item.ToList());
                    var x = item.Key;
                    var yUpper = item.Max(x => x.Y);
                    var yLower = item.Min(x => x.Y);
                    var yAverage = item.Average(x => x.Y);
                    if (fList != null && fList.Any())
                    if (!curvePointList.Any())
                    {
                        yUpper = fList.Max(x => x.Y);
                        yLower = fList.Min(x => x.Y);
                        yAverage = fList.Average(x => x.Y);
                        continue;
                    }
                    writer.WriteLine($"{x},{yUpper},{yAverage},{yLower}");
                    writerLow.WriteLine($"{x},{yLower}");
                }
            }
            {
                string filePath = Path.Combine(fullPath, "all.csv");
                using StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
                writer.WriteLine($"Time,Flow1,Pressure1,Flow2,Pressure2,FlowDiff2");
                foreach (var record in recordList)
                {
                    writer.WriteLine($"{record.Time},{record.Flow1},{record.Pressure1},{record.Flow2},{record.Pressure2},{record.FlowDiff2}");
                }
            }
            return;
            var dataCellList = new List<DataCellViewModel>() {
                new() { Name = "Flow1", ValueList = recordList.Select(x => x.Flow1).ToArray() },
                new() { Name = "Pressure1", ValueList = recordList.Select(x => x.Pressure1).ToArray() },
                new() { Name = "Flow2", ValueList = recordList.Select(x => x.Flow2).ToArray() },
                new() { Name = "Pressure2", ValueList = recordList.Select(x => x.Pressure2).ToArray() },
                new() { Name = "FlowDiff2", ValueList = recordList.Select(x => x.FlowDiff2).ToArray() } };
            var combineList = IStation.Curve.PermutationAndCombination<DataCellViewModel>.GetCombination(dataCellList.ToArray(), 2);
            Console.WriteLine("输出文件");
            foreach (var combine in combineList)
            {
                var x = combine[0];
                var y = combine[1];
                string filePath = Path.Combine(fullPath, $"{x.Name}-{y.Name}.csv");
                using StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
                var count = x.ValueList.Length;
                writer.WriteLine($"{x.Name},{y.Name}");
                for (int i = 0; i < count; i++)
                {
                    var xv = x.ValueList[i];
                    var yv = y.ValueList[i];
                    writer.WriteLine($"{xv},{yv}");
                    var currentCurveFile = Path.Combine(fullPath, newFileName);
                    CsvHelper.ExportToCsv(curvePointList, currentCurveFile);
                    Console.WriteLine(newFileName);
                }
            }
            Console.WriteLine("计算皮尔逊积差相关系数");
            foreach (var combine in combineList)
            {
                var x = combine[0];
                var y = combine[1];
                var (r, pValue) = PearsonTest(x.ValueList, y.ValueList);
                Console.WriteLine($"{x.Name}-{y.Name}: r = {r:F3}");
            }
            Console.WriteLine("计算斯皮尔曼等级相关系数");
            foreach (var combine in combineList)
            {
                var x = combine[0];
                var y = combine[1];
                var (rho, pValue) = SpearmanTest(x.ValueList, y.ValueList);
                Console.WriteLine($"{x.Name}-{y.Name}: ρ = {rho:F3}");
            }
            foreach (var combine in combineList)
            {
                var x = combine[0];
                var y = combine[1];
                string filePath = Path.Combine(fullPath, $"{x.Name}-{y.Name}.csv");
                using StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
                var count = x.ValueList.Length;
                writer.WriteLine($"{x.Name},{y.Name}");
                for (int i = 0; i < count; i++)
                {
                    var xv = x.ValueList[i];
                    var yv = y.ValueList[i];
                    writer.WriteLine($"{xv},{yv}");
                }
            }
            //foreach (var combine in combineList)
            //{
            //    var x = combine[0];
            //    var y = combine[1];
            //    var name = $"{x.Name}-{y.Name}";
            //    if (name.Equals("Flow2-Pressure2") || name.Equals("Pressure1-Pressure2") || name.Equals("Flow1-Pressure2"))
            //    {
            //        NonlinearRegressionExample2.Test(x, y);
            //    }
            //}
            Console.WriteLine("ok");
            Console.ReadKey();
        }
        /// <summary>
        /// 计算皮尔逊相关系数及显著性p值
        /// </summary>
        public static (double r, double pValue) PearsonTest(double[] x, double[] y)
        {
            // 计算皮尔逊相关系数
            double r = CorrelationHelper.Pearson(x, y);
            // 计算显著性p值(双尾t检验)
            int n = x.Length;
            double t = r * Math.Sqrt((n - 2) / (1 - r * r));
            var tDist = new StudentT(location: 0, scale: 1, freedom: n - 2);
            double pValue = 2 * (1 - tDist.CumulativeDistribution(Math.Abs(t)));
            return (r, pValue);
        }
        /// <summary>
        /// 计算斯皮尔曼等级相关系数及显著性p值
        /// </summary>
        public static (double rho, double pValue) SpearmanTest(double[] x, double[] y)
        {
            // 计算斯皮尔曼相关系数
            double rho = CorrelationHelper.Spearman(x, y);
            // 大样本正态近似法计算p值
            int n = x.Length;
            double z = rho * Math.Sqrt(n - 1);
            var normalDist = new Normal();
            double pValue = 2 * (1 - normalDist.CumulativeDistribution(Math.Abs(z)));
            return (rho, pValue);
        }
    }
    #region ViewModel
    public class DataCellViewModel
    {
        public string Name { get; set; }
        public double[] ValueList { get; set; }
    }
    public class PointViewModel
    {
        public PointViewModel() { }
        public PointViewModel(DateTime dt, double x, double y, double diff, int index)
        {
            this.Time = dt;
            this.X = x;
            this.Y = y;
            this.Diff = diff;
            this.Index = index;
        }
        public PointViewModel(PointViewModel rhs)
        {
            this.Time = rhs.Time;
            this.X = rhs.X;
            this.Y = rhs.Y;
            this.Index = rhs.Index;
            this.Diff = rhs.Diff;
        }
        public DateTime Time { get; set; }
        public int Index { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public double Diff { get; set; }
    }
    public class RecordViewModel
    {
        public RecordViewModel() { }
        public DateTime Time { get; set; }
        public double Flow1 { get; set; }
        public double Pressure1 { get; set; }
        public double Flow2 { get; set; }
        public double Pressure2 { get; set; }
        public double FlowDiff2 { get; set; }
    }
    #endregion
    public class DynamicThresholdProcessorHelper
    {
        public static List<PointViewModel> Filter(List<PointViewModel> ptList)
        {
            var pressures = ptList.Select(p => p.Y).ToList();
            // 计算统计量
            var (mean, stdDev) = CalculateStats(pressures);
            double skewness = CalculateSkewness(pressures);
            // 动态调整σ倍数
            double sigmaMultiplier = CalculateSigmaMultiplier(skewness);
            sigmaMultiplier = 3;//目前默认 标准差
            // 计算边界
            double lower = mean - sigmaMultiplier * stdDev;
            double upper = mean + sigmaMultiplier * stdDev;
            return ptList.Where(p => p.Y >= lower && p.Y <= upper).ToList();
        }
        // 核心统计计算
        private static (double mean, double stdDev) CalculateStats(List<double> values)
        {
            double mean = values.Average();
            double stdDev = Math.Sqrt(values.Sum(v => Math.Pow(v - mean, 2)) / (values.Count - 1));
            return (mean, stdDev);
        }
        // 偏度计算(Pearson's moment coefficient)
        private static double CalculateSkewness(List<double> values)
        {
            double mean = values.Average();
            double std = CalculateStats(values).stdDev;
            double sum = values.Sum(v => Math.Pow((v - mean) / std, 3));
            return (sum * values.Count) / ((values.Count - 1) * (values.Count - 2));
        }
        // 动态σ倍数计算规则
        private static double CalculateSigmaMultiplier(double skewness)
        {
            return skewness switch
            {
                > 1.0 => 2.0,    // 强正偏态
                > 0.5 => 2.5,
                > -0.5 => 3.0,   // 近似正态
                > -1.0 => 3.5,
                _ => 4.0    // 强负偏态
            };
        }
    }
    public static class CorrelationHelper
    {
        /// <summary>
        /// 计算皮尔逊积差相关系数
        /// </summary>
        /// <param name="dataA">数据样本A</param>
        /// <param name="dataB">数据样本B</param>
        /// <returns>皮尔逊积差相关系数</returns>
        public static double Pearson(IEnumerable<double> dataA, IEnumerable<double> dataB)
        {
            int n = 0;
            double r = 0.0;
            double meanA = 0;
            double meanB = 0;
            double varA = 0;
            double varB = 0;
            using (var ieA = dataA.GetEnumerator())
            using (var ieB = dataB.GetEnumerator())
            {
                while (ieA.MoveNext())
                {
                    if (!ieB.MoveNext())
                    {
                        throw new ArgumentOutOfRangeException("dataB", "数据长度不一致");
                    }
                    double currentA = ieA.Current;
                    double currentB = ieB.Current;
                    double deltaA = currentA - meanA;
                    double scaleDeltaA = deltaA / ++n;
                    double deltaB = currentB - meanB;
                    double scaleDeltaB = deltaB / n;
                    meanA += scaleDeltaA;
                    meanB += scaleDeltaB;
                    varA += scaleDeltaA * deltaA * (n - 1);
                    varB += scaleDeltaB * deltaB * (n - 1);
                    r += (deltaA * deltaB * (n - 1)) / n;
                }
                if (ieB.MoveNext())
                {
                    throw new ArgumentOutOfRangeException("dataA", "数据长度不一致");
                }
            }
            return r / Math.Sqrt(varA * varB);
        }
        /// <summary>
        /// 计算斯皮尔曼等级相关系数
        /// </summary>
        public static double Spearman(IEnumerable<double> dataA, IEnumerable<double> dataB)
        {
            return Pearson(Rank(dataA), Rank(dataB));
        }
        private static IEnumerable<double> Rank(IEnumerable<double> sequence)
        {
            var sorted = new List<double>(sequence);
            sorted.Sort();
            return (IEnumerable<double>)sequence.Select(x => (double)sorted.IndexOf(x) + 1);
        }
    }
    public class NonlinearRegressionHelper
    {
        //static void Main(string[] args)
        //{
        //    // 示例数据:Flow1 和 Pressure1
        //    double[] flow1 = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
        //    double[] pressure1 = { 2.1, 4.5, 6.8, 9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23.0 };
        //    var splineList = new List<CurvePoint>();
        //    var measuredList = new List<CurvePoint>();
        //    // 多项式回归的阶数(例如,二次多项式)
        //    int degree = 2;
        //    var path = AppDomain.CurrentDomain.BaseDirectory;
        //    var lienPaht = path + @"\pumpcsv\23_44_old_curve.csv";
        //    var measuredPath = path + @"\pumpcsv\23_44.csv";
        //    // 拟合多项式回归模型
        //    double[] coefficients = FitPolynomial(flow1, pressure1, degree);
        //    // 输出回归系数
        //    Console.WriteLine("多项式回归系数:");
        //    for (int i = 0; i <= degree; i++)
        //    using (var fs = new FileStream(lienPaht, FileMode.Open, FileAccess.Read))
        //    using (var sr = new StreamReader(fs, Encoding.UTF8))
        //    {
        //        Console.WriteLine($"系数 {i}: {coefficients[i]}");
        //        var strLine = string.Empty;
        //        sr.ReadLine();
        //        while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
        //        {
        //            var strList = strLine.Split(',');
        //            var x = double.Parse(strList[0]);
        //            var y = double.Parse(strList[1]);
        //            splineList.Add(new CurvePoint(x, y));
        //        }
        //    }
        //    // 使用模型进行预测
        //    double xNew = 11.0;
        //    double yPredicted = PredictPolynomial(xNew, coefficients);
        //    Console.WriteLine($"\n当 Flow1 = {xNew} 时,预测的 Pressure1 = {yPredicted}");
        //    using (var fs = new FileStream(measuredPath, FileMode.Open, FileAccess.Read))
        //    using (var sr = new StreamReader(fs, Encoding.UTF8))
        //    {
        //        var strLine = string.Empty;
        //        sr.ReadLine();
        //        while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
        //        {
        //            var strList = strLine.Split(',');
        //            var x = double.Parse(strList[4]);
        //            var y = double.Parse(strList[5]);
        //            measuredList.Add(new CurvePoint(x, y));
        //        }
        //    }
        //    // 计算 R² 和 MSE
        //    double rSquared = CalculateRSquared(flow1, pressure1, coefficients);
        //    double mse = CalculateMSE(flow1, pressure1, coefficients);
        //    Console.WriteLine($"\nR² = {rSquared}");
        //    Console.WriteLine($"MSE = {mse}");
        //    // 样条曲线处理
        //    double[] splineX = splineList.Select(x => x.X).ToArray();
        //    double[] splineY = splineList.Select(x => x.Y).ToArray();
        //    // 实测数据处理
        //    double[] measuredXAll = measuredList.Select(x => x.X).ToArray();
        //    double[] measuredYAll = measuredList.Select(x => x.Y).ToArray();
        //    var helper = new PumpCurveDataFusionCorrectorHelper();
        //    (double[] mergedX, double[] mergedY, double[] optimizedX, double[] optimizedY) = helper.Corrent(splineX, splineY, measuredXAll, measuredYAll);
        //    var pt_list = new List<CurvePoint>();
        //    for (int i = 0; i < optimizedX.Length; i++)
        //    {
        //        var x = optimizedX[i];
        //        var y = optimizedY[i];
        //        pt_list.Add(new CurvePoint(x, y));
        //    }
        //    var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pumpcsv");
        //    CsvHelper.ExportToCsv(pt_list, Path.Combine(fullPath, $"23_44_update_curve.csv"));
        //    Console.WriteLine("ok");
        //    Console.ReadKey();
        //}
        public static void Test(DataCellViewModel xCell, DataCellViewModel yCell)
        private static Dictionary<int, IStation.Model.CurveExpress> GetFlagCurveDict()
        {
            var x = xCell.ValueList.ToArray();
            var y = yCell.ValueList.ToArray();
            // 多项式回归的阶数(例如,二次多项式)
            int degree = 4;
            // 拟合多项式回归模型
            double[] coefficients = FitPolynomial(x, y, degree);
            // 输出回归系数
            Console.WriteLine("多项式回归系数:");
            for (int i = 0; i <= degree; i++)
            var dict = new Dictionary<int, IStation.Model.CurveExpress>();
            var bll_curve = new IStation.BLL.PumpCurve();
            var station_list = new IStation.BLL.Station().GetAll();
            foreach (var station in station_list)
            {
                Console.WriteLine($"系数 {i}: {coefficients[i]}");
            }
            // 使用模型进行预测
            double xNew = x.Average();
            double yPredicted = PredictPolynomial(xNew, coefficients);
            Console.WriteLine($"\n当 {xCell.Name} = {xNew} 时,预测的 {yCell.Name} = {yPredicted}");
            // 计算 R² 和 MSE
            double rSquared = CalculateRSquared(x, y, coefficients);
            double mse = CalculateMSE(x, y, coefficients);
            Console.WriteLine($"\nR² = {rSquared}");
            Console.WriteLine($"MSE = {mse}");
            Console.WriteLine();
            Console.WriteLine();
        }
        // 多项式回归拟合
        public static double[] FitPolynomial(double[] x, double[] y, int degree)
        {
            // 构建设计矩阵
            Matrix<double> X = DenseMatrix.OfArray(new double[x.Length, degree + 1]);
            for (int i = 0; i < x.Length; i++)
            {
                for (int j = 0; j <= degree; j++)
                var eq_list = new IStation.BLL.Equipment().GetPumpListByBelongTypeAndBelongID(IStation.ObjectType.Station, station.ID);
                if (eq_list == null || !eq_list.Any())
                {
                    X[i, j] = Math.Pow(x[i], j);
                    continue;
                }
                foreach (var eq in eq_list)
                {
                    IStation.Model.CurveExpress qh = null;
                    var curve_info = bll_curve.GetDefaultWorkingByPumpID(eq.ID)?.CurveInfo;
                    if (curve_info != null)
                    {
                        qh = curve_info.CurveQH;
                    }
                    dict.Add(eq.SortCode, qh);
                }
            }
            // 构建目标向量
            Vector<double> Y = DenseVector.OfArray(y);
            // 使用最小二乘法求解
            var qr = X.QR();
            Vector<double> coefficients = qr.Solve(Y);
            return coefficients.ToArray();
        }
        // 使用多项式模型进行预测
        public static double PredictPolynomial(double x, double[] coefficients)
        {
            double prediction = 0.0;
            for (int i = 0; i < coefficients.Length; i++)
            {
                prediction += coefficients[i] * Math.Pow(x, i);
            }
            return prediction;
        }
        // 计算 R²(决定系数)
        public static double CalculateRSquared(double[] x, double[] y, double[] coefficients)
        {
            double yMean = 0.0;
            double ssTotal = 0.0;
            double ssResidual = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                yMean += y[i];
            }
            yMean /= y.Length;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictPolynomial(x[i], coefficients);
                ssTotal += Math.Pow(y[i] - yMean, 2);
                ssResidual += Math.Pow(y[i] - yPredicted, 2);
            }
            return 1.0 - (ssResidual / ssTotal);
        }
        // 计算 MSE(均方误差)
        public static double CalculateMSE(double[] x, double[] y, double[] coefficients)
        {
            double mse = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictPolynomial(x[i], coefficients);
                mse += Math.Pow(y[i] - yPredicted, 2);
            }
            return mse / y.Length;
        }
        //static void Main(string[] args)
        //{
        //    // 示例数据:Flow 和 Pressure
        //    double[] flow = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
        //    double[] pressure = { 2.1, 4.5, 6.8, 9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23.0 };
        //    // 指数回归
        //    double[] exponentialCoefficients = FitExponentialRegression(flow, pressure);
        //    Console.WriteLine("指数回归系数:");
        //    Console.WriteLine($"a = {Math.Exp(exponentialCoefficients[0])}");
        //    Console.WriteLine($"b = {exponentialCoefficients[1]}");
        //    double flowNew = 11.0;
        //    double pressurePredictedExponential = PredictExponential(flowNew, exponentialCoefficients);
        //    Console.WriteLine($"\n当 Flow = {flowNew} 时,指数回归预测的 Pressure = {pressurePredictedExponential}");
        //    // 对数回归
        //    double[] logarithmicCoefficients = FitLogarithmicRegression(flow, pressure);
        //    Console.WriteLine("\n对数回归系数:");
        //    Console.WriteLine($"a = {logarithmicCoefficients[0]}");
        //    Console.WriteLine($"b = {logarithmicCoefficients[1]}");
        //    double pressurePredictedLogarithmic = PredictLogarithmic(flowNew, logarithmicCoefficients);
        //    Console.WriteLine($"\n当 Flow = {flowNew} 时,对数回归预测的 Pressure = {pressurePredictedLogarithmic}");
        //    // 模型评估
        //    double rSquaredExponential = CalculateRSquaredExponential(flow, pressure, exponentialCoefficients);
        //    double mseExponential = CalculateMSEExponential(flow, pressure, exponentialCoefficients);
        //    Console.WriteLine($"\n指数回归模型评估:");
        //    Console.WriteLine($"R² = {rSquaredExponential}");
        //    Console.WriteLine($"MSE = {mseExponential}");
        //    double rSquaredLogarithmic = CalculateRSquaredLogarithmic(flow, pressure, logarithmicCoefficients);
        //    double mseLogarithmic = CalculateMSELogarithmic(flow, pressure, logarithmicCoefficients);
        //    Console.WriteLine($"\n对数回归模型评估:");
        //    Console.WriteLine($"R² = {rSquaredLogarithmic}");
        //    Console.WriteLine($"MSE = {mseLogarithmic}");
        //}
        //public static void Test(DataCellViewModel xCell, DataCellViewModel yCell)
        //{
        //    // 示例数据:Flow 和 Pressure
        //    double[] x = xCell.ValueList.ToArray();
        //    double[] y = yCell.ValueList.ToArray();
        //    // 指数回归
        //    double[] exponentialCoefficients = FitExponentialRegression(x, y);
        //    Console.WriteLine("指数回归系数:");
        //    Console.WriteLine($"a = {Math.Exp(exponentialCoefficients[0])}");
        //    Console.WriteLine($"b = {exponentialCoefficients[1]}");
        //    double flowNew = x.Average();
        //    double pressurePredictedExponential = PredictExponential(flowNew, exponentialCoefficients);
        //    Console.WriteLine($"\n当 {xCell.Name} = {flowNew} 时,指数回归预测的 {yCell.Name} = {pressurePredictedExponential}");
        //    // 对数回归
        //    double[] logarithmicCoefficients = FitLogarithmicRegression(x, y);
        //    Console.WriteLine("\n对数回归系数:");
        //    Console.WriteLine($"a = {logarithmicCoefficients[0]}");
        //    Console.WriteLine($"b = {logarithmicCoefficients[1]}");
        //    double pressurePredictedLogarithmic = PredictLogarithmic(flowNew, logarithmicCoefficients);
        //    Console.WriteLine($"\n当 {xCell.Name} = {flowNew} 时,对数回归预测的 {yCell.Name} = {pressurePredictedLogarithmic}");
        //    // 模型评估
        //    double rSquaredExponential = CalculateRSquaredExponential(x, y, exponentialCoefficients);
        //    double mseExponential = CalculateMSEExponential(x, y, exponentialCoefficients);
        //    Console.WriteLine($"\n指数回归模型评估:");
        //    Console.WriteLine($"R² = {rSquaredExponential}");
        //    Console.WriteLine($"MSE = {mseExponential}");
        //    double rSquaredLogarithmic = CalculateRSquaredLogarithmic(x, y, logarithmicCoefficients);
        //    double mseLogarithmic = CalculateMSELogarithmic(x, y, logarithmicCoefficients);
        //    Console.WriteLine($"\n对数回归模型评估:");
        //    Console.WriteLine($"R² = {rSquaredLogarithmic}");
        //    Console.WriteLine($"MSE = {mseLogarithmic}");
        //}
        // 指数回归拟合
        public static double[] FitExponentialRegression(double[] x, double[] y)
        {
            // 将 y 转换为自然对数
            double[] logY = new double[y.Length];
            for (int i = 0; i < y.Length; i++)
            {
                logY[i] = Math.Log(y[i]);
            }
            // 构建设计矩阵
            Matrix<double> X = DenseMatrix.OfArray(new double[x.Length, 2]);
            for (int i = 0; i < x.Length; i++)
            {
                X[i, 0] = 1.0;  // 常数项
                X[i, 1] = x[i];
            }
            // 构建目标向量
            Vector<double> Y = DenseVector.OfArray(logY);
            // 使用最小二乘法求解
            var qr = X.QR();
            Vector<double> coefficients = qr.Solve(Y);
            return coefficients.ToArray();
        }
        // 指数回归预测
        public static double PredictExponential(double x, double[] coefficients)
        {
            double a = Math.Exp(coefficients[0]);
            double b = coefficients[1];
            return a * Math.Exp(b * x);
        }
        // 对数回归拟合
        public static double[] FitLogarithmicRegression(double[] x, double[] y)
        {
            // 将 x 转换为自然对数
            double[] logX = new double[x.Length];
            for (int i = 0; i < x.Length; i++)
            {
                logX[i] = Math.Log(x[i]);
            }
            // 构建设计矩阵
            Matrix<double> X = DenseMatrix.OfArray(new double[x.Length, 2]);
            for (int i = 0; i < x.Length; i++)
            {
                X[i, 0] = 1.0;  // 常数项
                X[i, 1] = logX[i];
            }
            // 构建目标向量
            Vector<double> Y = DenseVector.OfArray(y);
            // 使用最小二乘法求解
            var qr = X.QR();
            Vector<double> coefficients = qr.Solve(Y);
            return coefficients.ToArray();
        }
        // 对数回归预测
        public static double PredictLogarithmic(double x, double[] coefficients)
        {
            double a = coefficients[0];
            double b = coefficients[1];
            return a + b * Math.Log(x);
        }
        // 计算指数回归的 R²
        public static double CalculateRSquaredExponential(double[] x, double[] y, double[] coefficients)
        {
            double yMean = 0.0;
            double ssTotal = 0.0;
            double ssResidual = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                yMean += y[i];
            }
            yMean /= y.Length;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictExponential(x[i], coefficients);
                ssTotal += Math.Pow(y[i] - yMean, 2);
                ssResidual += Math.Pow(y[i] - yPredicted, 2);
            }
            return 1.0 - (ssResidual / ssTotal);
        }
        // 计算指数回归的 MSE
        public static double CalculateMSEExponential(double[] x, double[] y, double[] coefficients)
        {
            double mse = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictExponential(x[i], coefficients);
                mse += Math.Pow(y[i] - yPredicted, 2);
            }
            return mse / y.Length;
        }
        // 计算对数回归的 R²
        public static double CalculateRSquaredLogarithmic(double[] x, double[] y, double[] coefficients)
        {
            double yMean = 0.0;
            double ssTotal = 0.0;
            double ssResidual = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                yMean += y[i];
            }
            yMean /= y.Length;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictLogarithmic(x[i], coefficients);
                ssTotal += Math.Pow(y[i] - yMean, 2);
                ssResidual += Math.Pow(y[i] - yPredicted, 2);
            }
            return 1.0 - (ssResidual / ssTotal);
        }
        // 计算对数回归的 MSE
        public static double CalculateMSELogarithmic(double[] x, double[] y, double[] coefficients)
        {
            double mse = 0.0;
            for (int i = 0; i < y.Length; i++)
            {
                double yPredicted = PredictLogarithmic(x[i], coefficients);
                mse += Math.Pow(y[i] - yPredicted, 2);
            }
            return mse / y.Length;
            return dict;
        }
    }
}