This commit is contained in:
GukSang.Jin
2026-05-05 17:41:46 +08:00
parent 9559e61bf9
commit 6a57776f96
4 changed files with 91 additions and 4 deletions

View File

@@ -11,8 +11,10 @@ public sealed class ExperimentDataService : IExperimentDataService
private readonly IRealtimeDataService _realtimeDataService; private readonly IRealtimeDataService _realtimeDataService;
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 _accumulatedTotalHeatRelease; private double _accumulatedTotalHeatRelease;
private double _accumulatedTotalSmoke; private double _accumulatedTotalSmoke;
private bool _isTestRunning;
public ExperimentDataService(IRealtimeDataService realtimeDataService) public ExperimentDataService(IRealtimeDataService realtimeDataService)
{ {
@@ -37,16 +39,34 @@ public sealed class ExperimentDataService : IExperimentDataService
public event EventHandler<RealtimeSnapshot>? SnapshotUpdated; 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() public void ClearRecords()
{ {
Records.Clear(); Records.Clear();
_accumulatedTotalHeatRelease = 0; ResetComputedState();
_accumulatedTotalSmoke = 0;
} }
private void RecordSnapshot(RealtimeSnapshot snapshot) private void RecordSnapshot(RealtimeSnapshot snapshot)
{ {
var accumulatedSnapshot = ApplyAccumulatedTotals(snapshot); var massSnapshot = ApplyMassLoss(snapshot);
var accumulatedSnapshot = ApplyAccumulatedTotals(massSnapshot);
CurrentSnapshot = accumulatedSnapshot; CurrentSnapshot = accumulatedSnapshot;
Records.Add(RealtimeDataRecord.FromSnapshot(accumulatedSnapshot)); Records.Add(RealtimeDataRecord.FromSnapshot(accumulatedSnapshot));
@@ -61,6 +81,15 @@ public sealed class ExperimentDataService : IExperimentDataService
private RealtimeSnapshot ApplyAccumulatedTotals(RealtimeSnapshot snapshot) private RealtimeSnapshot ApplyAccumulatedTotals(RealtimeSnapshot snapshot)
{ {
if (!_isTestRunning)
{
return snapshot with
{
TotalHeatRelease = double.NaN,
TotalSmoke = double.NaN
};
}
if (double.IsFinite(snapshot.HeatReleaseRate)) if (double.IsFinite(snapshot.HeatReleaseRate))
{ {
_accumulatedTotalHeatRelease += snapshot.HeatReleaseRate; _accumulatedTotalHeatRelease += snapshot.HeatReleaseRate;
@@ -77,4 +106,36 @@ public sealed class ExperimentDataService : IExperimentDataService
TotalSmoke = _accumulatedTotalSmoke 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;
}
} }

View File

@@ -11,5 +11,9 @@ public interface IExperimentDataService
event EventHandler<RealtimeSnapshot>? SnapshotUpdated; event EventHandler<RealtimeSnapshot>? SnapshotUpdated;
void StartTest();
void StopTest();
void ClearRecords(); void ClearRecords();
} }

View File

@@ -4,6 +4,7 @@ namespace ConeCalorimeter.Services;
public sealed class ModbusRealtimeDataService : IRealtimeDataService public sealed class ModbusRealtimeDataService : IRealtimeDataService
{ {
private const ushort CurrentMassRegister = 1;
private const ushort OxygenRegister = 10; private const ushort OxygenRegister = 10;
private const ushort OrificeFlowRegister = 14; private const ushort OrificeFlowRegister = 14;
private const ushort OrificePressureRegister = 16; private const ushort OrificePressureRegister = 16;
@@ -45,7 +46,7 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService
Qa300: ReadFloatOrEmpty(Qa300Register), Qa300: ReadFloatOrEmpty(Qa300Register),
TotalHeatRelease: double.NaN, TotalHeatRelease: double.NaN,
SmokeProduction: ReadFloatOrEmpty(SmokeProductionRegister), SmokeProduction: ReadFloatOrEmpty(SmokeProductionRegister),
CurrentMass: double.NaN, CurrentMass: ReadFloatOrEmpty(CurrentMassRegister),
MassLoss: double.NaN, MassLoss: double.NaN,
IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister), IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister),
TestSeconds: ReadInt16OrEmpty(TestSecondsRegister), TestSeconds: ReadInt16OrEmpty(TestSecondsRegister),

View File

@@ -254,6 +254,16 @@ public sealed class TestPageViewModel : PageViewModel
LastAction = action; LastAction = action;
if (action == "测试开始")
{
_experimentDataService.StartTest();
ClearPlotSeries();
}
else if (action == "测试结束")
{
_experimentDataService.StopTest();
}
if (!TryGetDeviceActionCoil(action, out var coilAddress, out var value)) if (!TryGetDeviceActionCoil(action, out var coilAddress, out var value))
{ {
return; return;
@@ -265,6 +275,17 @@ public sealed class TestPageViewModel : PageViewModel
} }
} }
private void ClearPlotSeries()
{
_heatReleaseSeries.Points.Clear();
_totalHeatSeries.Points.Clear();
_totalSmokeSeries.Points.Clear();
var bottomAxis = HeatReleasePlot.Axes.First(axis => axis.Position == AxisPosition.Bottom);
bottomAxis.Maximum = 300;
HeatReleasePlot.InvalidatePlot(true);
}
private static bool TryGetDeviceActionCoil(string action, out ushort coilAddress, out bool value) private static bool TryGetDeviceActionCoil(string action, out ushort coilAddress, out bool value)
{ {
value = true; value = true;