From 8a6458071ae7a5642292557aa7dcf83f564d64aa Mon Sep 17 00:00:00 2001 From: "GukSang.Jin" Date: Thu, 7 May 2026 16:44:36 +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 | 11 +++--- ConeCalorimeter/Models/RealtimeSnapshot.cs | 1 + .../Services/ExperimentDataService.cs | 36 +++++++++++++++++-- .../Services/ModbusRealtimeDataService.cs | 1 + 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ConeCalorimeter/Models/RealtimeDataRecord.cs b/ConeCalorimeter/Models/RealtimeDataRecord.cs index b0c8cec..c7c82b8 100644 --- a/ConeCalorimeter/Models/RealtimeDataRecord.cs +++ b/ConeCalorimeter/Models/RealtimeDataRecord.cs @@ -22,10 +22,13 @@ public sealed record RealtimeDataRecord( double CurrentMass, double InitialMass, double MassLoss, + double MassLossRate, int IgnitionSeconds, int TestSeconds, double TotalSmoke) { + private const double DefaultIrradiatedAreaSquareMeters = 0.01; + public static RealtimeDataRecord FromSnapshot(RealtimeSnapshot snapshot) { return new RealtimeDataRecord( @@ -50,19 +53,17 @@ public sealed record RealtimeDataRecord( snapshot.CurrentMass, snapshot.InitialMass, snapshot.MassLoss, + snapshot.MassLossRate, snapshot.IgnitionSeconds, snapshot.TestSeconds, snapshot.TotalSmoke); } - public double MassLossRate => - double.IsFinite(MassLoss) && TestSeconds > 0 ? MassLoss / TestSeconds : double.NaN; - public double HeatReleaseRateKw => - double.IsFinite(HeatReleaseRate) ? HeatReleaseRate * 1000 : double.NaN; + double.IsFinite(HeatReleaseRate) ? HeatReleaseRate : double.NaN; public double EffectiveHeatOfCombustion => double.IsFinite(HeatReleaseRate) && double.IsFinite(MassLossRate) && MassLossRate > 0 - ? HeatReleaseRate / MassLossRate * 10 + ? HeatReleaseRate * DefaultIrradiatedAreaSquareMeters / MassLossRate : double.NaN; } diff --git a/ConeCalorimeter/Models/RealtimeSnapshot.cs b/ConeCalorimeter/Models/RealtimeSnapshot.cs index ae92312..9912a80 100644 --- a/ConeCalorimeter/Models/RealtimeSnapshot.cs +++ b/ConeCalorimeter/Models/RealtimeSnapshot.cs @@ -21,6 +21,7 @@ public sealed record RealtimeSnapshot( double CurrentMass, double InitialMass, double MassLoss, + double MassLossRate, int IgnitionSeconds, int TestSeconds, double TotalSmoke); diff --git a/ConeCalorimeter/Services/ExperimentDataService.cs b/ConeCalorimeter/Services/ExperimentDataService.cs index 3caf0e1..940d8fa 100644 --- a/ConeCalorimeter/Services/ExperimentDataService.cs +++ b/ConeCalorimeter/Services/ExperimentDataService.cs @@ -12,6 +12,8 @@ public sealed class ExperimentDataService : IExperimentDataService private readonly DispatcherTimer _timer; private readonly DateTime _startedAt = DateTime.Now; private double? _initialMass; + private double? _previousMass; + private int? _previousMassSeconds; private double _accumulatedTotalHeatRelease; private double _accumulatedTotalSmoke; private int? _lastAccumulationSeconds; @@ -139,7 +141,8 @@ public sealed class ExperimentDataService : IExperimentDataService return snapshot with { InitialMass = _initialMass ?? double.NaN, - MassLoss = double.NaN + MassLoss = double.NaN, + MassLossRate = double.NaN }; } @@ -151,17 +154,46 @@ public sealed class ExperimentDataService : IExperimentDataService var massLoss = _initialMass.HasValue && double.IsFinite(snapshot.CurrentMass) ? _initialMass.Value - snapshot.CurrentMass : double.NaN; + var massLossRate = CalculateMassLossRate(snapshot); return snapshot with { InitialMass = _initialMass ?? double.NaN, - MassLoss = massLoss + MassLoss = massLoss, + MassLossRate = massLossRate }; } + private double CalculateMassLossRate(RealtimeSnapshot snapshot) + { + if (snapshot.TestSeconds < 0 || !double.IsFinite(snapshot.CurrentMass)) + { + return double.NaN; + } + + if (!_previousMass.HasValue || !_previousMassSeconds.HasValue) + { + _previousMass = snapshot.CurrentMass; + _previousMassSeconds = snapshot.TestSeconds; + return double.NaN; + } + + var deltaSeconds = snapshot.TestSeconds - _previousMassSeconds.Value; + var deltaMass = _previousMass.Value - snapshot.CurrentMass; + + _previousMass = snapshot.CurrentMass; + _previousMassSeconds = snapshot.TestSeconds; + + return deltaSeconds > 0 && deltaMass >= 0 + ? deltaMass / deltaSeconds + : double.NaN; + } + private void ResetComputedState() { _initialMass = null; + _previousMass = null; + _previousMassSeconds = null; _accumulatedTotalHeatRelease = 0; _accumulatedTotalSmoke = 0; _lastAccumulationSeconds = null; diff --git a/ConeCalorimeter/Services/ModbusRealtimeDataService.cs b/ConeCalorimeter/Services/ModbusRealtimeDataService.cs index daaa9b5..244f6e4 100644 --- a/ConeCalorimeter/Services/ModbusRealtimeDataService.cs +++ b/ConeCalorimeter/Services/ModbusRealtimeDataService.cs @@ -54,6 +54,7 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService CurrentMass: ReadFloatOrEmpty(CurrentMassRegister), InitialMass: double.NaN, MassLoss: double.NaN, + MassLossRate: double.NaN, IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister), TestSeconds: ReadInt16OrEmpty(TestSecondsRegister), TotalSmoke: double.NaN);