From 0139c4475bb69fa18c14a9d26bab79d5327f4ee7 Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Wed, 27 May 2026 17:59:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConeCalorimeter/Models/RealtimeDataRecord.cs | 2 + ConeCalorimeter/Models/RealtimeSnapshot.cs | 1 + .../Services/ModbusRealtimeDataService.cs | 50 +++++++++++++++++++ .../Services/NpoiRealtimeDataExportService.cs | 30 +++++------ .../Services/NpoiReportExportService.cs | 22 ++++---- .../Services/SerialScaleOptions.cs | 2 +- .../ViewModels/RealtimeDataRowViewModel.cs | 12 ++--- ConeCalorimeter/Views/RealtimeDataView.xaml | 4 +- 8 files changed, 80 insertions(+), 43 deletions(-) diff --git a/ConeCalorimeter/Models/RealtimeDataRecord.cs b/ConeCalorimeter/Models/RealtimeDataRecord.cs index c7c82b8..aa9663f 100644 --- a/ConeCalorimeter/Models/RealtimeDataRecord.cs +++ b/ConeCalorimeter/Models/RealtimeDataRecord.cs @@ -12,6 +12,7 @@ public sealed record RealtimeDataRecord( double Oxygen, double CarbonDioxide, double CarbonMonoxide, + double Absorbance, double HeatReleaseRate, double PeakHeatReleaseRate, double CFactor, @@ -43,6 +44,7 @@ public sealed record RealtimeDataRecord( snapshot.Oxygen, snapshot.CarbonDioxide, snapshot.CarbonMonoxide, + snapshot.Absorbance, snapshot.HeatReleaseRate, snapshot.PeakHeatReleaseRate, snapshot.CFactor, diff --git a/ConeCalorimeter/Models/RealtimeSnapshot.cs b/ConeCalorimeter/Models/RealtimeSnapshot.cs index 9912a80..adb1b47 100644 --- a/ConeCalorimeter/Models/RealtimeSnapshot.cs +++ b/ConeCalorimeter/Models/RealtimeSnapshot.cs @@ -11,6 +11,7 @@ public sealed record RealtimeSnapshot( double Oxygen, double CarbonDioxide, double CarbonMonoxide, + double Absorbance, double HeatReleaseRate, double PeakHeatReleaseRate, double CFactor, diff --git a/ConeCalorimeter/Services/ModbusRealtimeDataService.cs b/ConeCalorimeter/Services/ModbusRealtimeDataService.cs index 7cc91ec..1fbc72d 100644 --- a/ConeCalorimeter/Services/ModbusRealtimeDataService.cs +++ b/ConeCalorimeter/Services/ModbusRealtimeDataService.cs @@ -16,6 +16,9 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService private const ushort ConeTemperatureRegister = 26; private const ushort OrificeTemperatureRegister = 30; private const ushort SampleTemperatureRegister = 36; + private const ushort AbsorbanceRegister = 120; + private const double AbsorbanceStableTolerance = 0.25; + private const int AbsorbanceStableReadCount = 2; private const ushort CFactorRegister = 312; private const ushort HeatReleaseRateRegister = 354; private const ushort PeakHeatReleaseRateRegister = 376; @@ -40,6 +43,9 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService private readonly HashSet _loggedInvalidFloatDiagnostics = []; private readonly Dictionary _stableRealtimeValues = []; private readonly Dictionary _pendingZeroReadCounts = []; + private double? _stableAbsorbance; + private double? _pendingAbsorbance; + private int _pendingAbsorbanceReadCount; private ModbusFloatByteOrder? _preferredFloatByteOrder; public ModbusRealtimeDataService( @@ -69,6 +75,7 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService Oxygen: ReadRangedFloatOrEmpty("O2", OxygenRegister, 0, 30), CarbonDioxide: ReadRangedFloatOrEmpty("CO2", CarbonDioxideRegister, 0, 20), CarbonMonoxide: ReadRangedFloatOrEmpty("CO", CarbonMonoxideRegister, 0, 10), + Absorbance: ReadAbsorbanceOrEmpty(), HeatReleaseRate: ReadRangedFloatOrEmpty("HeatReleaseRate", HeatReleaseRateRegister, 0, 5000), PeakHeatReleaseRate: ReadRangedFloatOrEmpty("PeakHeatReleaseRate", PeakHeatReleaseRateRegister, 0, 5000), CFactor: ReadRangedFloatOrEmpty("CFactor", CFactorRegister, 0, 1000), @@ -102,6 +109,49 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService return StabilizeRealtimeValue(registerAddress, value); } + private double ReadAbsorbanceOrEmpty() + { + var value = ReadRangedFloatOrEmpty("Absorbance", AbsorbanceRegister, 0, 100); + return double.IsFinite(value) && TryUpdateStableAbsorbance(value, out var stableValue) + ? stableValue + : double.NaN; + } + + private bool TryUpdateStableAbsorbance(double value, out double stableValue) + { + stableValue = _stableAbsorbance ?? value; + + if (_stableAbsorbance.HasValue + && Math.Abs(value - _stableAbsorbance.Value) <= AbsorbanceStableTolerance) + { + _pendingAbsorbance = null; + _pendingAbsorbanceReadCount = 0; + stableValue = _stableAbsorbance.Value; + return true; + } + + if (!_pendingAbsorbance.HasValue + || Math.Abs(value - _pendingAbsorbance.Value) > AbsorbanceStableTolerance) + { + _pendingAbsorbance = value; + _pendingAbsorbanceReadCount = 1; + return false; + } + + _pendingAbsorbanceReadCount++; + + if (_pendingAbsorbanceReadCount < AbsorbanceStableReadCount) + { + return false; + } + + _stableAbsorbance = value; + _pendingAbsorbance = null; + _pendingAbsorbanceReadCount = 0; + stableValue = value; + return true; + } + private bool TrySelectRealtimeFloat( ModbusFloatReadResult result, double minimum, diff --git a/ConeCalorimeter/Services/NpoiRealtimeDataExportService.cs b/ConeCalorimeter/Services/NpoiRealtimeDataExportService.cs index 6e04bda..ef4eda4 100644 --- a/ConeCalorimeter/Services/NpoiRealtimeDataExportService.cs +++ b/ConeCalorimeter/Services/NpoiRealtimeDataExportService.cs @@ -13,19 +13,17 @@ public sealed class NpoiRealtimeDataExportService : IRealtimeDataExportService "O2 (%)", "CO2 (%)", "CO (%)", + "吸光率%", "孔板压差 (Pa)", "孔板温度 (K)", "HRR", - "热释放速率180", - "热释放速率300", "THR (MJ/m2)", "SPR", "TSR (m2)", "MLR (g/s)", "热释放KW/m2", "EHC", - "损失质量", - "试样温度(℃)" + "损失质量" ]; public void Export(string outputPath, IReadOnlyList records) @@ -60,19 +58,17 @@ public sealed class NpoiRealtimeDataExportService : IRealtimeDataExportService SetNumeric(row, 1, record.Oxygen); SetNumeric(row, 2, record.CarbonDioxide); SetNumeric(row, 3, record.CarbonMonoxide); - SetNumeric(row, 4, record.OrificePressure); - SetNumeric(row, 5, record.OrificeTemperature); - SetNumeric(row, 6, record.HeatReleaseRate); - SetNumeric(row, 7, record.Qa180); - SetNumeric(row, 8, record.Qa300); - SetNumeric(row, 9, record.TotalHeatRelease); - SetNumeric(row, 10, record.SmokeProduction); - SetNumeric(row, 11, record.TotalSmoke); - SetNumeric(row, 12, record.MassLossRate); - SetNumeric(row, 13, record.HeatReleaseRateKw); - SetNumeric(row, 14, record.EffectiveHeatOfCombustion); - SetNumeric(row, 15, record.MassLoss); - SetNumeric(row, 16, record.SampleTemperature); + SetNumeric(row, 4, record.Absorbance); + SetNumeric(row, 5, record.OrificePressure); + SetNumeric(row, 6, record.OrificeTemperature); + SetNumeric(row, 7, record.HeatReleaseRate); + SetNumeric(row, 8, record.TotalHeatRelease); + SetNumeric(row, 9, record.SmokeProduction); + SetNumeric(row, 10, record.TotalSmoke); + SetNumeric(row, 11, record.MassLossRate); + SetNumeric(row, 12, record.HeatReleaseRateKw); + SetNumeric(row, 13, record.EffectiveHeatOfCombustion); + SetNumeric(row, 14, record.MassLoss); } for (var i = 0; i < Headers.Length; i++) diff --git a/ConeCalorimeter/Services/NpoiReportExportService.cs b/ConeCalorimeter/Services/NpoiReportExportService.cs index e676225..bcee2ff 100644 --- a/ConeCalorimeter/Services/NpoiReportExportService.cs +++ b/ConeCalorimeter/Services/NpoiReportExportService.cs @@ -22,13 +22,13 @@ public sealed class NpoiReportExportService : IReportExportService "O2 (%)", "CO2 (%)", "CO (%)", + "吸光率%", "孔板压差 (Pa)", "孔板温度 (K)", "MLR (g/s)", "热释放KW/m2", "EHC", "损失质量", - "试样温度(℃)", "Timestamp", "点火计时(s)", "火焰监测", @@ -37,8 +37,6 @@ public sealed class NpoiReportExportService : IReportExportService "当前质量", "初始质量", "最大热释放", - "热释放速率180", - "热释放速率300", "C-系数" ]; @@ -176,13 +174,13 @@ public sealed class NpoiReportExportService : IReportExportService SetNumeric(row, 7, record.Oxygen); SetNumeric(row, 8, record.CarbonDioxide); SetNumeric(row, 9, record.CarbonMonoxide); - SetNumeric(row, 10, record.OrificePressure); - SetNumeric(row, 11, record.OrificeTemperature); - SetNumeric(row, 12, record.MassLossRate); - SetNumeric(row, 13, record.HeatReleaseRateKw); - SetNumeric(row, 14, record.EffectiveHeatOfCombustion); - SetNumeric(row, 15, record.MassLoss); - SetNumeric(row, 16, record.SampleTemperature); + SetNumeric(row, 10, record.Absorbance); + SetNumeric(row, 11, record.OrificePressure); + SetNumeric(row, 12, record.OrificeTemperature); + SetNumeric(row, 13, record.MassLossRate); + SetNumeric(row, 14, record.HeatReleaseRateKw); + SetNumeric(row, 15, record.EffectiveHeatOfCombustion); + SetNumeric(row, 16, record.MassLoss); row.CreateCell(17).SetCellValue(record.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture)); SetNumeric(row, 18, record.IgnitionSeconds >= 0 ? record.IgnitionSeconds : double.NaN); SetNumeric(row, 19, record.FlameDetected ? 1 : 0); @@ -191,9 +189,7 @@ public sealed class NpoiReportExportService : IReportExportService SetNumeric(row, 22, record.CurrentMass); SetNumeric(row, 23, record.InitialMass); SetNumeric(row, 24, record.PeakHeatReleaseRate); - SetNumeric(row, 25, record.Qa180); - SetNumeric(row, 26, record.Qa300); - SetNumeric(row, 27, record.CFactor); + SetNumeric(row, 25, record.CFactor); } for (var i = 0; i < DataHeaders.Length; i++) diff --git a/ConeCalorimeter/Services/SerialScaleOptions.cs b/ConeCalorimeter/Services/SerialScaleOptions.cs index 4eadce5..49d3bc8 100644 --- a/ConeCalorimeter/Services/SerialScaleOptions.cs +++ b/ConeCalorimeter/Services/SerialScaleOptions.cs @@ -20,7 +20,7 @@ public sealed record SerialScaleOptions( public const string RegisterEnvironmentVariable = "CONE_SCALE_REGISTER"; public static SerialScaleOptions Default { get; } = new( - "COM1", + "COM3", 9600, Parity.None, 8, diff --git a/ConeCalorimeter/ViewModels/RealtimeDataRowViewModel.cs b/ConeCalorimeter/ViewModels/RealtimeDataRowViewModel.cs index 25cd94a..a8d9dd6 100644 --- a/ConeCalorimeter/ViewModels/RealtimeDataRowViewModel.cs +++ b/ConeCalorimeter/ViewModels/RealtimeDataRowViewModel.cs @@ -17,9 +17,8 @@ public sealed class RealtimeDataRowViewModel CarbonMonoxideText = Format(record.CarbonMonoxide); OrificePressureText = Format(record.OrificePressure); OrificeTemperatureText = Format(record.OrificeTemperature); + AbsorbanceText = Format(record.Absorbance); Hrr50Text = Format(record.HeatReleaseRate); - Qa180Text = Format(record.Qa180); - Qa300Text = Format(record.Qa300); ThrText = Format(record.TotalHeatRelease); Spr50Text = Format(record.SmokeProduction); TsrText = Format(record.TotalSmoke); @@ -27,7 +26,6 @@ public sealed class RealtimeDataRowViewModel HeatReleaseText = Format(record.HeatReleaseRateKw); EhcText = Format(record.EffectiveHeatOfCombustion); MassLossText = Format(record.MassLoss); - SampleTemperatureText = Format(record.SampleTemperature, "0.0"); } public string TimeText { get; init; } = string.Empty; @@ -42,12 +40,10 @@ public sealed class RealtimeDataRowViewModel public string OrificeTemperatureText { get; init; } = string.Empty; + public string AbsorbanceText { get; init; } = string.Empty; + public string Hrr50Text { get; init; } = string.Empty; - public string Qa180Text { get; init; } = string.Empty; - - public string Qa300Text { get; init; } = string.Empty; - public string ThrText { get; init; } = string.Empty; public string Spr50Text { get; init; } = string.Empty; @@ -62,8 +58,6 @@ public sealed class RealtimeDataRowViewModel public string MassLossText { get; init; } = string.Empty; - public string SampleTemperatureText { get; init; } = string.Empty; - private static string Format(double value, string format = "0.00") { return double.IsFinite(value) ? value.ToString(format, CultureInfo.InvariantCulture) : string.Empty; diff --git a/ConeCalorimeter/Views/RealtimeDataView.xaml b/ConeCalorimeter/Views/RealtimeDataView.xaml index 9ff633d..e583c7a 100644 --- a/ConeCalorimeter/Views/RealtimeDataView.xaml +++ b/ConeCalorimeter/Views/RealtimeDataView.xaml @@ -138,11 +138,10 @@ + - - @@ -150,7 +149,6 @@ -