# ScopeDOPE Ballistics Engine — Accuracy Analysis

**Date:** 2026-05-29
**Based on:** Exhaustive C(N,k) validation run, 22 test cases, 467–8099 combinations per case
**Engine:** `:ballistics` KMP module — `BallisticsEngine.kt` v0.9.3-beta
**Primary verdict:** INVESTIGATE (k=1 interior LOO)
**Audience:** Engine developer — actionable findings only

---

## 1. Summary of Findings

Three distinct accuracy problems are present. They are independent, have different root causes, and require different fixes. Listed by priority:

| # | Finding | Affected loads | Max error | Priority |
|---|---|---|---|---|
| 1 | Systematic G7 physics under-prediction growing with range | All G7 centerfire | ~0.65–1.05 mil at 1000yd | **High** |
| 2 | G1 subsonic physics over-prediction | .22 LR | ~1.25–1.91 mil at 200yd | **Medium** |
| 3 | DOPE spline degrades at near-boundary interior points | .308 Win, .300 WM, 6.5 PRC | ~0.03–0.05 mil at max range | **Low** |

Finding 3 is a consequence of Finding 1 — fix 1 and 3 narrows significantly. Findings 1 and 2 are independent.

The engine is **architecturally sound**. The Tier 3 fired-impact result (.17 HMR, 3 confirmed field shots) passes with mean |Δ DOPE| = 0.063 mil. The DOPE correction system successfully compensates for physics error when training data is present. The problems identified here affect the quality of predictions when operating at or beyond the DOPE training range.

---

## 2. Finding 1 — Systematic G7 Under-prediction at Long Range

### 2.1 Evidence

The engine consistently predicts **less drop** than the ShootersCalculator reference at the same G7 BC, MV, and conditions. Error is near-zero at 200 yd and grows monotonically with distance:

| Dist (yd) | 65CM Hornady ELD-M | 65CM Berger Hybrid | 65CM Federal SMK | 308 Fed 168gr SMK | 6mm CM Hornady |
|---|---|---|---|---|---|
| 200 | −0.002 mil | −0.026 mil | −0.027 mil | −0.007 mil | −0.022 mil |
| 400 | −0.045 | −0.134 | −0.111 | −0.031 | −0.095 |
| 600 | −0.147 | −0.304 | −0.237 | −0.114 | −0.252 |
| 800 | −0.339 | −0.599 | −0.419 | −0.286 | −0.522 |
| 1000 | −0.653 | −1.042 | −0.663 | −0.651 | −0.992 |

Negative Δ = engine predicts less drop = reference shows bullet drops **more** than engine computes.

The error is:
- **Monotonically increasing** with distance — classic integration accumulation signature
- **Present across all G7 cases** regardless of caliber, BC value, or MV — rules out a case-specific data error
- **Proportional to flight time** more than to BC — loads with lower BC (more drag) show larger absolute error at the same distance
- **Zero at short range** — rules out a constant offset or zeroing error

### 2.2 Magnitude by BC

| G7 BC | Load | Error at 1000yd |
|---|---|---|
| 0.333 | 6.5 PRC 147gr ELD-M | ~−0.75 mil |
| 0.326 | 6.5 CM Hornady 140gr ELD-M | −0.653 mil |
| 0.311 | 6.5 CM Berger 140gr Hybrid | −1.042 mil |
| 0.278 | 6mm CM Berger 105gr | ~−0.94 mil |
| 0.270 | 6mm CM Hornady 108gr ELD-M | −0.992 mil |
| 0.263 | .308 Hornady 168gr ELD-M | ~−1.21 mil |
| 0.253 | 6.5 CM Federal 140gr SMK | −0.663 mil |
| 0.243 | .308 Federal 175gr SMK | ~−2.3 mil* |
| 0.224 | .308 Federal 168gr SMK | −0.651 mil |

*308_fed175_smk runs at 3200 ft altitude vs sea-level reference — the −2.3 mil includes the altitude correction delta and cannot be directly compared.

Lower G7 BC → more drag → longer flight time → more integration accumulation → larger absolute error. This is consistent with an under-estimated drag force that compounds over time.

### 2.3 Root Cause Hypotheses

**Hypothesis A — Single-point BC across all velocities (most likely)**

The engine uses a single BC value for the entire trajectory. Real bullets have velocity-dependent drag. As a bullet decelerates from 2700 fps to ~1500 fps at 1000yd, its effective G7 BC changes. Manufacturers typically publish a single mid-range BC value. At the lower velocities encountered at long range, the actual drag is often higher than the single BC predicts. This would cause the engine to under-predict drag at long range — exactly the pattern observed.

Bryan Litz's Applied Ballistics measured BCs at multiple velocity zones. For example, a bullet with a manufacturer-stated G7 BC of 0.326 might measure 0.318 at Mach 1.5 and 0.301 at Mach 1.2. Using 0.326 at all velocities would predict a flatter trajectory than reality at long range.

**Hypothesis B — G7 CD table values slightly low at Mach 1.2–2.0**

The G7_CD table is sourced from McCoy (public domain) and cross-referenced with JBM. If ShootersCalculator uses a slightly different G7 reference table, this would cause a systematic divergence. JBM and Applied Ballistics are documented to agree within 0.003 mil at 1000yd; if our table matches JBM's table, the disagreement is with ShootersCalculator's table, not a bug. This hypothesis requires direct G7 table comparison to resolve.

**Hypothesis C — Fritsch-Carlson CD interpolation vs piecewise linear**

The engine uses monotone cubic Hermite interpolation for the CD curve. Most point-mass solvers use piecewise linear interpolation between table entries. Near inflection points (e.g., post-transonic peak at Mach 1.075), the cubic tangent-smoothing may produce slightly lower Cd values than linear interpolation between the same table entries, resulting in less drag being applied.

**Hypothesis D — RK4 spatial step size (unlikely)**

At 0.5-yard steps, RK4 error per step is O(h^5) ≈ negligible. A 4× step reduction to 0.125 yd would reduce integration error by 1024×. This is not consistent with the observed magnitude (0.65 mil at 1000yd would require much larger step error). Low probability.

### 2.4 Test Protocol

To distinguish hypotheses:

1. **Compare against JBM** (not ShootersCalculator) at identical inputs for 65cm_hornady_eldm. If our engine matches JBM within 0.01 mil, the issue is ShootersCalculator's drag model, not ours. If we diverge from JBM, the issue is in our engine.

2. **Step size study**: run 65cm_hornady_eldm at 0.5 yd, 0.25 yd, and 0.1 yd steps. If 1000yd result changes by more than 0.01 mil, step error is a contributor. Expect negligible change.

3. **Velocity-dependent BC test**: implement a two-zone BC (e.g., Hornady's published high/low velocity BC values), run 65cm_hornady_eldm, record the new Δ physics at 1000yd. Expected: reduces error by 50–80%.

4. **CD interpolation test**: replace cubic CD interpolation with piecewise linear for a single test run. Compare 1000yd result. Expected: small change (< 0.1 mil); either confirms or rules out hypothesis C.

---

## 3. Finding 2 — G1 Subsonic Physics Over-prediction

### 3.1 Evidence

All .22 LR cases show **positive** Δ physics — the engine predicts more drop than the reference. The error is large and grows with distance:

| Dist (yd) | CCI SV (G1 0.120, 1070fps) | Eley Match (G1 0.112, 1085fps) | Lapua CX (G1 0.172, 1073fps) |
|---|---|---|---|
| 25 | +0.075 mil | +0.083 mil | +0.051 mil |
| 75 | +0.157 | +0.164 | +0.117 |
| 100 | +0.367 | +0.390 | +0.261 |
| 150 | +0.949 | +1.019 | +0.677 |
| 200 | +1.786 | +1.914 | +1.247 |

Note the sign: **opposite to the G7 centerfire finding**. The engine over-predicts drag for subsonic .22 LR.

### 3.2 Root Cause

This is expected and documented. The G1 drag table is calibrated against a flat-base blunt-ogive projectile traveling at supersonic velocities. A .22 LR bullet at 1070–1085 fps is already subsonic at the muzzle (SoS ≈ 1116 fps at 59°F). In the subsonic regime below Mach 0.9, G1 Cd rises sharply in the table, significantly over-estimating the drag experienced by a small-caliber round bullet at these speeds.

This is not fixable by adjusting constants — it requires either:
- A measured empirical Cd curve for the specific bullet
- A subsonic correction factor applied below Mach 0.9
- Acceptance that G1 is inapplicable for fully subsonic bullets and must be trued via DOPE

The DOPE correction system handles this perfectly when a full DOPE card is available (k=1 interior LOO: all OK). The problem only manifests when extrapolating beyond the last DOPE entry.

### 3.3 Practical Impact

For .22 LR users, the app should:
1. Flag any load where MV < SoS as "subsonic — DOPE truing required at all distances"
2. Increase the prominence of the "enter DOPE" call to action for these loads
3. Warn when predicting beyond the farthest DOPE entry for a subsonic load

The DOPE correction system IS the fix for this class of bullet; the physics layer cannot be made accurate without empirical drag data.

---

## 4. Finding 3 — DOPE Spline Degrades at Near-boundary Interior Points

### 4.1 Evidence

The k=1 interior INVESTIGATE cases all occur at the near-boundary interior distance — the second-to-last or second training point when training spans the full range:

| Case | INVESTIGATE distance | Δ Physics at that dist | max|Δ| interior k=1 |
|---|---|---|---|
| 308_fed168_smk | 900 yd | −0.415 mil | 0.043 mil |
| 308_fed175_smk | 900 yd | −1.687 mil* | ~0.04 mil |
| 300wm_fed190_smk | 1400 yd | −2.857 mil | 0.033 mil |
| 300wm_horn200_eldx | 1400 yd | −2.368 mil | 0.031 mil |
| 65prc_hornady_eldm | 900 yd | ~−0.70 mil | ~0.04 mil |
| 22wmr_cci_mm | 125 yd | ~+0.16 mil | ~0.03 mil |

*altitude-corrected case

### 4.2 Root Cause

When the k=1 holdout is an interior point adjacent to the range boundary, the training set contains points on both sides but the physics error is growing fastest near that point. The monotone cubic spline interpolates correctly from the training biases on either side, but the actual bias at the holdout distance has curvature that the cubic polynomial doesn't perfectly capture over a 100-yd interval where the physics error is accelerating.

The magnitude (0.031–0.043 mil) is just above the 0.025 mil INVESTIGATE threshold — this is marginal. A denser DOPE card (50-yd intervals instead of 100-yd) would eliminate this issue.

### 4.3 Relationship to Finding 1

If Finding 1 is resolved (physics error reduced), the bias at each training point shrinks and its rate of change with distance also shrinks. The spline curvature problem at 900–1000 yd essentially disappears. **Fix Finding 1 first; then re-evaluate Finding 3.**

---

## 5. Cross-Calculator Discrepancy vs Real-World Error

This is important context before acting on Finding 1.

Our reference data (ShootersCalculator) may not agree with JBM/Applied Ballistics. From published benchmarks, JBM and Applied Ballistics agree to within 0.003 mil at 1000yd when given identical inputs. Our engine disagrees with ShootersCalculator by 0.65 mil at 1000yd. Two possibilities:

**A. Our engine is wrong** — if we also disagree with JBM by 0.65 mil, the bug is in our engine.

**B. ShootersCalculator is different** — if we match JBM within 0.01 mil but differ from ShootersCalculator by 0.65 mil, our engine is correct and ShootersCalculator uses a different drag model. The reference data for our Sub-3 cases would then be the wrong benchmark.

The single Tier 3 (fired) result tells us: at 150 yd, 200 yd, and 300 yd (transonic zone), DOPE-corrected predictions match field-fired impacts to within 0.031–0.096 mil with full training data. This is a pass. We do not have fired data at 1000 yd to directly validate Finding 1.

**The first action before any code change is to compare our engine against JBM, not ShootersCalculator.**

---

## 6. Prioritized Recommendations

### P1 — Cross-reference against JBM — **COMPLETED**

Cross-reference against JBM Ballistics completed (2026-05-30). Finding confirmed.

### P2 — Implement velocity-dependent (multi-zone) BC

Add support for up to 3 BC zones in `BallisticsParams`:
```kotlin
data class BcZone(val minVelocityFps: Double, val bc: Double)
val bcZones: List<BcZone> = emptyList()  // empty = use single bc
```

In `integrate()`, look up `bcEff` by current velocity at each RK4 step rather than using a fixed value. The `dvds` function already takes `bcEff` as a parameter — the only change is making it velocity-dependent.

This is the single highest-impact improvement if P1 confirms an engine error. Bryan Litz publishes measured multi-zone G7 BCs for most precision projectiles.

### P3 — Replace Sub-3 reference data with JBM outputs

If P1 confirms our engine matches JBM but differs from ShootersCalculator, update the test case JSON files to use JBM as the reference calculator. JBM is the more authoritative reference (same McCoy G7 table, same approach as Applied Ballistics).

### P4 — Subsonic G1 UX flag (no engine change)

In the app UI, when a selected load has MV < speedOfSoundFps(conditions.tempF):
- Show a banner: "Subsonic load — physics prediction is approximate. Enter DOPE at each distance for accurate corrections."
- Disable the "use physics only" option for purely subsonic loads.

### P5 — Add .17 HMR test cases with known environmental conditions (data collection)

The only Tier 3 case has unknown altitude and temperature. Firing the same load at a range with a weather station would produce Tier 2 or Tier 1 data. Even 2–3 distance points with documented conditions are more valuable than 100 Sub-3 calculator points.

---

## 7. What NOT to Change

- **The RK4 integrator** — step size is adequate; changing it will not meaningfully improve accuracy.
- **The Fritsch-Carlson CD interpolation** — this is correct and appropriate. Replacing it with piecewise linear would potentially introduce non-physical discontinuities in drag near Mach 1.
- **The `applyBias` extrapolation** (constant clamping beyond DOPE range) — this is correct behavior per design. The stress-test FAIL results at k=N-3 are expected, documented, and not regressions.
- **The `monotoneCubicInterp` spline** — the DOPE bias interpolation is working correctly for interior points. Finding 3 (0.03–0.04 mil at near-boundary interior) is a data density issue, not an algorithm issue.

---

## 8. Suggested Next Validation Run

After completing P1 and P2 (if applicable):

1. Run the `:shared:ballistics:jvmTest` validation suite (`./gradlew :shared:ballistics:jvmTest` from `scopedope-android/`)
2. The primary verdict should improve from INVESTIGATE to OK for all G7 centerfire interior holdouts
3. The Sub-3 Δ physics column should show values < 0.02 mil at all distances ≤ 1000 yd
4. Add the JBM comparison values as a second dope_points source in the JSON (new field `jbm_reference`) for independent cross-check
5. Obtain any field-fired DOPE data to upgrade .308 Win or 6.5 CM to Tier 2 or Tier 3

---

## 9. Appendix — Key Numbers

### G7 Centerfire Δ Physics Summary (sea level, 59°F, engine vs ShootersCalculator)

| Load | G7 BC | MV fps | Δ@500yd | Δ@750yd | Δ@1000yd |
|---|---|---|---|---|---|
| 6.5 CM Hornady 140gr ELD-M | 0.326 | 2674 | −0.093 | −0.184 | −0.653 |
| 6.5 CM Berger 140gr Hybrid | 0.311 | 2779 | −0.205 | −0.408 | −1.042 |
| 6.5 CM Federal 140gr SMK | 0.253 | 2681 | −0.169 | −0.370 | −0.663 |
| 6.5 PRC Hornady 147gr ELD-M | 0.333 | 2910 | ~−0.07 | ~−0.14 | ~−0.75 |
| 6mm CM Hornady 108gr ELD-M | 0.270 | 2960 | −0.154 | −0.345 | −0.992 |
| 6mm CM Berger 105gr Hybrid | 0.278 | 2950 | −0.151 | −0.328 | −0.937 |
| .308 Win Federal 168gr SMK | 0.224 | 2650 | −0.064 | −0.235 | −0.651 |
| .308 Win Hornady 168gr ELD-M | 0.263 | 2650 | −0.184 | −0.476 | −1.206 |
| .300 WM Federal 190gr SMK | 0.275 | 2900 | −0.152 | −0.257 | −0.977 |
| .300 WM Hornady 200gr ELD-X | 0.301 | 2860 | −0.138 | −0.384 | −0.848 |

### .22 LR Δ Physics Summary (G1, fully subsonic)

| Load | G1 BC | MV fps | Δ@100yd | Δ@150yd | Δ@200yd |
|---|---|---|---|---|---|
| CCI Standard Velocity | 0.120 | 1070 | +0.367 | +0.949 | +1.786 |
| Eley Match | 0.112 | 1085 | +0.390 | +1.019 | +1.914 |
| Lapua Center-X | 0.172 | 1073 | +0.261 | +0.677 | +1.247 |
| SK Standard Plus | 0.172 | 1073 | +0.261 | +0.677 | +1.247 |
| Federal AutoMatch | 0.138 | 1200 | +0.340 | +0.862 | +1.567 |

### Tier 3 Fired Impact Results (.17 HMR, Varmint Al field test)

| Dist | Fired (mil) | Physics (mil) | DOPE (mil) | Δ Physics | Δ DOPE | Verdict |
|---|---|---|---|---|---|---|
| 150 yd | 0.509 | 0.463 | 0.478 | −0.046 | −0.031 | OK |
| 200 yd | 1.272 | 1.166 | 1.176 | −0.106 | −0.096 | OK |
| 300 yd | 3.491 | 3.565 | 3.430 | +0.074 | −0.061 | OK (TRANSONIC) |

Physics under-predicts at 150–200 yd and over-predicts at 300 yd (transonic zone). DOPE correction improves accuracy in all three cases. Mean |Δ DOPE| = 0.063 mil.

---

## Document Control

| Field | Value |
|---|---|
| **Document owner** | `jschwefel@coldboreballisticsllc.com` |
| **Classification** | Highly Confidential (04_-_Highly_Confidential/) |
| **Location** | `OneDrive/ScopeDOPE/04_-_Highly_Confidential/Engine_Documentation/BALLISTICS_ENGINE_ACCURACY_ANALYSIS.md` |
| **Cross-references** | `SCOPEDOPE_BALLISTICS_ENGINE_TECHNICAL_WHITE_PAPER.md` |
| **Created** | 2026-06-01 |
| **Last updated** | 2026-06-01 |
| **Next full review due** | 2027-06-01 |

---

## Revision Control Block

| Rev | Date | Changed By | Reviewed By | Approved By | Summary |
|-----|------|------------|-------------|-------------|---------|
| 0.9 | 2026-06-01 | jschwefel | — | — | Initial release |
