From e9fd33961c1d32de29807bf626f9dabcf0689369 Mon Sep 17 00:00:00 2001 From: Sang Woo Kim Date: Fri, 17 Jul 2026 00:37:59 +0900 Subject: [PATCH] NDPluginTimeSeries: divide the averaged sum before narrowing, not after doTimeSeriesT() stored an averaged time-series point as pTimeCircular[...] = (epicsType)averageStore_[signal]/numAveraged_; C++ precedence binds the cast tighter than the divide, so this evaluates as ((epicsType)averageStore_[signal]) / numAveraged_. averageStore_ is a double accumulator holding the SUM of numAveraged_ samples, so the sum is truncated (and, for integer element types, wrapped) to the narrow element type before the division ever happens. For any integer signal with averaging enabled (numAveraged_ > 1) this corrupts every averaged point once the running sum exceeds the element type's range: three UInt8 samples of 200 sum to 600, which narrows to (epicsUInt8)600 == 88, then 88 / 3 == 29 instead of 200. Parenthesize as (epicsType)(averageStore_[signal]/numAveraged_) so the double division runs at full precision and only the final average is narrowed. Float element types were already correct and are unchanged. Verified with a proof driver over the worked example: the old expression yields 29, the parenthesized expression yields 200. --- ADApp/pluginSrc/NDPluginTimeSeries.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ADApp/pluginSrc/NDPluginTimeSeries.cpp b/ADApp/pluginSrc/NDPluginTimeSeries.cpp index 83d6efee3..52d85e2be 100644 --- a/ADApp/pluginSrc/NDPluginTimeSeries.cpp +++ b/ADApp/pluginSrc/NDPluginTimeSeries.cpp @@ -188,7 +188,7 @@ asynStatus NDPluginTimeSeries::doAddToTimeSeriesT(NDArray *pArray) if (numAveraged_ < numAverage_) continue; /* We have now collected the desired number of points to average */ for (signal=0; signal