feat: chart grid, pressure tolerance bands, QDelivery RPM normalization, pump page polish

Charts
- Add faint background grid (0.75px, #E0E0E0) to all live charts; matches PDF report style
- Show min/max tolerance bands on P1/P2 pressure charts during test runs (previously only Q-Delivery/Q-Over)
- Broaden BenchService.ToleranceUpdated to fire for every phase receive; UI routes by name
- Clear P1/P2 traces on PhaseChanged alongside Delivery/Over

CAN
- Normalize QDelivery flow rate to 1000 RPM reference before IIR filter so RPM spikes are low-pass filtered with flow-rate transients (matches old_source behavior)

Pump page
- Reorder columns: identification left, commands center, live data right
- PreIn control always visible; disabled when pump lacks pre-injection (rename IsPreInVisible -> IsPreInAvailable)
- Swap value/label order in command cards
- Remove redundant KlineErrors row from identification card

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 21:42:30 +02:00
parent 69bfda54e1
commit d9775b48be
8 changed files with 80 additions and 39 deletions

View File

@@ -44,6 +44,15 @@ namespace HC_APTBS.Infrastructure.Pcan
private Dictionary<uint, List<CanBusParameter>> _parameterMap = new();
private readonly object _mapLock = new();
// Cached reference to the bench RPM parameter, re-resolved on every SetParameters /
// AddParameters call. Used to normalize QDelivery (flow rate) against shaft speed
// before the IIR low-pass filter runs, so that RPM spikes are filtered alongside
// flow-rate transients rather than bleeding into the displayed value unfiltered.
// Matches old_source behavior (Herlic2.0/MainWindow.xaml.cs:656, 1874).
private CanBusParameter? _benchRpmParam;
private const double QDeliveryReferenceRpm = 1000.0;
private const double QDeliveryMinRpm = 1.0;
private Thread? _readThread;
private AutoResetEvent? _receiveEvent;
private volatile bool _stopRead = true;
@@ -228,6 +237,7 @@ namespace HC_APTBS.Infrastructure.Pcan
lock (_mapLock)
{
_parameterMap = parameters;
ResolveBenchRpmParam();
}
}
@@ -241,6 +251,24 @@ namespace HC_APTBS.Infrastructure.Pcan
if (!_parameterMap.ContainsKey(kv.Key))
_parameterMap.Add(kv.Key, kv.Value);
}
ResolveBenchRpmParam();
}
}
// Call under _mapLock.
private void ResolveBenchRpmParam()
{
_benchRpmParam = null;
foreach (var list in _parameterMap.Values)
{
foreach (var p in list)
{
if (p.Name == BenchParameterNames.BenchRpm)
{
_benchRpmParam = p;
return;
}
}
}
}
@@ -508,15 +536,27 @@ namespace HC_APTBS.Infrastructure.Pcan
}
// Spike rejection for QDelivery: discard values that are more than
// 100x the previous reading (caused by relay switching noise).
// 100x the previous raw reading (caused by relay switching noise).
// Compare against the previous raw-normalized value below.
if (param.Name == BenchParameterNames.QDelivery)
{
if (previousValue > 0.1 && param.Value > previousValue * 100)
// Normalize raw flow rate to a 1000 RPM reference BEFORE filtering,
// so that RPM spikes are low-pass filtered together with flow-rate
// transients rather than appearing as instantaneous jumps in the
// normalized output.
double rpm = _benchRpmParam?.Value ?? 0;
double normalized = rpm < QDeliveryMinRpm
? 0
: param.Value * (QDeliveryReferenceRpm / rpm);
if (previousValue > 0.1 && normalized > previousValue * 100)
{
_log.Warning(LogId,
$"QDelivery spike suppressed: prev={previousValue:F3}, new={param.Value:F3}");
param.Value = previousValue;
$"QDelivery spike suppressed: prev={previousValue:F3}, new={normalized:F3}");
normalized = previousValue;
}
param.Value = normalized;
}
// Apply single-pole IIR low-pass filter.