169 lines
4.6 KiB
C#
169 lines
4.6 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Windows.Threading;
|
|
using ConeCalorimeter.Models;
|
|
|
|
namespace ConeCalorimeter.Services;
|
|
|
|
public sealed class ExperimentDataService : IExperimentDataService
|
|
{
|
|
private const int MaximumRows = 1200;
|
|
|
|
private readonly IRealtimeDataService _realtimeDataService;
|
|
private readonly DispatcherTimer _timer;
|
|
private readonly DateTime _startedAt = DateTime.Now;
|
|
private double? _initialMass;
|
|
private double _accumulatedTotalHeatRelease;
|
|
private double _accumulatedTotalSmoke;
|
|
private int? _lastAccumulationSeconds;
|
|
private bool _isTestRunning;
|
|
|
|
public ExperimentDataService(IRealtimeDataService realtimeDataService)
|
|
{
|
|
_realtimeDataService = realtimeDataService;
|
|
Records = [];
|
|
CurrentSnapshot = _realtimeDataService.GetCurrentSnapshot(TimeSpan.Zero);
|
|
|
|
RecordSnapshot(CurrentSnapshot);
|
|
|
|
_timer = new DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
};
|
|
_timer.Tick += (_, _) => RecordSnapshot(
|
|
_realtimeDataService.GetCurrentSnapshot(DateTime.Now - _startedAt));
|
|
_timer.Start();
|
|
}
|
|
|
|
public ObservableCollection<RealtimeDataRecord> Records { get; }
|
|
|
|
public RealtimeSnapshot CurrentSnapshot { get; private set; }
|
|
|
|
public event EventHandler<RealtimeSnapshot>? SnapshotUpdated;
|
|
|
|
public void StartTest()
|
|
{
|
|
Records.Clear();
|
|
ResetComputedState();
|
|
_isTestRunning = true;
|
|
|
|
if (double.IsFinite(CurrentSnapshot.CurrentMass))
|
|
{
|
|
_initialMass = CurrentSnapshot.CurrentMass;
|
|
}
|
|
}
|
|
|
|
public void StopTest()
|
|
{
|
|
_isTestRunning = false;
|
|
_initialMass = null;
|
|
}
|
|
|
|
public void ClearRecords()
|
|
{
|
|
Records.Clear();
|
|
ResetComputedState();
|
|
}
|
|
|
|
private void RecordSnapshot(RealtimeSnapshot snapshot)
|
|
{
|
|
var massSnapshot = ApplyMassLoss(snapshot);
|
|
var accumulatedSnapshot = ApplyAccumulatedTotals(massSnapshot);
|
|
|
|
CurrentSnapshot = accumulatedSnapshot;
|
|
Records.Add(RealtimeDataRecord.FromSnapshot(accumulatedSnapshot));
|
|
|
|
while (Records.Count > MaximumRows)
|
|
{
|
|
Records.RemoveAt(0);
|
|
}
|
|
|
|
SnapshotUpdated?.Invoke(this, accumulatedSnapshot);
|
|
}
|
|
|
|
private RealtimeSnapshot ApplyAccumulatedTotals(RealtimeSnapshot snapshot)
|
|
{
|
|
if (!_isTestRunning)
|
|
{
|
|
return snapshot with
|
|
{
|
|
TotalHeatRelease = double.NaN,
|
|
TotalSmoke = double.NaN
|
|
};
|
|
}
|
|
|
|
if (snapshot.TestSeconds < 0)
|
|
{
|
|
return snapshot with
|
|
{
|
|
TotalHeatRelease = _accumulatedTotalHeatRelease,
|
|
TotalSmoke = _accumulatedTotalSmoke
|
|
};
|
|
}
|
|
|
|
if (!_lastAccumulationSeconds.HasValue)
|
|
{
|
|
_lastAccumulationSeconds = snapshot.TestSeconds;
|
|
return snapshot with
|
|
{
|
|
TotalHeatRelease = _accumulatedTotalHeatRelease,
|
|
TotalSmoke = _accumulatedTotalSmoke
|
|
};
|
|
}
|
|
|
|
var deltaSeconds = snapshot.TestSeconds - _lastAccumulationSeconds.Value;
|
|
if (deltaSeconds > 0)
|
|
{
|
|
if (double.IsFinite(snapshot.HeatReleaseRate))
|
|
{
|
|
_accumulatedTotalHeatRelease += snapshot.HeatReleaseRate * deltaSeconds;
|
|
}
|
|
|
|
if (double.IsFinite(snapshot.SmokeProduction))
|
|
{
|
|
_accumulatedTotalSmoke += snapshot.SmokeProduction * deltaSeconds;
|
|
}
|
|
|
|
_lastAccumulationSeconds = snapshot.TestSeconds;
|
|
}
|
|
|
|
return snapshot with
|
|
{
|
|
TotalHeatRelease = _accumulatedTotalHeatRelease,
|
|
TotalSmoke = _accumulatedTotalSmoke
|
|
};
|
|
}
|
|
|
|
private RealtimeSnapshot ApplyMassLoss(RealtimeSnapshot snapshot)
|
|
{
|
|
if (!_isTestRunning)
|
|
{
|
|
return snapshot with
|
|
{
|
|
MassLoss = double.NaN
|
|
};
|
|
}
|
|
|
|
if (!_initialMass.HasValue && double.IsFinite(snapshot.CurrentMass))
|
|
{
|
|
_initialMass = snapshot.CurrentMass;
|
|
}
|
|
|
|
var massLoss = _initialMass.HasValue && double.IsFinite(snapshot.CurrentMass)
|
|
? _initialMass.Value - snapshot.CurrentMass
|
|
: double.NaN;
|
|
|
|
return snapshot with
|
|
{
|
|
MassLoss = massLoss
|
|
};
|
|
}
|
|
|
|
private void ResetComputedState()
|
|
{
|
|
_initialMass = null;
|
|
_accumulatedTotalHeatRelease = 0;
|
|
_accumulatedTotalSmoke = 0;
|
|
_lastAccumulationSeconds = null;
|
|
}
|
|
}
|