From 09b182978951870e694b8f35196ee58e7fcc12f8 Mon Sep 17 00:00:00 2001 From: xyy <544939200@qq.com> Date: Mon, 13 Apr 2026 22:45:22 +0800 Subject: [PATCH] --- Helpers/PoreDistributionAnalysis.cs | 126 ++++++++++++++++++++---- ViewModels/BubblePointViewModel.cs | 2 +- ViewModels/PoreDistributionViewModel.cs | 4 +- Views/PoreDistributionView.xaml | 2 +- 4 files changed, 113 insertions(+), 21 deletions(-) diff --git a/Helpers/PoreDistributionAnalysis.cs b/Helpers/PoreDistributionAnalysis.cs index 26d0b4f..923ad93 100644 --- a/Helpers/PoreDistributionAnalysis.cs +++ b/Helpers/PoreDistributionAnalysis.cs @@ -1,42 +1,134 @@ using MembranePoreTester.Models; +using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace MembranePoreTester.Helpers { public static class PoreDistributionAnalysis { + //public static double CalculateAveragePore( + // IEnumerable points, + // string unit, + // TestLiquid liquid) + //{ + // var sorted = points.OrderBy(p => p.Pressure).ToList(); + // if (sorted.Count < 2) return 0; + + // double[] pressures = sorted.Select(p => p.Pressure).ToArray(); + // double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray(); + // double[] wetFlows = sorted.Select(p => p.WetFlow).ToArray(); + + // double halfDryFlow = dryFlows.Max() / 2.0; + + // // 找到湿膜流量等于 halfDryFlow 的压力(交点) + // for (int i = 0; i < wetFlows.Length - 1; i++) + // { + // if ((wetFlows[i] <= halfDryFlow && wetFlows[i + 1] >= halfDryFlow) || + // (wetFlows[i] >= halfDryFlow && wetFlows[i + 1] <= halfDryFlow)) + // { + // double p = Interpolation.Linear( + // new[] { wetFlows[i], wetFlows[i + 1] }, + // new[] { pressures[i], pressures[i + 1] }, + // halfDryFlow); + // return PoreCalculator.PressureToPore(p, unit, liquid); + // } + // } + // return 0; + //} + public static double CalculateAveragePore( - IEnumerable points, - string unit, - TestLiquid liquid) + IEnumerable points, + string unit, + TestLiquid liquid) { var sorted = points.OrderBy(p => p.Pressure).ToList(); if (sorted.Count < 2) return 0; double[] pressures = sorted.Select(p => p.Pressure).ToArray(); - double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray(); double[] wetFlows = sorted.Select(p => p.WetFlow).ToArray(); + double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray(); - double halfDryFlow = dryFlows.Max() / 2.0; - - // 找到湿膜流量等于 halfDryFlow 的压力(交点) - for (int i = 0; i < wetFlows.Length - 1; i++) + // 寻找湿膜流量曲线与干膜流量曲线的所有交点(直接相交),记录交点压力及对应的插值干膜流量 + var intersections = new List<(double Pressure, double DryFlowAtP)>(); + const double eps = 1e-12; + for (int i = 0; i < pressures.Length - 1; i++) { - if ((wetFlows[i] <= halfDryFlow && wetFlows[i + 1] >= halfDryFlow) || - (wetFlows[i] >= halfDryFlow && wetFlows[i + 1] <= halfDryFlow)) + double diff1 = wetFlows[i] - dryFlows[i]; + double diff2 = wetFlows[i + 1] - dryFlows[i + 1]; + // 检查差值是否异号或为零(表示相交) + if (diff1 * diff2 <= 0 && diff1 != diff2) { - double p = Interpolation.Linear( - new[] { wetFlows[i], wetFlows[i + 1] }, - new[] { pressures[i], pressures[i + 1] }, - halfDryFlow); - return PoreCalculator.PressureToPore(p, unit, liquid); + double p; + if (Math.Abs(diff1) < eps) + { + p = pressures[i]; + } + else if (Math.Abs(diff2) < eps) + { + p = pressures[i + 1]; + } + else + { + double p0 = pressures[i]; + double p1 = pressures[i + 1]; + if (Math.Abs(diff2 - diff1) < eps) + continue; + p = p0 + (p1 - p0) * (0 - diff1) / (diff2 - diff1); + } + + if (p <= 0) continue; + + // 线性插值计算交点处的干膜流量 + double dryAtP; + { + double d0 = dryFlows[i]; + double d1 = dryFlows[i + 1]; + double p0 = pressures[i]; + double p1 = pressures[i + 1]; + if (Math.Abs(p1 - p0) < eps) + dryAtP = d0; + else + dryAtP = d0 + (d1 - d0) * (p - p0) / (p1 - p0); + } + + intersections.Add((p, dryAtP)); } } - return 0; + + if (intersections.Count == 0) + return 0; + + // 如果存在多个交点,默认选择压力最小(靠近低压区的第一个交点) + var chosen = intersections.OrderBy(x => x.Pressure).First(); + + // 将调试信息写入日志文件,便于在非 VS 环境下查看计算过程 + try + { + Log($"PoreDistributionAnalysis: unit={unit}, liquid.C_Pa={liquid?.C_Pa}"); + foreach (var it in intersections) + Log($"intersection: P={it.Pressure}, dryAtP={it.DryFlowAtP}"); + Log($"chosen intersection: P={chosen.Pressure}"); + double pore = PoreCalculator.PressureToPore(chosen.Pressure, unit, liquid); + Log($"calculated pore={pore}"); + return pore; + } + catch + { + try { return PoreCalculator.PressureToPore(chosen.Pressure, unit, liquid); } catch { return 0; } + } } - + private static void Log(string message) + { + try + { + string path = Path.Combine(Directory.GetCurrentDirectory(), "PoreDistributionAnalysis.log"); + File.AppendAllText(path, DateTime.Now.ToString("o") + " " + message + Environment.NewLine); + } + catch { } + } public static double CalculatePoreRangePercentage( diff --git a/ViewModels/BubblePointViewModel.cs b/ViewModels/BubblePointViewModel.cs index 920ce22..dfee5ef 100644 --- a/ViewModels/BubblePointViewModel.cs +++ b/ViewModels/BubblePointViewModel.cs @@ -44,7 +44,7 @@ namespace MembranePoreTester.ViewModels public IReadOnlyList Liquids => TestLiquid.Predefined; public List PressureUnits => new() { "Pa", "cmHg", "psi" }; - public List MembraneTypes => new() { "平板膜", "中空纤维膜" }; + public List MembraneTypes => new() { "中空纤维膜" }; public TestLiquid SelectedLiquid { diff --git a/ViewModels/PoreDistributionViewModel.cs b/ViewModels/PoreDistributionViewModel.cs index da29ddd..cb60f03 100644 --- a/ViewModels/PoreDistributionViewModel.cs +++ b/ViewModels/PoreDistributionViewModel.cs @@ -260,7 +260,7 @@ namespace MembranePoreTester.ViewModels public IReadOnlyList Liquids => TestLiquid.Predefined; public List PressureUnits => new() { "Pa", "cmHg", "psi" }; - public List MembraneTypes => new() { "平板膜", "中空纤维膜" }; + public List MembraneTypes => new() { "中空纤维膜" }; public TestLiquid SelectedLiquid { @@ -1208,7 +1208,7 @@ namespace MembranePoreTester.ViewModels model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, - Title = "压力 (kPa)", + Title = "压力 (Pa)", TitleFontSize = 12 }); model.Axes.Add(new LinearAxis diff --git a/Views/PoreDistributionView.xaml b/Views/PoreDistributionView.xaml index 16d6c69..124577b 100644 --- a/Views/PoreDistributionView.xaml +++ b/Views/PoreDistributionView.xaml @@ -293,7 +293,7 @@