Files
VacuumPressureMembranePoreS…/Helpers/PoreDistributionAnalysis.cs
2026-04-14 23:16:56 +08:00

236 lines
9.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
//{
// var sorted = points.OrderBy(p => p.Pressure).ToList();
// if (sorted.Count < 2) return 0;
// double[] pressures = sorted.Select(p => p.Pressure).ToArray();
// double[] wetFlows = sorted.Select(p => p.WetFlow).ToArray();
// double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray();
// // 日志文件路径(位于程序运行目录)
// string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PoreCalcLog.txt");
// void Log(string msg)
// {
// try
// {
// File.AppendAllText(logPath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} - {msg}{Environment.NewLine}");
// }
// catch { /* 忽略日志写入错误,不影响主流程 */ }
// }
// Log($"开始计算平均孔径,数据点数={sorted.Count},单位={unit},液体={liquid.Name},表面张力={liquid.SurfaceTension}");
// for (int i = 0; i < pressures.Length - 1; i++)
// {
// double diff1 = wetFlows[i] - dryFlows[i];
// double diff2 = wetFlows[i + 1] - dryFlows[i + 1];
// Log($"区间{i}: 压力=[{pressures[i]}, {pressures[i + 1]}], 湿膜=[{wetFlows[i]}, {wetFlows[i + 1]}], 干膜=[{dryFlows[i]}, {dryFlows[i + 1]}], diff1={diff1}, diff2={diff2}");
// // 检查是否异号或其中之一为零
// if (diff1 * diff2 < 0 || Math.Abs(diff1) < 1e-8 || Math.Abs(diff2) < 1e-8)
// {
// double p;
// if (Math.Abs(diff1) < 1e-8)
// {
// p = pressures[i];
// Log($"直接命中点i压力={p}");
// }
// else if (Math.Abs(diff2) < 1e-8)
// {
// p = pressures[i + 1];
// Log($"直接命中点i+1压力={p}");
// }
// else
// {
// double t = -diff1 / (diff2 - diff1); // t 在 0~1 之间
// p = pressures[i] + t * (pressures[i + 1] - pressures[i]);
// Log($"线性插值: t={t}, 交点压力={p}");
// }
// if (p > 0)
// {
// double pore = PoreCalculator.PressureToPore(p, unit, liquid);
// Log($"平均孔径计算结果: 交点压力={p} {unit}, 孔径={pore} μm");
// return pore;
// }
// }
// }
// Log("未找到湿膜与干膜曲线的交点");
// return 0;
//}
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[] wetFlows = sorted.Select(p => p.WetFlow).ToArray();
double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray();
// 日志记录
string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PoreCalcLog.txt");
void Log(string msg)
{
try { File.AppendAllText(logPath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} - {msg}{Environment.NewLine}"); }
catch { }
}
Log($"开始计算平均孔径,数据点数={sorted.Count}");
for (int i = 0; i < pressures.Length - 1; i++)
{
// 跳过干膜流量为0的点避免虚假交点
if (dryFlows[i] == 0 || dryFlows[i + 1] == 0)
continue;
double diff1 = wetFlows[i] - dryFlows[i];
double diff2 = wetFlows[i + 1] - dryFlows[i + 1];
Log($"区间{i}: P=[{pressures[i]}, {pressures[i + 1]}], diff1={diff1}, diff2={diff2}");
if (diff1 * diff2 < 0 || Math.Abs(diff1) < 1e-8 || Math.Abs(diff2) < 1e-8)
{
double p;
if (Math.Abs(diff1) < 1e-8)
p = pressures[i];
else if (Math.Abs(diff2) < 1e-8)
p = pressures[i + 1];
else
{
double t = -diff1 / (diff2 - diff1);
p = pressures[i] + t * (pressures[i + 1] - pressures[i]);
}
Log($"找到交点: 压力={p} Pa");
double pore = PoreCalculator.PressureToPore(p, unit, liquid);
Log($"平均孔径={pore} μm");
return pore;
}
}
Log("未找到有效交点");
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(
IEnumerable<DataPoint> points,
string unit,
TestLiquid liquid,
double lowerPore,
double upperPore)
{
var sorted = points.OrderBy(p => p.Pressure).ToList();
if (sorted.Count < 2) return 0;
// 提取有效点(流量 > 0
var wetValid = sorted.Where(p => p.WetFlow > 0).Select(p => (Pressure: p.Pressure, Flow: p.WetFlow)).ToList();
var dryValid = sorted.Where(p => p.DryFlow > 0).Select(p => (Pressure: p.Pressure, Flow: p.DryFlow)).ToList();
if (wetValid.Count < 2 || dryValid.Count < 2) return 0;
// 有效压力重叠区间
double minPressure = Math.Max(wetValid.First().Pressure, dryValid.First().Pressure);
double maxPressure = Math.Min(wetValid.Last().Pressure, dryValid.Last().Pressure);
if (minPressure >= maxPressure) return 0;
// 孔径转压力
double pLower = PoreCalculator.PoreToPressure(upperPore, unit, liquid);
double pUpper = PoreCalculator.PoreToPressure(lowerPore, unit, liquid);
pLower = Math.Max(pLower, minPressure);
pUpper = Math.Min(pUpper, maxPressure);
if (pUpper <= pLower) return 0;
// 在有效点集上插值
double qWetLower = InterpolateOnValid(wetValid, pLower);
double qDryLower = InterpolateOnValid(dryValid, pLower);
double qWetUpper = InterpolateOnValid(wetValid, pUpper);
double qDryUpper = InterpolateOnValid(dryValid, pUpper);
if (qDryLower <= 0 || qDryUpper <= 0) return 0;
double ratioLow = qWetLower / qDryLower;
double ratioHigh = qWetUpper / qDryUpper;
double result = (ratioHigh - ratioLow) * 100;
return result < 0 ? 0 : result;
}
// 辅助插值函数:基于有效点列表(已按压力升序)
private static double InterpolateOnValid(List<(double Pressure, double Flow)> validPoints, double pressure)
{
if (validPoints.Count == 0) return 0;
if (pressure <= validPoints[0].Pressure) return validPoints[0].Flow;
if (pressure >= validPoints[^1].Pressure) return validPoints[^1].Flow;
for (int i = 0; i < validPoints.Count - 1; i++)
{
if (pressure >= validPoints[i].Pressure && pressure <= validPoints[i + 1].Pressure)
{
double p1 = validPoints[i].Pressure;
double f1 = validPoints[i].Flow;
double p2 = validPoints[i + 1].Pressure;
double f2 = validPoints[i + 1].Flow;
return f1 + (f2 - f1) * (pressure - p1) / (p2 - p1);
}
}
return 0;
}
}
}