Skip to content

Fix incorrenct indexing#391

Merged
jniebuhr merged 4 commits intojniebuhr:masterfrom
spsancti:fix/auto-adjust
Dec 10, 2025
Merged

Fix incorrenct indexing#391
jniebuhr merged 4 commits intojniebuhr:masterfrom
spsancti:fix/auto-adjust

Conversation

@spsancti
Copy link
Contributor

@spsancti spsancti commented Aug 27, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Improved stability of predictive rate calculations by fixing boundary handling and indexing.
    • Prevented divide-by-zero and underflow when data is sparse or degenerate.
    • Returns safe defaults for invalid or degenerate inputs to avoid erratic values.
    • Made overshoot adjustment more robust when computed rates are extremely low or invalid, with safer fallbacks.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

Walkthrough

Implements defensive fixes and indexing corrections in src/display/core/predictive.h. getRate adds a cutoff boundary check, corrects accumulation loop indexing, guards against tiny variance and non-positive slopes, and returns 0.0 for degenerate cases. getOvershootAdjustMillis caches rate and avoids division by near-zero. No API changes.

Changes

Cohort / File(s) Summary
Predictive rate and overshoot safeguards
src/display/core/predictive.h
getRate: add cutoff boundary check (i > 0), fix accumulation loop to use j, guard against tiny tdev2 (< 1e-10) and non-positive computed volume, return 0.0 for degenerate cases. getOvershootAdjustMillis: cache local rate, return 0.0 if rate < 1e-10, validate adjust (NaN/inf/negative) and log invalid results. No signature/API changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Files to inspect closely:
    • src/display/core/predictive.h — verify loop bounds, index usage, numeric thresholds, and logging behavior.
    • Areas where callers rely on non-zero rates or negative return semantics to ensure behavior remains safe.

Poem

I nibble numbers, whiskers all a-twitch,
Tightened the loops and fixed the glitch.
Tiny variances now gently stall,
No divide-by-zero, I guard them all.
Carrot-coded calm across the hilltop switch. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix incorrenct indexing' is directly related to the main changes: correcting indexing in the getRate accumulation loop (using j instead of i) and adding boundary checks. However, the title contains a typo ('incorrenct' instead of 'incorrect') and doesn't capture the broader scope of defensive improvements including division-by-zero guards and validation checks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/display/core/predictive.h (1)

4-5: Include what you use.

This header uses std::vector and std::pow but doesn’t include their headers. Avoid relying on transitive includes.

 #include <Arduino.h>
+#include <vector>
+#include <cmath>
🧹 Nitpick comments (4)
src/display/core/predictive.h (4)

45-47: Indexing fix is correct; avoid pow in the hot loop.

Use precomputed deltas and multiplication to reduce floating-point overhead on MCU targets.

-            tdev_vdev += (measurementTimes[j] - t_mean) * (measurements[j] - v_mean);
-            tdev2 += pow(measurementTimes[j] - t_mean, 2.0);
+            const double dt = measurementTimes[j] - t_mean;
+            const double dv = measurements[j] - v_mean;
+            tdev_vdev += dt * dv;
+            tdev2 += dt * dt;

48-53: Near-zero denominator guard is good; name the threshold.

Minor: give the magic number a name for readability and easier tuning.

-        // Prevent division by zero
-        if (tdev2 < 1e-10) {
+        // Prevent division by near-zero denominator (units: ms^2)
+        constexpr double kTdev2Epsilon = 1e-10;
+        if (tdev2 < kTdev2Epsilon) {
             return 0.0;
         }

54-56: Comment mismatch on units.

The code returns volume/ms; the comment suggests seconds. Align the comment to avoid confusion.

-        double volumePerMilliSecond = tdev_vdev / tdev2;              // the slope (volume per millisecond) of the linear best fit
-        return volumePerMilliSecond > 0 ? volumePerMilliSecond : 0.0; // return 0 if it is not positive, convert to seconds
+        double volumePerMilliSecond = tdev_vdev / tdev2;              // slope (volume per millisecond) of the linear best fit
+        return volumePerMilliSecond > 0 ? volumePerMilliSecond : 0.0; // return 0 if it is not positive (units: volume/ms)

62-70: Division-by-zero guard is correct; clarify negative overshoot behavior.

If actual < expected, result is negative ms. Is that intended? Consider clamping to 0 for “overshoot” semantics.

         double rate = getRate(measurementTimes.back());
         
         // Prevent division by zero
         if (rate < 1e-10) {
             return 0.0;
         }
-        
-        return overshoot / rate;
+        // If actual <= expected, there is no overshoot to adjust.
+        if (overshoot <= 0.0) {
+            return 0.0;
+        }
+        return overshoot / rate;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f62c2e5 and 895f02e.

📒 Files selected for processing (1)
  • src/display/core/predictive.h (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: deploy
  • GitHub Check: test
🔇 Additional comments (1)
src/display/core/predictive.h (1)

25-27: Good underflow safeguard in cutoff scan.

The added i > 0 guard prevents size_t wraparound and out-of-bounds access when the window excludes all points. LGTM.

@cla-bot cla-bot bot added the cla-signed label Dec 10, 2025
@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/display/core/predictive.h (2)

42-53: Indexing fix and tdev2 guard look good; consider tiny micro-optimization

Using j consistently in the accumulation loop fixes the earlier indexing bug, and the tdev2 < 1e-10 guard avoids division by (near) zero in degenerate cases, which is the right defensive behavior here.

If you care about tight performance on MCU targets, you could avoid pow and reuse the time delta:

-        for (size_t j = i; j < measurements.size(); j++) {
-            tdev_vdev += (measurementTimes[j] - t_mean) * (measurements[j] - v_mean);
-            tdev2 += pow(measurementTimes[j] - t_mean, 2.0);
-        }
+        for (size_t j = i; j < measurements.size(); j++) {
+            const double dt = measurementTimes[j] - t_mean;
+            tdev_vdev += dt * (measurements[j] - v_mean);
+            tdev2 += dt * dt;
+        }

Purely optional, but a bit lighter than pow in a tight loop.


57-79: Robust overshoot adjustment; confirm undershoot behavior and header dependencies

The new early return on measurementTimes.size() < 2, the cached rate, and guards on rate and adjust (including NaN/Inf and negativity) make this method much safer against bad data and arithmetic issues.

Two points to double‑check:

  1. Undershoot semantics: When actualVolume < expectedVolume, overshoot becomes negative, adjust becomes negative, and you now treat that as invalid and return 0.0 (with a warning). If the intended behavior is “only correct positive overshoot”, this is fine; if you ever want to compensate undershoot (e.g., extend run time), you’ll need a separate code path instead of discarding it.

  2. Logging / math dependencies: This header now relies on ESP_LOGW, isnan, and isinf. Please ensure every translation unit including predictive.h has the appropriate logging and math headers included (or include them here) so the header remains self‑contained and consistently compilable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce01772 and 0453f6b.

📒 Files selected for processing (1)
  • src/display/core/predictive.h (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: deploy
  • GitHub Check: test
🔇 Additional comments (1)
src/display/core/predictive.h (1)

23-31: Boundary check in cutoff loop correctly prevents underflow/OOB access

Adding i > 0 to the loop condition makes the backward scan safe when all timestamps are newer than cutoff, and the subsequent measurements.size() - i < 2 guard ensures you only fit when there are at least two in-window points. The window selection logic still matches the comment about “first entry after the cutoff”.

@jniebuhr jniebuhr merged commit 6328186 into jniebuhr:master Dec 10, 2025
6 of 7 checks passed
DevNullGamer pushed a commit that referenced this pull request Dec 12, 2025
* Fix incorrenct indexing

* fix

* Added checks for invalid rate and adjustment values, logging warnings when encountered.

---------

Co-authored-by: Jochen Niebuhr <kontakt@ju-hh.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants