From d9775b48bef8bc0792dbcdb520f6e642b3cdc0e8 Mon Sep 17 00:00:00 2001 From: LucianoDev Date: Mon, 20 Apr 2026 21:42:30 +0200 Subject: [PATCH] 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 --- Infrastructure/Pcan/PcanAdapter.cs | 48 +++++++++++++++++-- Services/Impl/BenchService.cs | 9 ++-- ViewModels/MainViewModel.cs | 12 ++++- ViewModels/PumpControlViewModel.cs | 2 +- ViewModels/SingleFlowChartViewModel.cs | 3 +- Views/Pages/PumpPage.xaml | 8 ++-- Views/UserControls/PumpCommandsCard.xaml | 32 ++++++------- .../UserControls/PumpIdentificationCard.xaml | 5 -- 8 files changed, 80 insertions(+), 39 deletions(-) diff --git a/Infrastructure/Pcan/PcanAdapter.cs b/Infrastructure/Pcan/PcanAdapter.cs index 097e601..a77b77a 100644 --- a/Infrastructure/Pcan/PcanAdapter.cs +++ b/Infrastructure/Pcan/PcanAdapter.cs @@ -44,6 +44,15 @@ namespace HC_APTBS.Infrastructure.Pcan private Dictionary> _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. diff --git a/Services/Impl/BenchService.cs b/Services/Impl/BenchService.cs index c25cd6c..38496f2 100644 --- a/Services/Impl/BenchService.cs +++ b/Services/Impl/BenchService.cs @@ -754,13 +754,10 @@ namespace HC_APTBS.Services.Impl } } - // Notify chart view of expected tolerance bands. + // Notify chart view of expected tolerance bands for every receive. + // The UI layer routes to the appropriate chart by parameter name. foreach (var recv in phase.Receives) - { - if (recv.Name == BenchParameterNames.QDelivery || - recv.Name == BenchParameterNames.QOver) - ToleranceUpdated?.Invoke(recv.Name, recv.Value, recv.Tolerance); - } + ToleranceUpdated?.Invoke(recv.Name, recv.Value, recv.Tolerance); // ── Step 4: Conditioning time countdown ─────────────────────────── sw.Stop(); diff --git a/ViewModels/MainViewModel.cs b/ViewModels/MainViewModel.cs index 2b8ec9c..6a6545c 100644 --- a/ViewModels/MainViewModel.cs +++ b/ViewModels/MainViewModel.cs @@ -252,6 +252,8 @@ namespace HC_APTBS.ViewModels // Clear real-time plot traces at each new phase boundary. FlowmeterChart.Delivery.Clear(); FlowmeterChart.Over.Clear(); + BenchPage.PressureTrace.P1.Clear(); + BenchPage.PressureTrace.P2.Clear(); }); _bench.PhaseTimerTick += (section, remaining, total) => App.Current.Dispatcher.Invoke( () => TestPanel.ApplyPhaseTimerTick(section, remaining, total)); @@ -269,6 +271,10 @@ namespace HC_APTBS.ViewModels { TestPanel.UpdateLiveIndicator(paramName, value); FlowmeterChart.SetTolerance(paramName, value, tolerance); + if (paramName == BenchParameterNames.Pressure) + BenchPage.PressureTrace.P1.SetTolerance(value, tolerance); + else if (paramName == BenchParameterNames.AnalogSensor2) + BenchPage.PressureTrace.P2.SetTolerance(value, tolerance); }); _bench.MeasurementSampled += (name, value) => App.Current.Dispatcher.Invoke(() => @@ -277,6 +283,10 @@ namespace HC_APTBS.ViewModels FlowmeterChart.Delivery.AddValue(value); else if (name == BenchParameterNames.QOver) FlowmeterChart.Over.AddValue(value); + else if (name == BenchParameterNames.Pressure) + BenchPage.PressureTrace.P1.AddValue(value); + else if (name == BenchParameterNames.AnalogSensor2) + BenchPage.PressureTrace.P2.AddValue(value); }); _bench.EmergencyStopTriggered += reason => App.Current.Dispatcher.Invoke(() => { @@ -329,7 +339,7 @@ namespace HC_APTBS.ViewModels _can.RegisterPumpMessageIds(GetReceiveMessageIds(pump.ParametersById)); // Configure pump control sliders. - PumpControl.IsPreInVisible = pump.HasPreInjection; + PumpControl.IsPreInAvailable = pump.HasPreInjection; PumpControl.IsEnabled = true; PumpControl.Reset(); diff --git a/ViewModels/PumpControlViewModel.cs b/ViewModels/PumpControlViewModel.cs index 97eb8c8..5b6b47a 100644 --- a/ViewModels/PumpControlViewModel.cs +++ b/ViewModels/PumpControlViewModel.cs @@ -64,7 +64,7 @@ namespace HC_APTBS.ViewModels // ── Visibility / enablement ─────────────────────────────────────────────── /// True when the current pump supports pre-injection. - [ObservableProperty] private bool _isPreInVisible; + [ObservableProperty] private bool _isPreInAvailable; /// True when a pump is selected and CAN is connected. [ObservableProperty] private bool _isEnabled; diff --git a/ViewModels/SingleFlowChartViewModel.cs b/ViewModels/SingleFlowChartViewModel.cs index 1fdb4c5..e2b7701 100644 --- a/ViewModels/SingleFlowChartViewModel.cs +++ b/ViewModels/SingleFlowChartViewModel.cs @@ -79,7 +79,8 @@ namespace HC_APTBS.ViewModels new Axis { AnimationsSpeed = TimeSpan.Zero, - MinLimit = 0 + MinLimit = 0, + SeparatorsPaint = new SolidColorPaint(new SKColor(224, 224, 224), 0.75f) } }; } diff --git a/Views/Pages/PumpPage.xaml b/Views/Pages/PumpPage.xaml index a5fddd3..32f3aaa 100644 --- a/Views/Pages/PumpPage.xaml +++ b/Views/Pages/PumpPage.xaml @@ -32,12 +32,12 @@ - + - + @@ -48,10 +48,10 @@ - + - + diff --git a/Views/UserControls/PumpCommandsCard.xaml b/Views/UserControls/PumpCommandsCard.xaml index 46c6bc9..da180bc 100644 --- a/Views/UserControls/PumpCommandsCard.xaml +++ b/Views/UserControls/PumpCommandsCard.xaml @@ -10,8 +10,6 @@ - -