This commit is contained in:
@@ -36,34 +36,71 @@ namespace MembranePoreTester.Helpers
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static double CalculatePoreRangePercentage(
|
||||
IEnumerable<DataPoint> points,
|
||||
string unit,
|
||||
TestLiquid liquid,
|
||||
double lowerPore,
|
||||
double upperPore)
|
||||
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;
|
||||
|
||||
double[] pressures = sorted.Select(p => p.Pressure).ToArray();
|
||||
double[] wetFlows = sorted.Select(p => p.WetFlow).ToArray();
|
||||
double[] dryFlows = sorted.Select(p => p.DryFlow).ToArray();
|
||||
// 提取有效点(流量 > 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);
|
||||
|
||||
// 插值
|
||||
double qWetLower = Interpolation.Linear(pressures, wetFlows, pLower);
|
||||
double qDryLower = Interpolation.Linear(pressures, dryFlows, pLower);
|
||||
double qWetUpper = Interpolation.Linear(pressures, wetFlows, pUpper);
|
||||
double qDryUpper = Interpolation.Linear(pressures, dryFlows, pUpper);
|
||||
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;
|
||||
}
|
||||
|
||||
return (ratioHigh - ratioLow) * 100;
|
||||
// 辅助插值函数:基于有效点列表(已按压力升序)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,22 @@ namespace MembranePoreTester.ViewModels
|
||||
float rawPressure = await _plcService.ReadPressureAsync(StationId);
|
||||
double pressure = Math.Round(rawPressure * _plcConfig.PressureFactor, 2);
|
||||
|
||||
|
||||
|
||||
|
||||
// 2. 读取当前工位的加压上限(实时)
|
||||
ushort upperLimitAddress = StationId == 1 ? _plcConfig.PressureUpperLimit
|
||||
: StationId == 2 ? _plcConfig.PressureUpperLimit2
|
||||
: _plcConfig.PressureUpperLimit3;
|
||||
double pressureUpperLimit = await _plcService.ReadFloatAsync(upperLimitAddress);
|
||||
|
||||
// 3. 如果压力已达到或超过上限,停止采集
|
||||
if (pressure >= pressureUpperLimit - 3)
|
||||
{
|
||||
StopCollecting();
|
||||
return; // 不再添加当前数据点
|
||||
}
|
||||
|
||||
// 2. 读取当前模式对应的流量
|
||||
double flow = 0;
|
||||
if (TestMode.Contains("湿膜"))
|
||||
@@ -550,11 +566,18 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
|
||||
|
||||
// 修改 Calculate 方法:
|
||||
//修改 Calculate 方法:
|
||||
private void Calculate()
|
||||
{
|
||||
// 先清洗数据并替换到绑定的集合中,确保DataGrid和曲线显示清洗后的数据
|
||||
var originalPoints = Record.DataPoints.ToList();
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("=== 清洗前的数据点 ===");
|
||||
foreach (var p in originalPoints)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"P={p.Pressure}, Wet={p.WetFlow}, Dry={p.DryFlow}");
|
||||
}
|
||||
|
||||
var cleanedPoints = CleanDataPoints(originalPoints);
|
||||
|
||||
if (cleanedPoints.Count < 2)
|
||||
@@ -587,22 +610,105 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
//private void Calculate()
|
||||
//{
|
||||
// // 直接使用原始数据,不清洗
|
||||
// if (Record.DataPoints.Count < 2)
|
||||
// {
|
||||
// MessageBox.Show("有效数据点不足,至少需要 2 个数据点进行计算。");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // 注意:不清洗,也不改变 Record.DataPoints 的顺序(但计算函数内部会自己排序)
|
||||
// // 直接计算
|
||||
// AveragePoreSize = PoreDistributionAnalysis.CalculateAveragePore(
|
||||
// Record.DataPoints, Record.PressureUnit, Record.Liquid);
|
||||
|
||||
// RangePercentage = PoreDistributionAnalysis.CalculatePoreRangePercentage(
|
||||
// Record.DataPoints, Record.PressureUnit, Record.Liquid, LowerPore, UpperPore);
|
||||
|
||||
// // 可选:提示用户当前使用了原始数据(不清洗)
|
||||
// // MessageBox.Show("已使用原始数据(未清洗)进行计算");
|
||||
//}
|
||||
|
||||
//private List<Models.DataPoint> CleanDataPoints(IEnumerable<Models.DataPoint> points)
|
||||
//{
|
||||
// return points
|
||||
// .Where(p => p.Pressure > 0.001) // 移除压力接近0的点
|
||||
// .Where(p => !(Math.Abs(p.WetFlow) < 0.001 && Math.Abs(p.DryFlow) < 0.001)) // 移除双零流量点
|
||||
// .GroupBy(p => Math.Round(p.Pressure, 2)) // 按压力四舍五入分组(避免重复压力)
|
||||
// .Select(g => new Models.DataPoint
|
||||
// {
|
||||
// Pressure = g.Key,
|
||||
// WetFlow = g.Max(x => x.WetFlow), // 取最大值(避免0覆盖有效值)
|
||||
// DryFlow = g.Max(x => x.DryFlow)
|
||||
// })
|
||||
// .OrderBy(p => p.Pressure)
|
||||
// .ToList();
|
||||
//}
|
||||
|
||||
|
||||
|
||||
private List<Models.DataPoint> CleanDataPoints(IEnumerable<Models.DataPoint> points)
|
||||
{
|
||||
return points
|
||||
.Where(p => p.Pressure > 0.001) // 移除压力接近0的点
|
||||
.Where(p => !(Math.Abs(p.WetFlow) < 0.001 && Math.Abs(p.DryFlow) < 0.001)) // 移除双零流量点
|
||||
.GroupBy(p => Math.Round(p.Pressure, 2)) // 按压力四舍五入分组(避免重复压力)
|
||||
// 第一步:基础清洗(移除压力≤0、双零流量、合并相同压力取最大流量)
|
||||
var cleaned = points
|
||||
.Where(p => p.Pressure > 0.001)
|
||||
.Where(p => !(Math.Abs(p.WetFlow) < 0.001 && Math.Abs(p.DryFlow) < 0.001))
|
||||
.GroupBy(p => Math.Round(p.Pressure, 2))
|
||||
.Select(g => new Models.DataPoint
|
||||
{
|
||||
Pressure = g.Key,
|
||||
WetFlow = g.Max(x => x.WetFlow), // 取最大值(避免0覆盖有效值)
|
||||
WetFlow = g.Max(x => x.WetFlow),
|
||||
DryFlow = g.Max(x => x.DryFlow)
|
||||
})
|
||||
.OrderBy(p => p.Pressure)
|
||||
.ToList();
|
||||
|
||||
if (cleaned.Count < 4) return cleaned; // 点数太少,不进行高级剔除
|
||||
|
||||
// 第二步:仅对湿膜流量进行异常孤立点剔除(干膜保持原样,因为干膜可能有很多0和少量非零)
|
||||
var result = new List<Models.DataPoint>();
|
||||
const double threshold = 3.0; // 孤立高点阈值(倍),比之前放宽
|
||||
|
||||
for (int i = 0; i < cleaned.Count; i++)
|
||||
{
|
||||
var current = cleaned[i];
|
||||
bool isAbnormal = false;
|
||||
|
||||
// 仅检查中间的点(非首尾),且只检查湿膜流量
|
||||
if (i > 0 && i < cleaned.Count - 1)
|
||||
{
|
||||
double prevWet = cleaned[i - 1].WetFlow;
|
||||
double nextWet = cleaned[i + 1].WetFlow;
|
||||
double maxNeighbor = Math.Max(prevWet, nextWet);
|
||||
double minNeighbor = Math.Min(prevWet, nextWet);
|
||||
|
||||
// 如果当前湿膜流量远大于前后邻居的最大值(孤立高峰),且前后邻居都不为0
|
||||
if (maxNeighbor > 0 && current.WetFlow > maxNeighbor * threshold)
|
||||
isAbnormal = true;
|
||||
|
||||
// 如果当前湿膜流量远小于前后邻居的最小值(孤立低谷),一般很少见,但保留
|
||||
if (minNeighbor > 0 && current.WetFlow < minNeighbor / threshold)
|
||||
isAbnormal = true;
|
||||
}
|
||||
|
||||
// 不剔除干膜中的非零点(即使孤立也不删)
|
||||
if (!isAbnormal)
|
||||
result.Add(current);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 如果全部被误判为异常,则回退到原始清洗结果
|
||||
return result.Count == 0 ? cleaned : result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//private void GenerateReport()
|
||||
//{
|
||||
// ReportGenerator.GeneratePoreDistributionReport(Record);
|
||||
|
||||
Reference in New Issue
Block a user