This commit is contained in:
GukSang.Jin
2026-05-07 16:44:36 +08:00
parent 32f56a8710
commit 8a6458071a
4 changed files with 42 additions and 7 deletions

View File

@@ -22,10 +22,13 @@ public sealed record RealtimeDataRecord(
double CurrentMass, double CurrentMass,
double InitialMass, double InitialMass,
double MassLoss, double MassLoss,
double MassLossRate,
int IgnitionSeconds, int IgnitionSeconds,
int TestSeconds, int TestSeconds,
double TotalSmoke) double TotalSmoke)
{ {
private const double DefaultIrradiatedAreaSquareMeters = 0.01;
public static RealtimeDataRecord FromSnapshot(RealtimeSnapshot snapshot) public static RealtimeDataRecord FromSnapshot(RealtimeSnapshot snapshot)
{ {
return new RealtimeDataRecord( return new RealtimeDataRecord(
@@ -50,19 +53,17 @@ public sealed record RealtimeDataRecord(
snapshot.CurrentMass, snapshot.CurrentMass,
snapshot.InitialMass, snapshot.InitialMass,
snapshot.MassLoss, snapshot.MassLoss,
snapshot.MassLossRate,
snapshot.IgnitionSeconds, snapshot.IgnitionSeconds,
snapshot.TestSeconds, snapshot.TestSeconds,
snapshot.TotalSmoke); snapshot.TotalSmoke);
} }
public double MassLossRate =>
double.IsFinite(MassLoss) && TestSeconds > 0 ? MassLoss / TestSeconds : double.NaN;
public double HeatReleaseRateKw => public double HeatReleaseRateKw =>
double.IsFinite(HeatReleaseRate) ? HeatReleaseRate * 1000 : double.NaN; double.IsFinite(HeatReleaseRate) ? HeatReleaseRate : double.NaN;
public double EffectiveHeatOfCombustion => public double EffectiveHeatOfCombustion =>
double.IsFinite(HeatReleaseRate) && double.IsFinite(MassLossRate) && MassLossRate > 0 double.IsFinite(HeatReleaseRate) && double.IsFinite(MassLossRate) && MassLossRate > 0
? HeatReleaseRate / MassLossRate * 10 ? HeatReleaseRate * DefaultIrradiatedAreaSquareMeters / MassLossRate
: double.NaN; : double.NaN;
} }

View File

@@ -21,6 +21,7 @@ public sealed record RealtimeSnapshot(
double CurrentMass, double CurrentMass,
double InitialMass, double InitialMass,
double MassLoss, double MassLoss,
double MassLossRate,
int IgnitionSeconds, int IgnitionSeconds,
int TestSeconds, int TestSeconds,
double TotalSmoke); double TotalSmoke);

View File

@@ -12,6 +12,8 @@ public sealed class ExperimentDataService : IExperimentDataService
private readonly DispatcherTimer _timer; private readonly DispatcherTimer _timer;
private readonly DateTime _startedAt = DateTime.Now; private readonly DateTime _startedAt = DateTime.Now;
private double? _initialMass; private double? _initialMass;
private double? _previousMass;
private int? _previousMassSeconds;
private double _accumulatedTotalHeatRelease; private double _accumulatedTotalHeatRelease;
private double _accumulatedTotalSmoke; private double _accumulatedTotalSmoke;
private int? _lastAccumulationSeconds; private int? _lastAccumulationSeconds;
@@ -139,7 +141,8 @@ public sealed class ExperimentDataService : IExperimentDataService
return snapshot with return snapshot with
{ {
InitialMass = _initialMass ?? double.NaN, 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) var massLoss = _initialMass.HasValue && double.IsFinite(snapshot.CurrentMass)
? _initialMass.Value - snapshot.CurrentMass ? _initialMass.Value - snapshot.CurrentMass
: double.NaN; : double.NaN;
var massLossRate = CalculateMassLossRate(snapshot);
return snapshot with return snapshot with
{ {
InitialMass = _initialMass ?? double.NaN, 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() private void ResetComputedState()
{ {
_initialMass = null; _initialMass = null;
_previousMass = null;
_previousMassSeconds = null;
_accumulatedTotalHeatRelease = 0; _accumulatedTotalHeatRelease = 0;
_accumulatedTotalSmoke = 0; _accumulatedTotalSmoke = 0;
_lastAccumulationSeconds = null; _lastAccumulationSeconds = null;

View File

@@ -54,6 +54,7 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService
CurrentMass: ReadFloatOrEmpty(CurrentMassRegister), CurrentMass: ReadFloatOrEmpty(CurrentMassRegister),
InitialMass: double.NaN, InitialMass: double.NaN,
MassLoss: double.NaN, MassLoss: double.NaN,
MassLossRate: double.NaN,
IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister), IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister),
TestSeconds: ReadInt16OrEmpty(TestSecondsRegister), TestSeconds: ReadInt16OrEmpty(TestSecondsRegister),
TotalSmoke: double.NaN); TotalSmoke: double.NaN);