예제 #1
0
        // bore = the hollow part inside a gun barrel or other tube.

        // A function to generate a ballistic solution table in 1 yard increments, up to __BCOMP_MAXRANGE__.

        /* Arguments:
         *      DragFunction:  The drag function you wish to use for the solution (G1, G2, G3, G5, G6, G7, or G8)
         *      DragCoefficient:  The coefficient of drag for the projectile you wish to model.
         *      Velocity:  The projectile initial velocity.
         *      SightHeight:  The height of the sighting system above the bore centerline.
         *                      Most scopes are in the 1.5"-2.0" range.
         *      BoreAngle:  The uphill or downhill shooting angle, in degrees.  Usually 0, but can be anything from
         *                      90 (directly up), to -90 (directly down).
         *      SightToBoreAngle:  The angle of the sighting system relative to the bore, in degrees.  This can be easily computed
         *                  using the CalculateSightToBoreAngle() function documented above.
         *      WindSpeed:  The wind velocity, in mi/hr
         *      WindAngle:  The angle at which the wind is approaching from, in degrees.
         *                  0 degrees is a straight headwind
         *                  90 degrees is from right to left
         *                  180 degrees is a straight tailwind
         *                  -90 or 270 degrees is from left to right.
         *      Solution:	A pointer provided for accessing the solution after it has been generated.
         *                  Memory for this pointer is allocated in the function, so the user does not need
         *                  to worry about it.  This solution can be passed to the retrieval functions to get
         *                  useful data from the solution.
         *      Return Value:
         *                  This function returns an integer representing the maximum valid range of the
         *                  solution.  This also indicates the maximum number of rows in the solution matrix,
         *                  and should not be exceeded in order to avoid a memory segmentation fault.
         */
        static int SolveAll(DragFunction DragFunction, double DragCoefficient, double Velocity_feet_sec, double SightHeight_inch, double BoreAngle, double SightToBoreAngle, double WindSpeed_mile_hr, double WindAngle)
        {
            // seconds
            double t  = 0;
            double dt = 0;
            // feet per second
            double v = 0;
            double vx = 0, vx1 = 0, vy = 0, vy1 = 0;
            // acceleration
            double dv = 0, dvx = 0, dvy = 0;
            // feet
            double x = 0, y = 0;

            // miles per hour
            double headwind_mile_hr = HeadWindVelocity(WindSpeed_mile_hr, WindAngle);
            double crosswind_mile_hr = CrossWindVelocity(WindSpeed_mile_hr, WindAngle);

            // feet per second
            double Gy = GRAVITY * Math.Cos(DegtoRad((BoreAngle + SightToBoreAngle)));
            double Gx = GRAVITY * Math.Sin(DegtoRad((BoreAngle + SightToBoreAngle)));

            vx = Velocity_feet_sec * Math.Cos(DegtoRad(SightToBoreAngle));
            vy = Velocity_feet_sec * Math.Sin(DegtoRad(SightToBoreAngle));

            y = -SightHeight_inch / 12;

            int n = 0;

            for (t = 0; ; t = t + dt)
            {
                // feet per second
                vx1 = vx;
                vy1 = vy;

                v = Math.Sqrt(vx * vx + vy * vy);

                // Compute acceleration using the drag function retardation.
                dv  = DragRetardationVelocity(DragFunction, DragCoefficient, v + headwind_mile_hr * 5280.0 / 3600.0);
                dvx = -(vx / v) * dv;
                dvy = -(vy / v) * dv;

                // Compute velocity, including the resolved gravity vectors.
                vx += dt * dvx + dt * Gx;
                vy += dt * dvy + dt * Gy;

                if (x / 3 >= n)
                {
                    Projectile projectile = new Projectile();
                    projectile.Range      = x / 3;                                                              // Range in yards
                    projectile.Path       = y * 12;                                                             // Path in inches
                    projectile.MOA        = -RadtoMOA(Math.Atan(y / x));                                        // Correction in MOA
                    projectile.Time       = t + dt;                                                             // Time in s
                    projectile.Windage    = WindageCorrection(crosswind_mile_hr, Velocity_feet_sec, x, t + dt); // Windage in inches
                    projectile.WindageMOA = RadtoMOA(Math.Atan(projectile.Windage / (12 * x)));                 // Windage in MOA
                    projectile.Velocity   = v;                                                                  // Velocity (combined)
                    projectile.Vx         = vx;                                                                 // Velocity (x)
                    projectile.Vy         = vy;                                                                 // Velocity (y)
                    ProjectileYards.Add(projectile);
                    n++;
                }

                // Compute position based on average velocity.
                x += dt * (vx + vx1) / 2;
                y += dt * (vy + vy1) / 2;

                dt = 0.5 / v;

                if (Math.Abs(vy) > Math.Abs(3 * vx))
                {
                    break;
                }
                if (n >= __BCOMP_MAXRANGE__ + 1)
                {
                    break;
                }
            }

            size = n;

            return(n);
        }
예제 #2
0
        // A function to calculate ballistic retardation values based on standard drag functions.

        /* Arguments:
         *      DragFunction:  G1, G2, G3, G4, G5, G6, G7, or G8.  All are enumerated above.
         *      DragCoefficient:  The coefficient of drag for the projectile for the given drag function.
         *      Velocity:  The Velocity of the projectile.
         *
         *  Return Value:
         *      The function returns the projectile drag retardation velocity, in ft/s per second.
         */
        static double DragRetardationVelocity(DragFunction DragFunction, double DragCoefficient, double Velocity_feet_sec)
        {
            double vp  = Velocity_feet_sec;
            double val = -1;
            double A   = -1;
            double M   = -1;

            switch (DragFunction)
            {
            case DragFunction.G1:
                if (vp > 4230)
                {
                    A = 1.477404177730177e-04; M = 1.9565;
                }
                else if (vp > 3680)
                {
                    A = 1.920339268755614e-04; M = 1.925;
                }
                else if (vp > 3450)
                {
                    A = 2.894751026819746e-04; M = 1.875;
                }
                else if (vp > 3295)
                {
                    A = 4.349905111115636e-04; M = 1.825;
                }
                else if (vp > 3130)
                {
                    A = 6.520421871892662e-04; M = 1.775;
                }
                else if (vp > 2960)
                {
                    A = 9.748073694078696e-04; M = 1.725;
                }
                else if (vp > 2830)
                {
                    A = 1.453721560187286e-03; M = 1.675;
                }
                else if (vp > 2680)
                {
                    A = 2.162887202930376e-03; M = 1.625;
                }
                else if (vp > 2460)
                {
                    A = 3.209559783129881e-03; M = 1.575;
                }
                else if (vp > 2225)
                {
                    A = 3.904368218691249e-03; M = 1.55;
                }
                else if (vp > 2015)
                {
                    A = 3.222942271262336e-03; M = 1.575;
                }
                else if (vp > 1890)
                {
                    A = 2.203329542297809e-03; M = 1.625;
                }
                else if (vp > 1810)
                {
                    A = 1.511001028891904e-03; M = 1.675;
                }
                else if (vp > 1730)
                {
                    A = 8.609957592468259e-04; M = 1.75;
                }
                else if (vp > 1595)
                {
                    A = 4.086146797305117e-04; M = 1.85;
                }
                else if (vp > 1520)
                {
                    A = 1.954473210037398e-04; M = 1.95;
                }
                else if (vp > 1420)
                {
                    A = 5.431896266462351e-05; M = 2.125;
                }
                else if (vp > 1360)
                {
                    A = 8.847742581674416e-06; M = 2.375;
                }
                else if (vp > 1315)
                {
                    A = 1.456922328720298e-06; M = 2.625;
                }
                else if (vp > 1280)
                {
                    A = 2.419485191895565e-07; M = 2.875;
                }
                else if (vp > 1220)
                {
                    A = 1.657956321067612e-08; M = 3.25;
                }
                else if (vp > 1185)
                {
                    A = 4.745469537157371e-10; M = 3.75;
                }
                else if (vp > 1150)
                {
                    A = 1.379746590025088e-11; M = 4.25;
                }
                else if (vp > 1100)
                {
                    A = 4.070157961147882e-13; M = 4.75;
                }
                else if (vp > 1060)
                {
                    A = 2.938236954847331e-14; M = 5.125;
                }
                else if (vp > 1025)
                {
                    A = 1.228597370774746e-14; M = 5.25;
                }
                else if (vp > 980)
                {
                    A = 2.916938264100495e-14; M = 5.125;
                }
                else if (vp > 945)
                {
                    A = 3.855099424807451e-13; M = 4.75;
                }
                else if (vp > 905)
                {
                    A = 1.185097045689854e-11; M = 4.25;
                }
                else if (vp > 860)
                {
                    A = 3.566129470974951e-10; M = 3.75;
                }
                else if (vp > 810)
                {
                    A = 1.045513263966272e-08; M = 3.25;
                }
                else if (vp > 780)
                {
                    A = 1.291159200846216e-07; M = 2.875;
                }
                else if (vp > 750)
                {
                    A = 6.824429329105383e-07; M = 2.625;
                }
                else if (vp > 700)
                {
                    A = 3.569169672385163e-06; M = 2.375;
                }
                else if (vp > 640)
                {
                    A = 1.839015095899579e-05; M = 2.125;
                }
                else if (vp > 600)
                {
                    A = 5.71117468873424e-05; M = 1.950;
                }
                else if (vp > 550)
                {
                    A = 9.226557091973427e-05; M = 1.875;
                }
                else if (vp > 250)
                {
                    A = 9.337991957131389e-05; M = 1.875;
                }
                else if (vp > 100)
                {
                    A = 7.225247327590413e-05; M = 1.925;
                }
                else if (vp > 65)
                {
                    A = 5.792684957074546e-05; M = 1.975;
                }
                else if (vp > 0)
                {
                    A = 5.206214107320588e-05; M = 2.000;
                }
                break;

            case DragFunction.G2:
                if (vp > 1674)
                {
                    A = .0079470052136733; M = 1.36999902851493;
                }
                else if (vp > 1172)
                {
                    A = 1.00419763721974e-03; M = 1.65392237010294;
                }
                else if (vp > 1060)
                {
                    A = 7.15571228255369e-23; M = 7.91913562392361;
                }
                else if (vp > 949)
                {
                    A = 1.39589807205091e-10; M = 3.81439537623717;
                }
                else if (vp > 670)
                {
                    A = 2.34364342818625e-04; M = 1.71869536324748;
                }
                else if (vp > 335)
                {
                    A = 1.77962438921838e-04; M = 1.76877550388679;
                }
                else if (vp > 0)
                {
                    A = 5.18033561289704e-05; M = 1.98160270524632;
                }
                break;

            case DragFunction.G5:
                if (vp > 1730)
                {
                    A = 7.24854775171929e-03; M = 1.41538574492812;
                }
                else if (vp > 1228)
                {
                    A = 3.50563361516117e-05; M = 2.13077307854948;
                }
                else if (vp > 1116)
                {
                    A = 1.84029481181151e-13; M = 4.81927320350395;
                }
                else if (vp > 1004)
                {
                    A = 1.34713064017409e-22; M = 7.8100555281422;
                }
                else if (vp > 837)
                {
                    A = 1.03965974081168e-07; M = 2.84204791809926;
                }
                else if (vp > 335)
                {
                    A = 1.09301593869823e-04; M = 1.81096361579504;
                }
                else if (vp > 0)
                {
                    A = 3.51963178524273e-05; M = 2.00477856801111;
                }
                break;

            case DragFunction.G6:
                if (vp > 3236)
                {
                    A = 0.0455384883480781; M = 1.15997674041274;
                }
                else if (vp > 2065)
                {
                    A = 7.167261849653769e-02; M = 1.10704436538885;
                }
                else if (vp > 1311)
                {
                    A = 1.66676386084348e-03; M = 1.60085100195952;
                }
                else if (vp > 1144)
                {
                    A = 1.01482730119215e-07; M = 2.9569674731838;
                }
                else if (vp > 1004)
                {
                    A = 4.31542773103552e-18; M = 6.34106317069757;
                }
                else if (vp > 670)
                {
                    A = 2.04835650496866e-05; M = 2.11688446325998;
                }
                else if (vp > 0)
                {
                    A = 7.50912466084823e-05; M = 1.92031057847052;
                }
                break;

            case DragFunction.G7:
                if (vp > 4200)
                {
                    A = 1.29081656775919e-09; M = 3.24121295355962;
                }
                else if (vp > 3000)
                {
                    A = 0.0171422231434847; M = 1.27907168025204;
                }
                else if (vp > 1470)
                {
                    A = 2.33355948302505e-03; M = 1.52693913274526;
                }
                else if (vp > 1260)
                {
                    A = 7.97592111627665e-04; M = 1.67688974440324;
                }
                else if (vp > 1110)
                {
                    A = 5.71086414289273e-12; M = 4.3212826264889;
                }
                else if (vp > 960)
                {
                    A = 3.02865108244904e-17; M = 5.99074203776707;
                }
                else if (vp > 670)
                {
                    A = 7.52285155782535e-06; M = 2.1738019851075;
                }
                else if (vp > 540)
                {
                    A = 1.31766281225189e-05; M = 2.08774690257991;
                }
                else if (vp > 0)
                {
                    A = 1.34504843776525e-05; M = 2.08702306738884;
                }
                break;

            case DragFunction.G8:
                if (vp > 3571)
                {
                    A = .0112263766252305; M = 1.33207346655961;
                }
                else if (vp > 1841)
                {
                    A = .0167252613732636; M = 1.28662041261785;
                }
                else if (vp > 1120)
                {
                    A = 2.20172456619625e-03; M = 1.55636358091189;
                }
                else if (vp > 1088)
                {
                    A = 2.0538037167098e-16; M = 5.80410776994789;
                }
                else if (vp > 976)
                {
                    A = 5.92182174254121e-12; M = 4.29275576134191;
                }
                else if (vp > 0)
                {
                    A = 4.3917343795117e-05; M = 1.99978116283334;
                }
                break;

            default:
                break;
            }

            if (A != -1 && M != -1 && vp > 0 && vp < 10000)
            {
                val = A * Math.Pow(vp, M) / DragCoefficient;
                return(val);
            }
            else
            {
                return(-1);
            }
        }
예제 #3
0
        // bore = the hollow part inside a gun barrel or other tube.

        // A function to determine the bore angle needed to achieve a target zero at Range yards
        // (at standard conditions and on level ground.)

        /*  Arguments:
         *      DragFunction:  The drag function to use (G1, G2, G3, G5, G6, G7, G8)
         *      DragCoefficient:  The coefficient of drag for the projectile, for the supplied drag function.
         *      Velocity:  The initial velocity of the projectile, in feet/s
         *      SightHeight:  The height of the sighting system above the bore centerline, in inches.
         *                    Most scopes fall in the 1.6 to 2.0 inch range.
         *      ZeroRange:  The range in yards, at which you wish the projectile to intersect yIntercept.
         *      yIntercept:  The height, in inches, you wish for the projectile to be when it crosses ZeroRange yards.
         *                  This is usually 0 for a target zero, but could be any number.  For example if you wish
         *                  to sight your rifle in 1.5" high at 100 yards, then you would set yIntercept to 1.5, and ZeroRange to 100
         *
         *  Return Value:
         *      Returns the angle of the bore relative to the sighting system, in degrees.
         */
        static double CalculateSightToBoreAngle(DragFunction DragFunction, double DragCoefficient, double Velocity_feet_sec, double SightHeight_inch, double ZeroRange_yard, double yIntercept_inch)
        {
            // Numerical Integration variables
            double t  = 0;
            double dt = 1 / Velocity_feet_sec; // The solution accuracy generally doesn't suffer if its within a foot for each second of time.
            double y  = 0;                     /*-SightHeight/12;*/
            double x  = 0;
            double da;                         // The change in the bore angle used to iterate in on the correct zero angle.

            // State variables for each integration loop.
            double v = 0, vx = 0, vy = 0;    // velocity
            double vx1 = 0, vy1 = 0;         // Last frame's velocity, used for computing average velocity.
            double dv = 0, dvx = 0, dvy = 0; // acceleration
            double Gx = 0, Gy = 0;           // Gravitational acceleration

            double angle = 0;                // The actual angle of the bore.

            // Start with a very coarse angular change, to quickly solve even large launch angle problems.
            da = DegtoRad(14);

            // The general idea here is to start at 0 degrees elevation, and increase the elevation by 14 degrees
            // until we are above the correct elevation.  Then reduce the angular change by half, and begin reducing
            // the angle.  Once we are again below the correct angle, reduce the angular change by half again, and go
            // back up.  This allows for a fast successive approximation of the correct elevation, usually within less
            // than 20 iterations.
            for (angle = 0; ; angle = angle + da)
            {
                vy = Velocity_feet_sec * Math.Sin(angle);
                vx = Velocity_feet_sec * Math.Cos(angle);
                Gx = GRAVITY * Math.Sin(angle);
                Gy = GRAVITY * Math.Cos(angle);

                for (t = 0, x = 0, y = 0 - SightHeight_inch / 12; x <= ZeroRange_yard * 3; t = t + dt)
                {
                    vy1 = vy;
                    vx1 = vx;

                    v  = Math.Sqrt(vx * vx + vy * vy);
                    dt = 1 / v;

                    // Compute acceleration using the drag function retardation.
                    dv  = DragRetardationVelocity(DragFunction, DragCoefficient, v);
                    dvx = -(vx / v) * dv;
                    dvy = -(vy / v) * dv;

                    // Compute velocity, including the resolved gravity vectors.
                    vx += dt * dvx + dt * Gx;
                    vy += dt * dvy + dt * Gy;

                    x += dt * (vx + vx1) / 2;
                    y += dt * (vy + vy1) / 2;

                    // Break early to save CPU time if we won't find a solution.
                    if (vy < 0 && y < yIntercept_inch)
                    {
                        break;
                    }
                    if (vy > 3 * vx)
                    {
                        break;
                    }
                }

                if (y > yIntercept_inch && da > 0)
                {
                    da = -da / 2;
                }

                if (y < yIntercept_inch && da < 0)
                {
                    da = -da / 2;
                }

                if (Math.Abs(da) < MOAtoRad(0.01))
                {
                    break; // If our accuracy is sufficient, we can stop approximating.
                }
                if (angle > DegtoRad(45))
                {
                    break; // If we exceed the 45 degree launch angle, then the projectile just won't get there, so we stop trying.
                }
            }

            return(RadtoDeg(angle)); // Convert to degrees for return value.
        }