This commit is contained in:
xyy
2026-04-13 22:45:22 +08:00
parent abd2103c85
commit 09b1829789
4 changed files with 113 additions and 21 deletions

View File

@@ -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<DataPoint> 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<DataPoint> points,
string unit,
TestLiquid liquid)
IEnumerable<DataPoint> 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(

View File

@@ -44,7 +44,7 @@ namespace MembranePoreTester.ViewModels
public IReadOnlyList<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
public List<string> MembraneTypes => new() { "中空纤维膜" };
public TestLiquid SelectedLiquid
{

View File

@@ -260,7 +260,7 @@ namespace MembranePoreTester.ViewModels
public IReadOnlyList<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
public List<string> 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

View File

@@ -293,7 +293,7 @@
<TextBox Text="{Binding UpperPore}" Width="48" Margin="1"/>
<TextBlock Text="μm" VerticalAlignment="Center" Margin="2,0,5,0"/>
<Button Content="计算" Command="{Binding CalculateCommand}" Margin="2,0" Padding="8,5" Background="#2196F3" Click="Button_Click"/>
<TextBlock Text="{Binding RangePercentage, StringFormat={}{0:F3}%}" FontSize="14" FontWeight="Bold" VerticalAlignment="Center" Margin="5,0" Foreground="#4CAF50"/>
<TextBlock Text="{Binding RangePercentage, StringFormat={}{0:F2}%}" FontSize="14" FontWeight="Bold" VerticalAlignment="Center" Margin="5,0" Foreground="#4CAF50"/>
</StackPanel>
</GroupBox>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="3,0"/>