Wrote some fun code tonight to find ballistic coefficient using my solver. It searches trajectory data using the selected drag law to determine which ballistic coefficient within a thousandths, matches your inputs, being distance, velocity 1 and velocity 2. This means I can 'true' my BC to my solver. I believe Chairgun and MERO use similar methods to determine ballistic coefficient from the same inputs as well.
This has been my best formulation to determine ballistic coefficient to date.
What it does:
Loops through every tenth bc from .01 to .2 and obtain trajectory data at the provided distance. Closest match to second velocity fetched.
Rinse repeat for hundredth, thousandths, then ten thousandths. Best matching ballistic coefficient for given parameters obtained.
Tested with GA, GA2, RA4, SLG0, SLG1, G1, against MERO's bc calculator and all lines up 1:1. Another mystery solved.
Code snippet:
function FindBC(DragFunction, Vi, SightHeight, ShootingAngle, ZAngle, WindSpeed, WindAngle, windVar, targetDistanceYards, pelletWeightGrains, zeroRangeYards, DensityFactor, Vi2) {
const ptr = new Array(2); // Preallocate space for outputs (only what is needed)
const dragCoefficientsTenths = Array.from({ length: 20 }, (_, i) => (i + 1) * 0.01); // Drag coefficients from 0.01 to 0.2
const dragCoefficientsHundredths = Array.from({ length: 200 }, (_, i) => (i + 1) * 0.001); // Drag coefficients from 0.001 to 0.2
const dragCoefficientsThousandths = Array.from({ length: 2000 }, (_, i) => (i + 1) * 0.0001); // Drag coefficients from 0.0001 to 0.2
const dragCoefficientsTenThousandths = Array.from({ length: 20000 }, (_, i) => (i + 1) * 0.00001); // Drag coefficients from 0.00001 to 0.1
let closestVelocity = null;
let closestDragCoefficientTenth = null;
// Step 1: Find the closest drag coefficient in tenths
for (const DragCoefficient of dragCoefficientsTenths) {
const result = SolveSingle(DragFunction, DragCoefficient, Vi, SightHeight, ShootingAngle, ZAngle, WindSpeed, WindAngle, windVar, targetDistanceYards, pelletWeightGrains, zeroRangeYards, DensityFactor);
if (result && result[7] !== undefined) {
const currentVelocity = parseFloat(result[7]);
if (closestVelocity === null || Math.abs(currentVelocity - Vi2) < Math.abs(closestVelocity - Vi2)) {
closestVelocity = currentVelocity;
closestDragCoefficientTenth = DragCoefficient;
}
}
}
const lowerBoundHundredth = Math.max(0.01, closestDragCoefficientTenth - 0.005);
const upperBoundHundredth = Math.min(0.2, closestDragCoefficientTenth + 0.005);
let closestDragCoefficientHundredth = null;
for (const DragCoefficient of dragCoefficientsHundredths) {
if (DragCoefficient >= lowerBoundHundredth && DragCoefficient <= upperBoundHundredth) {
const result = SolveSingle(DragFunction, DragCoefficient, Vi, SightHeight, ShootingAngle, ZAngle, WindSpeed, WindAngle, windVar, targetDistanceYards, pelletWeightGrains, zeroRangeYards, DensityFactor);
if (result && result[7] !== undefined) {
const currentVelocity = parseFloat(result[7]);
if (closestDragCoefficientHundredth === null || Math.abs(currentVelocity - Vi2) < Math.abs(closestVelocity - Vi2)) {
closestVelocity = currentVelocity;
closestDragCoefficientHundredth = DragCoefficient;
}
}
}
}
const lowerBoundThousandth = Math.max(0.001, closestDragCoefficientHundredth - 0.0005);
const upperBoundThousandth = Math.min(0.2, closestDragCoefficientHundredth + 0.0005);
let closestDragCoefficientThousandth = null;
for (const DragCoefficient of dragCoefficientsThousandths) {
if (DragCoefficient >= lowerBoundThousandth && DragCoefficient <= upperBoundThousandth) {
const result = SolveSingle(DragFunction, DragCoefficient, Vi, SightHeight, ShootingAngle, ZAngle, WindSpeed, WindAngle, windVar, targetDistanceYards, pelletWeightGrains, zeroRangeYards, DensityFactor);
if (result && result[7] !== undefined) {
const currentVelocity = parseFloat(result[7]);
if (closestDragCoefficientThousandth === null || Math.abs(currentVelocity - Vi2) < Math.abs(closestVelocity - Vi2)) {
closestVelocity = currentVelocity;
closestDragCoefficientThousandth = DragCoefficient;
}
}
}
}
const lowerBoundTenThousandth = Math.max(0.00001, closestDragCoefficientThousandth - 0.00005);
const upperBoundTenThousandth = Math.min(0.2, closestDragCoefficientThousandth + 0.00005);
let closestDragCoefficientTenThousandth = null;
for (const DragCoefficient of dragCoefficientsTenThousandths) {
if (DragCoefficient >= lowerBoundTenThousandth && DragCoefficient <= upperBoundTenThousandth) {
const result = SolveSingle(DragFunction, DragCoefficient, Vi, SightHeight, ShootingAngle, ZAngle, WindSpeed, WindAngle, windVar, targetDistanceYards, pelletWeightGrains, zeroRangeYards, DensityFactor);
if (result && result[7] !== undefined) {
const currentVelocity = parseFloat(result[7]);
if (closestDragCoefficientTenThousandth === null || Math.abs(currentVelocity - Vi2) < Math.abs(closestVelocity - Vi2)) {
closestVelocity = currentVelocity;
closestDragCoefficientTenThousandth = DragCoefficient;
}
}
}
}
ptr[0] = closestDragCoefficientTenThousandth;
return ptr;
}
-Matt