This commit is contained in:
GukSang.Jin
2026-05-05 16:31:40 +08:00
parent 8d485ddc76
commit 9559e61bf9
6 changed files with 54 additions and 19 deletions

View File

@@ -49,6 +49,14 @@ public sealed record RealtimeDataRecord(
snapshot.TotalSmoke);
}
public double MassLossRate =>
double.IsFinite(MassLoss) && TestSeconds > 0 ? MassLoss / TestSeconds : double.NaN;
public double HeatReleaseRateKw =>
double.IsFinite(HeatReleaseRate) ? HeatReleaseRate * 1000 : double.NaN;
public double EffectiveHeatOfCombustion =>
TotalHeatRelease <= 0 ? 0 : HeatReleaseRate / Math.Max(TotalHeatRelease, 1);
double.IsFinite(HeatReleaseRate) && double.IsFinite(MassLossRate) && MassLossRate > 0
? HeatReleaseRate / MassLossRate * 10
: double.NaN;
}

View File

@@ -11,6 +11,8 @@ public sealed class ExperimentDataService : IExperimentDataService
private readonly IRealtimeDataService _realtimeDataService;
private readonly DispatcherTimer _timer;
private readonly DateTime _startedAt = DateTime.Now;
private double _accumulatedTotalHeatRelease;
private double _accumulatedTotalSmoke;
public ExperimentDataService(IRealtimeDataService realtimeDataService)
{
@@ -38,18 +40,41 @@ public sealed class ExperimentDataService : IExperimentDataService
public void ClearRecords()
{
Records.Clear();
_accumulatedTotalHeatRelease = 0;
_accumulatedTotalSmoke = 0;
}
private void RecordSnapshot(RealtimeSnapshot snapshot)
{
CurrentSnapshot = snapshot;
Records.Add(RealtimeDataRecord.FromSnapshot(snapshot));
var accumulatedSnapshot = ApplyAccumulatedTotals(snapshot);
CurrentSnapshot = accumulatedSnapshot;
Records.Add(RealtimeDataRecord.FromSnapshot(accumulatedSnapshot));
while (Records.Count > MaximumRows)
{
Records.RemoveAt(0);
}
SnapshotUpdated?.Invoke(this, snapshot);
SnapshotUpdated?.Invoke(this, accumulatedSnapshot);
}
private RealtimeSnapshot ApplyAccumulatedTotals(RealtimeSnapshot snapshot)
{
if (double.IsFinite(snapshot.HeatReleaseRate))
{
_accumulatedTotalHeatRelease += snapshot.HeatReleaseRate;
}
if (double.IsFinite(snapshot.SmokeProduction))
{
_accumulatedTotalSmoke += snapshot.SmokeProduction;
}
return snapshot with
{
TotalHeatRelease = _accumulatedTotalHeatRelease,
TotalSmoke = _accumulatedTotalSmoke
};
}
}

View File

@@ -15,7 +15,6 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService
private const ushort HeatReleaseRateRegister = 354;
private const ushort Qa180Register = 366;
private const ushort Qa300Register = 370;
private const ushort TotalHeatReleaseRegister = 372;
private const ushort SmokeProductionRegister = 390;
private const ushort IgnitionSecondsRegister = 1014;
private const ushort TestSecondsRegister = 1015;
@@ -44,13 +43,13 @@ public sealed class ModbusRealtimeDataService : IRealtimeDataService
HeatReleaseRate: ReadFloatOrEmpty(HeatReleaseRateRegister),
Qa180: ReadFloatOrEmpty(Qa180Register),
Qa300: ReadFloatOrEmpty(Qa300Register),
TotalHeatRelease: ReadFloatOrEmpty(TotalHeatReleaseRegister),
TotalHeatRelease: double.NaN,
SmokeProduction: ReadFloatOrEmpty(SmokeProductionRegister),
CurrentMass: double.NaN,
MassLoss: double.NaN,
IgnitionSeconds: ReadInt16OrEmpty(IgnitionSecondsRegister),
TestSeconds: ReadInt16OrEmpty(TestSecondsRegister),
TotalSmoke: ReadFloatOrEmpty(SmokeProductionRegister));
TotalSmoke: double.NaN);
}
private double ReadFloatOrEmpty(ushort registerAddress)

View File

@@ -18,9 +18,9 @@ public sealed class NpoiReportExportService : IReportExportService
"CO (%)",
"孔板压差 (Pa)",
"孔板温度 (℃)",
"HRR50",
"HRR",
"THR (MJ/m2)",
"SPR50",
"SPR",
"TSR (m2)",
"MLR (g/s)",
"热释放KW/m2",
@@ -119,7 +119,7 @@ public sealed class NpoiReportExportService : IReportExportService
{
var row = sheet.CreateRow(i + 1);
var record = records[i];
SetNumeric(row, 0, record.TestSeconds);
SetNumeric(row, 0, record.TestSeconds >= 0 ? record.TestSeconds : double.NaN);
SetNumeric(row, 1, record.Oxygen);
SetNumeric(row, 2, record.CarbonDioxide);
SetNumeric(row, 3, record.CarbonMonoxide);
@@ -129,11 +129,11 @@ public sealed class NpoiReportExportService : IReportExportService
SetNumeric(row, 7, record.TotalHeatRelease);
SetNumeric(row, 8, record.SmokeProduction);
SetNumeric(row, 9, record.TotalSmoke);
SetNumeric(row, 10, record.MassLoss);
SetNumeric(row, 11, record.HeatReleaseRate);
SetNumeric(row, 10, record.MassLossRate);
SetNumeric(row, 11, record.HeatReleaseRateKw);
SetNumeric(row, 12, record.EffectiveHeatOfCombustion);
SetNumeric(row, 13, record.MassLoss);
SetNumeric(row, 14, record.ConeTemperature);
SetNumeric(row, 14, record.SampleTemperature);
}
for (var i = 0; i < DataHeaders.Length; i++)
@@ -223,7 +223,10 @@ public sealed class NpoiReportExportService : IReportExportService
private static void SetNumeric(IRow row, int columnIndex, double value)
{
row.CreateCell(columnIndex).SetCellValue(double.IsFinite(value) ? value : 0);
if (double.IsFinite(value))
{
row.CreateCell(columnIndex).SetCellValue(value);
}
}
private static string FindTemplatePath()
@@ -270,7 +273,7 @@ public sealed class NpoiReportExportService : IReportExportService
private static string FormatWithUnit(double? value, string unit)
{
return value is null ? "" : $"{value.Value:0.00} {unit}";
return value is null || !double.IsFinite(value.Value) ? "" : $"{value.Value:0.00} {unit}";
}
private static string FirstNonEmpty(params string[] values)

View File

@@ -21,8 +21,8 @@ public sealed class RealtimeDataRowViewModel
ThrText = Format(record.TotalHeatRelease);
Spr50Text = Format(record.SmokeProduction);
TsrText = Format(record.TotalSmoke);
MlrText = Format(record.MassLoss);
HeatReleaseText = Format(record.HeatReleaseRate);
MlrText = Format(record.MassLossRate);
HeatReleaseText = Format(record.HeatReleaseRateKw);
EhcText = Format(record.EffectiveHeatOfCombustion);
MassLossText = Format(record.MassLoss);
SampleTemperatureText = Format(record.SampleTemperature, "0.0");

View File

@@ -139,9 +139,9 @@
<DataGridTextColumn Header="CO (%)" Binding="{Binding CarbonMonoxideText}" Width="82" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="孔板压差 (Pa)" Binding="{Binding OrificePressureText}" Width="116" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="孔板温度 (℃)" Binding="{Binding OrificeTemperatureText}" Width="116" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="HRR50" Binding="{Binding Hrr50Text}" Width="78" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="HRR" Binding="{Binding Hrr50Text}" Width="78" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="THR (MJ/m2)" Binding="{Binding ThrText}" Width="108" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="SPR50" Binding="{Binding Spr50Text}" Width="78" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="SPR" Binding="{Binding Spr50Text}" Width="78" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="TSR (m2)" Binding="{Binding TsrText}" Width="88" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="MLR (g/s)" Binding="{Binding MlrText}" Width="92" ElementStyle="{StaticResource RealtimeTextElementStyle}" />
<DataGridTextColumn Header="热释放KW/m2" Binding="{Binding HeatReleaseText}" Width="122" ElementStyle="{StaticResource RealtimeTextElementStyle}" />