From 0a908d85dff7808924ae7de30e433f47fef442e5 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Sat, 30 May 2026 15:04:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B02026?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FootwearTest/Models/TestRecords.cs | 16 ++- FootwearTest/Services/ExcelReportService.cs | 137 ++++++++++++++------ FootwearTest/Services/TestFormulaService.cs | 123 +++++++++++++----- FootwearTest/ViewModels/MethodAViewModel.cs | 28 ++-- FootwearTest/ViewModels/MethodBViewModel.cs | 90 ++++++++++--- FootwearTest/Views/MethodBView.axaml | 57 +++++++- 6 files changed, 341 insertions(+), 110 deletions(-) diff --git a/FootwearTest/Models/TestRecords.cs b/FootwearTest/Models/TestRecords.cs index e2fb43a..6d91cc3 100644 --- a/FootwearTest/Models/TestRecords.cs +++ b/FootwearTest/Models/TestRecords.cs @@ -42,7 +42,7 @@ public sealed record MethodAResult( double ThermalCoefficientOfVariation, bool PassedDeviationCheck); -public sealed record MethodBMoistureResult( +public sealed record MethodBMoistureTrialResult( double M1, double M2, double M3, @@ -61,10 +61,22 @@ public sealed record MethodBMoistureResult( double XT180Corrected, bool IsValid); -public sealed record MethodBWarmthResult( +public sealed record MethodBMoistureResult( + MethodBMoistureTrialResult Trial1, + MethodBMoistureTrialResult Trial2, + double AverageT180Corrected, + double AverageXT180Corrected, + bool IsValid); + +public sealed record MethodBWarmthCycleResult( double EnergyKilojoules, double Seconds, double HeatWatts, double FootTemperatureC, double ChamberTemperatureC, double ThermalResistance); + +public sealed record MethodBWarmthResult( + MethodBWarmthCycleResult Cycle1, + MethodBWarmthCycleResult Cycle2, + double AverageThermalResistance); diff --git a/FootwearTest/Services/ExcelReportService.cs b/FootwearTest/Services/ExcelReportService.cs index 0673846..623a1b1 100644 --- a/FootwearTest/Services/ExcelReportService.cs +++ b/FootwearTest/Services/ExcelReportService.cs @@ -63,7 +63,11 @@ public sealed class ExcelReportService else if (record.Method.StartsWith("方法 B", StringComparison.Ordinal)) { sheets.Add(CreateMethodBResultSheet(root, record.Method)); - sheets.Add(CreateMethodBMassSheet(root)); + if (record.Method.Contains("吸湿透水汽", StringComparison.Ordinal)) + { + sheets.Add(CreateMethodBMassSheet(root)); + } + sheets.Add(CreateProcedureSheet(root)); } @@ -111,12 +115,12 @@ public sealed class ExcelReportService rows.Add(Row("方法 B 试样", "满帮鞋同号两只;试验前在 (23±2) ℃、(50±5)% RH 标准环境调节", record.SampleDescription)); rows.Add(Row("方法 B 供水", "泵流量 (5.0±0.3) cm3/h;测试周期 (180±1) min", record.Conditions)); rows.Add(Row("方法 B 称重", "m11-m72 均精确到 0.01 g;m180 应在 (15±0.9) g 范围内", record.IsValid ? "m180 有效" : "m180 超限")); - rows.Add(Row("方法 B 结果", "透水汽性能 T180*;吸湿透水汽性能 XT180*=T180*+m3*+m4*,保留两位小数", record.ResultSummary)); + rows.Add(Row("方法 B 结果", "两次试验结果取平均;透水汽性能 T180*、吸湿透水汽性能 XT180*=T180*+m3*+m4*,最终保留两位小数", record.ResultSummary)); } else { rows.Add(Row("方法 B 保暖", "假脚温度 (38±1) ℃;测试周期 (180±1) min,连续测试 2 个周期", record.Conditions)); - rows.Add(Row("方法 B 热阻", "Q=P/t×1000;R=S×(Tf-Tc)/Q,结果保留三位小数", record.ResultSummary)); + rows.Add(Row("方法 B 热阻", "每个周期 Q=P/t×1000、R=S×(Tf-Tc)/Q;最终取两次热阻平均值并保留三位小数", record.ResultSummary)); } return new WorksheetData("标准核对", rows); @@ -156,8 +160,8 @@ public sealed class ExcelReportService { var waterLoss = GetDouble(sample, "WaterLossGramsPerHour"); var power = GetDouble(sample, "PowerWatts"); - var moistureHeat = sample.TryGetProperty("MoistureHeatWatts", out _) ? GetDouble(sample, "MoistureHeatWatts") : Math.Round(0.672 * Math.Max(waterLoss, 0.001), 3); - var dryHeat = sample.TryGetProperty("DryHeatWatts", out _) ? GetDouble(sample, "DryHeatWatts") : Math.Round(Math.Max(power - moistureHeat, 0.001), 3); + var moistureHeat = sample.TryGetProperty("MoistureHeatWatts", out _) ? GetDouble(sample, "MoistureHeatWatts") : (waterLoss > 0 ? Round(0.672 * waterLoss, 3) : 0); + var dryHeat = sample.TryGetProperty("DryHeatWatts", out _) ? GetDouble(sample, "DryHeatWatts") : (power > moistureHeat ? Round(power - moistureHeat, 3) : 0); rows.Add(Row( GetDouble(sample, "Index"), GetString(sample, "Timestamp"), @@ -186,37 +190,67 @@ public sealed class ExcelReportService if (method.Contains("吸湿透水汽", StringComparison.Ordinal)) { - rows.Add(Row("m5", GetDouble(result, "M5"), "g,C1 消耗水量")); - rows.Add(Row("m6", GetDouble(result, "M6"), "g,C2 蒸发水量")); - rows.Add(Row("m7", GetDouble(result, "M7"), "g,C3 蒸发水量")); - rows.Add(Row("m8", GetDouble(result, "M8"), "g,C2/C3 平均蒸发量")); - rows.Add(Row("m180", GetDouble(result, "M180"), "g,泵进鞋腔内水总质量,15±0.9 g")); - rows.Add(Row("m1", GetDouble(result, "M1"), "g,模拟皮肤质量变化")); - rows.Add(Row("m2", GetDouble(result, "M2"), "g,标准长筒袜质量变化")); - rows.Add(Row("m3", GetDouble(result, "M3"), "g,样品鞋质量变化")); - rows.Add(Row("m4", GetDouble(result, "M4"), "g,鞋垫质量变化")); - rows.Add(Row("T180", GetDouble(result, "T180"), "g,散发到环境中的水汽质量")); - rows.Add(Row("m1*", GetDouble(result, "M1Corrected"), "g,按 15 g 修正")); - rows.Add(Row("m2*", GetDouble(result, "M2Corrected"), "g,按 15 g 修正")); - rows.Add(Row("m3*", GetDouble(result, "M3Corrected"), "g,按 15 g 修正")); - rows.Add(Row("m4*", GetDouble(result, "M4Corrected"), "g,按 15 g 修正")); - rows.Add(Row("T180*", GetDouble(result, "T180Corrected"), "g,透水汽性能")); - rows.Add(Row("XT180*", GetDouble(result, "XT180Corrected"), "g,吸湿透水汽性能")); - rows.Add(Row("有效性", GetBool(result, "IsValid") ? "有效" : "m180 超出 15±0.9 g", "")); + if (result.TryGetProperty("Trial1", out var trial1) && result.TryGetProperty("Trial2", out var trial2)) + { + rows.Add(Row("T180* 平均值", GetDouble(result, "AverageT180Corrected"), "g,透水汽性能,最终保留两位小数")); + rows.Add(Row("XT180* 平均值", GetDouble(result, "AverageXT180Corrected"), "g,吸湿透水汽性能,最终保留两位小数")); + rows.Add(Row("有效性", GetBool(result, "IsValid") ? "有效" : "至少一次 m180 超出 15±0.9 g", "")); + AddMoistureTrialRows(rows, "第1次", trial1); + AddMoistureTrialRows(rows, "第2次", trial2); + } + else + { + AddMoistureTrialRows(rows, "单次", result); + rows.Add(Row("有效性", GetBool(result, "IsValid") ? "有效" : "m180 超出 15±0.9 g", "")); + } } else { - rows.Add(Row("P", GetDouble(result, "EnergyKilojoules"), "kJ,180 min 能量消耗")); - rows.Add(Row("t", GetDouble(result, "Seconds"), "s,测试周期")); - rows.Add(Row("Q", GetDouble(result, "HeatWatts"), "W,单位时间热量消耗")); - rows.Add(Row("Tf", GetDouble(result, "FootTemperatureC"), "℃,假脚表面温度平均值")); - rows.Add(Row("Tc", GetDouble(result, "ChamberTemperatureC"), "℃,测试箱环境温度平均值")); - rows.Add(Row("R", GetDouble(result, "ThermalResistance"), "m2·℃/W,保暖性能热阻值")); + if (result.TryGetProperty("Cycle1", out var cycle1) && result.TryGetProperty("Cycle2", out var cycle2)) + { + rows.Add(Row("R 平均值", GetDouble(result, "AverageThermalResistance"), "m2·℃/W,最终保留三位小数")); + AddWarmthCycleRows(rows, "第1周期", cycle1); + AddWarmthCycleRows(rows, "第2周期", cycle2); + } + else + { + AddWarmthCycleRows(rows, "单周期", result); + } } return new WorksheetData("方法B结果", rows); } + private static void AddMoistureTrialRows(List> rows, string prefix, JsonElement trial) + { + rows.Add(Row($"{prefix} m5", GetDouble(trial, "M5"), "g,C1 消耗水量")); + rows.Add(Row($"{prefix} m6", GetDouble(trial, "M6"), "g,C2 蒸发水量")); + rows.Add(Row($"{prefix} m7", GetDouble(trial, "M7"), "g,C3 蒸发水量")); + rows.Add(Row($"{prefix} m8", GetDouble(trial, "M8"), "g,C2/C3 平均蒸发量")); + rows.Add(Row($"{prefix} m180", GetDouble(trial, "M180"), "g,泵进鞋腔内水总质量,15±0.9 g")); + rows.Add(Row($"{prefix} m1", GetDouble(trial, "M1"), "g,模拟皮肤质量变化")); + rows.Add(Row($"{prefix} m2", GetDouble(trial, "M2"), "g,标准长筒袜质量变化")); + rows.Add(Row($"{prefix} m3", GetDouble(trial, "M3"), "g,样品鞋质量变化")); + rows.Add(Row($"{prefix} m4", GetDouble(trial, "M4"), "g,鞋垫质量变化")); + rows.Add(Row($"{prefix} T180", GetDouble(trial, "T180"), "g,散发到环境中的水汽质量")); + rows.Add(Row($"{prefix} m1*", GetDouble(trial, "M1Corrected"), "g,按 15 g 修正")); + rows.Add(Row($"{prefix} m2*", GetDouble(trial, "M2Corrected"), "g,按 15 g 修正")); + rows.Add(Row($"{prefix} m3*", GetDouble(trial, "M3Corrected"), "g,按 15 g 修正")); + rows.Add(Row($"{prefix} m4*", GetDouble(trial, "M4Corrected"), "g,按 15 g 修正")); + rows.Add(Row($"{prefix} T180*", GetDouble(trial, "T180Corrected"), "g,透水汽性能")); + rows.Add(Row($"{prefix} XT180*", GetDouble(trial, "XT180Corrected"), "g,吸湿透水汽性能")); + } + + private static void AddWarmthCycleRows(List> rows, string prefix, JsonElement cycle) + { + rows.Add(Row($"{prefix} P", GetDouble(cycle, "EnergyKilojoules"), "kJ,180 min 能量消耗")); + rows.Add(Row($"{prefix} t", GetDouble(cycle, "Seconds"), "s,测试周期")); + rows.Add(Row($"{prefix} Q", GetDouble(cycle, "HeatWatts"), "W,单位时间热量消耗")); + rows.Add(Row($"{prefix} Tf", GetDouble(cycle, "FootTemperatureC"), "℃,假脚表面温度平均值")); + rows.Add(Row($"{prefix} Tc", GetDouble(cycle, "ChamberTemperatureC"), "℃,测试箱环境温度平均值")); + rows.Add(Row($"{prefix} R", GetDouble(cycle, "ThermalResistance"), "m2·℃/W,保暖性能热阻值")); + } + private static WorksheetData CreateMethodBMassSheet(JsonElement root) { var rows = new List> @@ -226,25 +260,39 @@ public sealed class ExcelReportService if (root.TryGetProperty("Masses", out var masses)) { - rows.Add(Row("m11", GetDouble(masses, "M11"), "模拟皮肤测试前质量")); - rows.Add(Row("m12", GetDouble(masses, "M12"), "模拟皮肤测试后质量")); - rows.Add(Row("m21", GetDouble(masses, "M21"), "标准长筒袜测试前质量")); - rows.Add(Row("m22", GetDouble(masses, "M22"), "标准长筒袜测试后质量")); - rows.Add(Row("m31", GetDouble(masses, "M31"), "样品鞋测试前质量")); - rows.Add(Row("m32", GetDouble(masses, "M32"), "样品鞋测试后质量")); - rows.Add(Row("m41", GetDouble(masses, "M41"), "鞋垫测试前质量")); - rows.Add(Row("m42", GetDouble(masses, "M42"), "鞋垫测试后质量")); - rows.Add(Row("m51", GetDouble(masses, "M51"), "C1 测试前质量")); - rows.Add(Row("m52", GetDouble(masses, "M52"), "C1 测试后质量")); - rows.Add(Row("m61", GetDouble(masses, "M61"), "C2 测试前质量")); - rows.Add(Row("m62", GetDouble(masses, "M62"), "C2 测试后质量")); - rows.Add(Row("m71", GetDouble(masses, "M71"), "C3 测试前质量")); - rows.Add(Row("m72", GetDouble(masses, "M72"), "C3 测试后质量")); + if (masses.TryGetProperty("Trial1", out var trial1) && masses.TryGetProperty("Trial2", out var trial2)) + { + AddMassRows(rows, "第1次", trial1); + AddMassRows(rows, "第2次", trial2); + } + else + { + AddMassRows(rows, "", masses); + } } return new WorksheetData("方法B称重", rows); } + private static void AddMassRows(List> rows, string prefix, JsonElement masses) + { + var label = string.IsNullOrWhiteSpace(prefix) ? "" : $"{prefix} "; + rows.Add(Row($"{label}m11", GetDouble(masses, "M11"), "模拟皮肤测试前质量")); + rows.Add(Row($"{label}m12", GetDouble(masses, "M12"), "模拟皮肤测试后质量")); + rows.Add(Row($"{label}m21", GetDouble(masses, "M21"), "标准长筒袜测试前质量")); + rows.Add(Row($"{label}m22", GetDouble(masses, "M22"), "标准长筒袜测试后质量")); + rows.Add(Row($"{label}m31", GetDouble(masses, "M31"), "样品鞋测试前质量")); + rows.Add(Row($"{label}m32", GetDouble(masses, "M32"), "样品鞋测试后质量")); + rows.Add(Row($"{label}m41", GetDouble(masses, "M41"), "鞋垫测试前质量")); + rows.Add(Row($"{label}m42", GetDouble(masses, "M42"), "鞋垫测试后质量")); + rows.Add(Row($"{label}m51", GetDouble(masses, "M51"), "C1 测试前质量")); + rows.Add(Row($"{label}m52", GetDouble(masses, "M52"), "C1 测试后质量")); + rows.Add(Row($"{label}m61", GetDouble(masses, "M61"), "C2 测试前质量")); + rows.Add(Row($"{label}m62", GetDouble(masses, "M62"), "C2 测试后质量")); + rows.Add(Row($"{label}m71", GetDouble(masses, "M71"), "C3 测试前质量")); + rows.Add(Row($"{label}m72", GetDouble(masses, "M72"), "C3 测试后质量")); + } + private static WorksheetData CreateProcedureSheet(JsonElement root) { var rows = new List> @@ -471,6 +519,11 @@ public sealed class ExcelReportService return element.TryGetProperty(property, out var value) && value.ValueKind == JsonValueKind.True; } + private static double Round(double value, int digits) + { + return Math.Round(value, digits, MidpointRounding.AwayFromZero); + } + private static string ColumnName(int column) { var name = ""; diff --git a/FootwearTest/Services/TestFormulaService.cs b/FootwearTest/Services/TestFormulaService.cs index a5f11bf..7f2a89b 100644 --- a/FootwearTest/Services/TestFormulaService.cs +++ b/FootwearTest/Services/TestFormulaService.cs @@ -8,6 +8,8 @@ namespace FootwearTest.Services; public sealed class TestFormulaService { private const double VaporizationHeatWhPerGram = 0.672; + private const double MethodBTargetWaterGrams = 15.0; + private const double MethodBWaterToleranceGrams = 0.9; public double CalculateSkinMoistureResistance( double footAreaSquareMeters, @@ -17,9 +19,11 @@ public sealed class TestFormulaService double environmentRelativeHumidity, double nakedFootSweatGramsPerHour) { + EnsurePositive(nakedFootSweatGramsPerHour, "裸脚状态下的出汗量 Qn"); + return footAreaSquareMeters * (skinSaturatedVaporPressurePa * skinRelativeHumidity - environmentSaturatedVaporPressurePa * environmentRelativeHumidity) / - (VaporizationHeatWhPerGram * Math.Max(nakedFootSweatGramsPerHour, 0.001)); + (VaporizationHeatWhPerGram * nakedFootSweatGramsPerHour); } public MethodASampleRecord CalculateMethodASample( @@ -30,11 +34,15 @@ public sealed class TestFormulaService double skinSaturatedVaporPressurePa = 5623.0, double environmentSaturatedVaporPressurePa = 2809.0) { - var he = VaporizationHeatWhPerGram * Math.Max(snapshot.WaterLossGramsPerHour, 0.001); + EnsurePositive(snapshot.WaterLossGramsPerHour, "整鞋蒸发出汗量 Q"); + + var he = VaporizationHeatWhPerGram * snapshot.WaterLossGramsPerHour; var re = footAreaSquareMeters * (skinSaturatedVaporPressurePa - environmentSaturatedVaporPressurePa * snapshot.EnvironmentHumidityPercent / 100.0) / he - skinMoistureResistance; - var hd = Math.Max(snapshot.PowerWatts - he, 0.001); + var hd = snapshot.PowerWatts - he; + EnsurePositive(hd, "通过整鞋的干热量 Hd"); + var rt = footAreaSquareMeters * (snapshot.FootTemperatureC - snapshot.EnvironmentTemperatureC) / hd; return new MethodASampleRecord( @@ -45,10 +53,10 @@ public sealed class TestFormulaService snapshot.EnvironmentHumidityPercent, snapshot.WaterLossGramsPerHour, snapshot.PowerWatts, - Math.Round(he, 3), - Math.Round(hd, 3), - Math.Round(re, 3), - Math.Round(rt, 4)); + Round(he, 3), + Round(hd, 3), + Round(re, 3), + Round(rt, 4)); } public double Average(IEnumerable values) @@ -87,7 +95,7 @@ public sealed class TestFormulaService return list.All(value => Math.Abs(value - average) <= Math.Abs(average) * 0.10); } - public MethodBMoistureResult CalculateMethodBMoisture( + public MethodBMoistureTrialResult CalculateMethodBMoistureTrial( double m11, double m12, double m21, @@ -108,49 +116,92 @@ public sealed class TestFormulaService var m7 = m71 - m72; var m8 = (m6 + m7) / 2.0; var m180 = m5 - m8; - var scale = 15.0 / Math.Max(m180, 0.001); + EnsurePositive(m180, "180 min 测试过程中泵进鞋腔内水的总质量 m180"); + var scale = MethodBTargetWaterGrams / m180; var m1 = m12 - m11; var m2 = m22 - m21; var m3 = m32 - m31; var m4 = m42 - m41; var t180 = m180 - m1 - m2 - m3 - m4; + var t180Corrected = t180 * scale; + var m3Corrected = m3 * scale; + var m4Corrected = m4 * scale; - return new MethodBMoistureResult( - Math.Round(m1, 3), - Math.Round(m2, 3), - Math.Round(m3, 3), - Math.Round(m4, 3), - Math.Round(m5, 3), - Math.Round(m6, 3), - Math.Round(m7, 3), - Math.Round(m8, 3), - Math.Round(m180, 3), - Math.Round(t180, 3), - Math.Round(m1 * scale, 3), - Math.Round(m2 * scale, 3), - Math.Round(m3 * scale, 3), - Math.Round(m4 * scale, 3), - Math.Round(t180 * scale, 3), - Math.Round((t180 + m3 + m4) * scale, 3), - m180 >= 14.1 && m180 <= 15.9); + return new MethodBMoistureTrialResult( + Round(m1, 3), + Round(m2, 3), + Round(m3, 3), + Round(m4, 3), + Round(m5, 3), + Round(m6, 3), + Round(m7, 3), + Round(m8, 3), + Round(m180, 3), + Round(t180, 3), + Round(m1 * scale, 3), + Round(m2 * scale, 3), + Round(m3Corrected, 3), + Round(m4Corrected, 3), + Round(t180Corrected, 3), + Round(t180Corrected + m3Corrected + m4Corrected, 3), + m180 >= MethodBTargetWaterGrams - MethodBWaterToleranceGrams && + m180 <= MethodBTargetWaterGrams + MethodBWaterToleranceGrams); } - public MethodBWarmthResult CalculateMethodBWarmth( + public MethodBMoistureResult CalculateMethodBMoisture( + MethodBMoistureTrialResult trial1, + MethodBMoistureTrialResult trial2) + { + return new MethodBMoistureResult( + trial1, + trial2, + Round((trial1.T180Corrected + trial2.T180Corrected) / 2.0, 2), + Round((trial1.XT180Corrected + trial2.XT180Corrected) / 2.0, 2), + trial1.IsValid && trial2.IsValid); + } + + public MethodBWarmthCycleResult CalculateMethodBWarmthCycle( double energyKilojoules, double seconds, double footAreaSquareMeters, double footTemperatureC, double chamberTemperatureC) { - var heatWatts = energyKilojoules / Math.Max(seconds, 1.0) * 1000.0; - var resistance = footAreaSquareMeters * (footTemperatureC - chamberTemperatureC) / Math.Max(heatWatts, 0.001); - return new MethodBWarmthResult( - Math.Round(energyKilojoules, 1), + EnsurePositive(seconds, "测试周期时长 t"); + EnsurePositive(energyKilojoules, "180 min 测试周期内的能量消耗 P"); + + var heatWatts = energyKilojoules / seconds * 1000.0; + var resistance = footAreaSquareMeters * (footTemperatureC - chamberTemperatureC) / heatWatts; + return new MethodBWarmthCycleResult( + Round(energyKilojoules, 1), seconds, - Math.Round(heatWatts, 3), - Math.Round(footTemperatureC, 2), - Math.Round(chamberTemperatureC, 2), - Math.Round(resistance, 3)); + Round(heatWatts, 3), + Round(footTemperatureC, 2), + Round(chamberTemperatureC, 2), + Round(resistance, 3)); + } + + public MethodBWarmthResult CalculateMethodBWarmth( + MethodBWarmthCycleResult cycle1, + MethodBWarmthCycleResult cycle2) + { + return new MethodBWarmthResult( + cycle1, + cycle2, + Round((cycle1.ThermalResistance + cycle2.ThermalResistance) / 2.0, 3)); + } + + private static double Round(double value, int digits) + { + return Math.Round(value, digits, MidpointRounding.AwayFromZero); + } + + private static void EnsurePositive(double value, string name) + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, $"{name} 必须大于 0,无法按 GB/T 33393 公式计算。"); + } } } diff --git a/FootwearTest/ViewModels/MethodAViewModel.cs b/FootwearTest/ViewModels/MethodAViewModel.cs index 6aeda95..b1ebf28 100644 --- a/FootwearTest/ViewModels/MethodAViewModel.cs +++ b/FootwearTest/ViewModels/MethodAViewModel.cs @@ -120,6 +120,7 @@ public partial class MethodAViewModel : ViewModelBase Samples.Clear(); await _deviceClient.SetOutputsAsync(true, true, true); + var skinResistanceValues = new double[30]; for (var i = 1; i <= 30; i++) { await Task.Delay(60); @@ -131,12 +132,16 @@ public partial class MethodAViewModel : ViewModelBase 2809.0, snapshot.EnvironmentHumidityPercent / 100.0, snapshot.WaterLossGramsPerHour); - SkinMoistureResistance = Math.Round(value, 3); - Samples.Add(_formulaService.CalculateMethodASample(i, snapshot, _settings.FootAreaSquareMeters, SkinMoistureResistance)); + skinResistanceValues[i - 1] = value; + SkinMoistureResistance = Round(_formulaService.Average(skinResistanceValues.Take(i)), 3); } await _deviceClient.SetOutputsAsync(false, true, false); - UpdateMethodAResult("皮肤湿阻"); + MoistureCvPercent = Round(_formulaService.CoefficientOfVariationPercent(skinResistanceValues), 2); + ThermalCvPercent = 0; + AverageMoistureResistance = 0; + AverageThermalResistance = 0; + ResultText = $"皮肤湿阻: Res {SkinMoistureResistance:F3} Pa·m²/W,CV {MoistureCvPercent:F2}%"; var id = await SaveRunAsync("方法 A - 皮肤湿阻", true); StatusText = "皮肤湿阻测定完成"; _logger.LogInformation("Method A skin moisture resistance completed. RecordId={RecordId}, Samples={Samples}, Result={ResultText}", id, Samples.Count, ResultText); @@ -178,7 +183,9 @@ public partial class MethodAViewModel : ViewModelBase } await _deviceClient.SetOutputsAsync(false, true, false); - var passed = _formulaService.PassesTenPercentDeviation(Samples.Select(sample => sample.ThermalResistance)); + var passed = + _formulaService.PassesTenPercentDeviation(Samples.Select(sample => sample.MoistureResistance)) && + _formulaService.PassesTenPercentDeviation(Samples.Select(sample => sample.ThermalResistance)); UpdateMethodAResult("整鞋热阻/湿阻"); var id = await SaveRunAsync("方法 A - 整鞋热阻/湿阻", passed); StatusText = passed ? "试验完成" : "结果偏差超过 ±10%,建议重测"; @@ -222,13 +229,18 @@ public partial class MethodAViewModel : ViewModelBase private void UpdateMethodAResult(string stage) { - AverageMoistureResistance = Math.Round(_formulaService.Average(Samples.Select(sample => sample.MoistureResistance)), 3); - AverageThermalResistance = Math.Round(_formulaService.Average(Samples.Select(sample => sample.ThermalResistance)), 4); - MoistureCvPercent = Math.Round(_formulaService.CoefficientOfVariationPercent(Samples.Select(sample => sample.MoistureResistance)), 2); - ThermalCvPercent = Math.Round(_formulaService.CoefficientOfVariationPercent(Samples.Select(sample => sample.ThermalResistance)), 2); + AverageMoistureResistance = Round(_formulaService.Average(Samples.Select(sample => sample.MoistureResistance)), 3); + AverageThermalResistance = Round(_formulaService.Average(Samples.Select(sample => sample.ThermalResistance)), 4); + MoistureCvPercent = Round(_formulaService.CoefficientOfVariationPercent(Samples.Select(sample => sample.MoistureResistance)), 2); + ThermalCvPercent = Round(_formulaService.CoefficientOfVariationPercent(Samples.Select(sample => sample.ThermalResistance)), 2); ResultText = $"{stage}: 湿阻 {AverageMoistureResistance:F3} Pa·m²/W,热阻 {AverageThermalResistance:F4} m²·℃/W,CV {ThermalCvPercent:F2}%"; } + private static double Round(double value, int digits) + { + return Math.Round(value, digits, MidpointRounding.AwayFromZero); + } + private async Task StopOutputsAfterFailureAsync(string reason) { try diff --git a/FootwearTest/ViewModels/MethodBViewModel.cs b/FootwearTest/ViewModels/MethodBViewModel.cs index 0ccaf1f..b0b3b2b 100644 --- a/FootwearTest/ViewModels/MethodBViewModel.cs +++ b/FootwearTest/ViewModels/MethodBViewModel.cs @@ -57,8 +57,24 @@ public partial class MethodBViewModel : ViewModelBase private double _m62 = 99.80; private double _m71 = 100.00; private double _m72 = 99.78; + private double _m11Second = 6.00; + private double _m12Second = 7.08; + private double _m21Second = 14.00; + private double _m22Second = 16.36; + private double _m31Second = 410.00; + private double _m32Second = 413.15; + private double _m41Second = 18.00; + private double _m42Second = 18.95; + private double _m51Second = 100.00; + private double _m52Second = 84.74; + private double _m61Second = 100.00; + private double _m62Second = 99.81; + private double _m71Second = 100.00; + private double _m72Second = 99.79; private double _warmthEnergyKilojoules = 48.2; private double _warmthSeconds = 10800; + private double _warmthEnergyKilojoulesSecond = 48.0; + private double _warmthSecondsSecond = 10800; public string SampleDescription { get => _sampleDescription; set => SetProperty(ref _sampleDescription, value); } public string StatusText { get => _statusText; set => SetProperty(ref _statusText, value); } @@ -80,8 +96,24 @@ public partial class MethodBViewModel : ViewModelBase public double M62 { get => _m62; set => SetProperty(ref _m62, value); } public double M71 { get => _m71; set => SetProperty(ref _m71, value); } public double M72 { get => _m72; set => SetProperty(ref _m72, value); } + public double M11Second { get => _m11Second; set => SetProperty(ref _m11Second, value); } + public double M12Second { get => _m12Second; set => SetProperty(ref _m12Second, value); } + public double M21Second { get => _m21Second; set => SetProperty(ref _m21Second, value); } + public double M22Second { get => _m22Second; set => SetProperty(ref _m22Second, value); } + public double M31Second { get => _m31Second; set => SetProperty(ref _m31Second, value); } + public double M32Second { get => _m32Second; set => SetProperty(ref _m32Second, value); } + public double M41Second { get => _m41Second; set => SetProperty(ref _m41Second, value); } + public double M42Second { get => _m42Second; set => SetProperty(ref _m42Second, value); } + public double M51Second { get => _m51Second; set => SetProperty(ref _m51Second, value); } + public double M52Second { get => _m52Second; set => SetProperty(ref _m52Second, value); } + public double M61Second { get => _m61Second; set => SetProperty(ref _m61Second, value); } + public double M62Second { get => _m62Second; set => SetProperty(ref _m62Second, value); } + public double M71Second { get => _m71Second; set => SetProperty(ref _m71Second, value); } + public double M72Second { get => _m72Second; set => SetProperty(ref _m72Second, value); } public double WarmthEnergyKilojoules { get => _warmthEnergyKilojoules; set => SetProperty(ref _warmthEnergyKilojoules, value); } public double WarmthSeconds { get => _warmthSeconds; set => SetProperty(ref _warmthSeconds, value); } + public double WarmthEnergyKilojoulesSecond { get => _warmthEnergyKilojoulesSecond; set => SetProperty(ref _warmthEnergyKilojoulesSecond, value); } + public double WarmthSecondsSecond { get => _warmthSecondsSecond; set => SetProperty(ref _warmthSecondsSecond, value); } private async Task RunMoistureAsync() { @@ -101,13 +133,15 @@ public partial class MethodBViewModel : ViewModelBase ProcedureLog.Add("模拟 180 min 周期完成,关闭泵、风扇及温控。"); await _deviceClient.SetOutputsAsync(false, false, false); - var result = _formulaService.CalculateMethodBMoisture(M11, M12, M21, M22, M31, M32, M41, M42, M51, M52, M61, M62, M71, M72); + var trial1 = _formulaService.CalculateMethodBMoistureTrial(M11, M12, M21, M22, M31, M32, M41, M42, M51, M52, M61, M62, M71, M72); + var trial2 = _formulaService.CalculateMethodBMoistureTrial(M11Second, M12Second, M21Second, M22Second, M31Second, M32Second, M41Second, M42Second, M51Second, M52Second, M61Second, M62Second, M71Second, M72Second); + var result = _formulaService.CalculateMethodBMoisture(trial1, trial2); MoistureResultText = result.IsValid - ? $"T180*={result.T180Corrected:F2} g,XT180*={result.XT180Corrected:F2} g,m180={result.M180:F2} g" - : $"m180={result.M180:F2} g,超出 15±0.9 g,结果作废"; + ? $"T180*平均={result.AverageT180Corrected:F2} g,XT180*平均={result.AverageXT180Corrected:F2} g" + : $"第1次 m180={trial1.M180:F2} g,第2次 m180={trial2.M180:F2} g,存在超出 15±0.9 g,结果作废"; MoistureDetailText = - $"m1={result.M1:F3} g,m2={result.M2:F3} g,m3={result.M3:F3} g,m4={result.M4:F3} g\n" + - $"m5={result.M5:F3} g,m6={result.M6:F3} g,m7={result.M7:F3} g,m8={result.M8:F3} g,T180={result.T180:F3} g"; + $"第1次: m180={trial1.M180:F3} g,T180*={trial1.T180Corrected:F3} g,XT180*={trial1.XT180Corrected:F3} g\n" + + $"第2次: m180={trial2.M180:F3} g,T180*={trial2.T180Corrected:F3} g,XT180*={trial2.XT180Corrected:F3} g"; StatusText = result.IsValid ? "吸湿透水汽测试完成" : "吸湿透水汽测试需重测"; var id = await SaveRunAsync("方法 B - 吸湿透水汽性能", MoistureResultText, result, result.IsValid); @@ -133,17 +167,26 @@ public partial class MethodBViewModel : ViewModelBase ProcedureLog.Add("开启风扇和温控,稳定到 38±1 ℃。"); await _deviceClient.SetOutputsAsync(false, true, true); await Task.Delay(500); - ProcedureLog.Add("记录两个 180 min 周期能量消耗,生成热阻结果。"); + ProcedureLog.Add("记录两个 180 min 周期能量消耗,分别计算热阻并取平均。"); await _deviceClient.SetOutputsAsync(false, false, false); - var result = _formulaService.CalculateMethodBWarmth( + var cycle1 = _formulaService.CalculateMethodBWarmthCycle( WarmthEnergyKilojoules, WarmthSeconds, _settings.FootAreaSquareMeters, _settings.MethodBWarmthTargetTemperatureC, _settings.EnvironmentTemperatureC); - WarmthResultText = $"Q={result.HeatWatts:F3} W,R={result.ThermalResistance:F3} m²·℃/W"; - WarmthDetailText = $"P={result.EnergyKilojoules:F1} kJ,t={result.Seconds:F0} s,Tf={result.FootTemperatureC:F2} ℃,Tc={result.ChamberTemperatureC:F2} ℃"; + var cycle2 = _formulaService.CalculateMethodBWarmthCycle( + WarmthEnergyKilojoulesSecond, + WarmthSecondsSecond, + _settings.FootAreaSquareMeters, + _settings.MethodBWarmthTargetTemperatureC, + _settings.EnvironmentTemperatureC); + var result = _formulaService.CalculateMethodBWarmth(cycle1, cycle2); + WarmthResultText = $"R平均={result.AverageThermalResistance:F3} m²·℃/W"; + WarmthDetailText = + $"第1周期: P={cycle1.EnergyKilojoules:F1} kJ,Q={cycle1.HeatWatts:F3} W,R={cycle1.ThermalResistance:F3} m²·℃/W\n" + + $"第2周期: P={cycle2.EnergyKilojoules:F1} kJ,Q={cycle2.HeatWatts:F3} W,R={cycle2.ThermalResistance:F3} m²·℃/W"; StatusText = "保暖性能测试完成"; var id = await SaveRunAsync("方法 B - 保暖性能", WarmthResultText, result, true); @@ -180,12 +223,29 @@ public partial class MethodBViewModel : ViewModelBase private async Task SaveRunAsync(string method, string summary, object result, bool isValid) { - var data = JsonSerializer.Serialize(new - { - Result = result, - Masses = new { M11, M12, M21, M22, M31, M32, M41, M42, M51, M52, M61, M62, M71, M72 }, - ProcedureLog - }, new JsonSerializerOptions { WriteIndented = true }); + object payload = method.Contains("吸湿透水汽", StringComparison.Ordinal) + ? new + { + Result = result, + Masses = new + { + Trial1 = new { M11, M12, M21, M22, M31, M32, M41, M42, M51, M52, M61, M62, M71, M72 }, + Trial2 = new { M11 = M11Second, M12 = M12Second, M21 = M21Second, M22 = M22Second, M31 = M31Second, M32 = M32Second, M41 = M41Second, M42 = M42Second, M51 = M51Second, M52 = M52Second, M61 = M61Second, M62 = M62Second, M71 = M71Second, M72 = M72Second } + }, + ProcedureLog + } + : new + { + Result = result, + WarmthInputs = new + { + Cycle1 = new { EnergyKilojoules = WarmthEnergyKilojoules, Seconds = WarmthSeconds }, + Cycle2 = new { EnergyKilojoules = WarmthEnergyKilojoulesSecond, Seconds = WarmthSecondsSecond } + }, + ProcedureLog + }; + + var data = JsonSerializer.Serialize(payload, new JsonSerializerOptions { WriteIndented = true }); return await _repository.SaveAsync(new TestRunRecord( 0, diff --git a/FootwearTest/Views/MethodBView.axaml b/FootwearTest/Views/MethodBView.axaml index f6fddb2..de17371 100644 --- a/FootwearTest/Views/MethodBView.axaml +++ b/FootwearTest/Views/MethodBView.axaml @@ -33,7 +33,7 @@ - + @@ -41,18 +41,22 @@ - + - + + + + + - + - + @@ -89,7 +93,46 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -101,7 +144,7 @@ - +