The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Physics::Ballistics::Internal -- Various internal ballistics formulae.

ABSTRACT

Internal ballistics is the study of what happens while a projectile is being launched from a barrel, from the time the propellant ignites to the moment after the projectile leaves the muzzle.

This module implements a variety of functions and mathematical formulae useful in the analysis and prediction of internal ballistic effects.

It also branches out somewhat into the closely-related matters of bullet and cartridge composition and characteristics.

REGARDING BULLET DIAMETERS

Some of these functions require the diameter of a projectile as a parameter. Please note that bullet diameters are usually different from the names of their calibers. NATO 5.56mm bullets are actually 5.70mm in diameter, while Russian 5.45mm bullets are actually 5.62mm. .308 caliber bullets really are 0.308 inches in diameter (7.82mm), but .22 Long Rifle bullets are 0.222 inches across.

Making assumptions can hurt! It's better to look it up before plugging it in.

ANNOTATIONS OF SOURCES

Regarding their source, these functions fall into three categories: Some are simple encodings of basic physics (like energy = 1/2 * mass * velocity**2), and these will not be cited. Others are from published works, such as books or trade journals, and these will be cited when possible. A few are products of my own efforts, and will be thus annotated.

OOP INTERFACE

A more integrated, object-oriented interface for these functions is under development.

CONSTANTS

%CASE_CAPACITY_GRAINS

This hash table maps the names of various cartridges to their volumes, in grains of water.

It is based on the table at: http://kwk.us/cases.html

Powder capacities will vary considerably depending on powder type, but multiplying water capacity by 0.85 comes pretty close for most powder types.

FUNCTIONS

cartridge_capacity (bullet_diameter_mm, base_diameter_mm, case_len_mm, psi, [want_powder_bool])

This function estimates the internal capacity (volume) of a rifle cartridge, assuming typical brass material construction.

It is not very accurate (+/- 6%) and actual volumes will vary between different manufacturers of the same cartridge anyway.

Its main advantage over a Powley calculator is ease of use, as it requires fewer and easier-to-obtain parameters.

Unlike the Powley calculator, it is only valid for typically-tapered rifle casings for calibers in the range of about 5mm to 14mm.

This function is the original work of the author.

DISCLAIMER: Do not use this as a guide for handloading! Get a Speer Reloading Manual or similar. If you must use this function, start at least 15% lower than the function indicates and work your way up slowly. Author is not responsible for idiots blasting copper case-bits into their own faces.

    parameter: (float) bullet_diameter_mm is the width of the bullet (in mm)

    parameter: (float) base_diameter_mm is the width of the case at its base, NOT its rim (in mm)

    parameter: (float) case_len_mm is the overall length of the case, including rim and neck (in mm)

    parameter: (float) psi is the peak pressure tolerated by the cartridge (in psi)

    parameter: (boolean) OPTIONAL: set want_powder_bool to a True value to approximate powder capacity instead of water capacity. This is intrinsically inaccurate, since different powders have different weights, but it does okay for typical powders.

    returns: (int) cartridge capacity (in grains)

empty_brass (bullet_diameter_mm, base_diameter_mm, case_len_mm, psi)

This function estimates the weight of an empty rifle cartridge, assuming typical brass material construction. This is just the weight of the case metal, without primer, bullet, or powder.

It is moderately accurate, with the occasional winger, but actual weights will vary between different manufacturers of the same cartridge anyway.

Its main advantage over a Powley calculator is ease of use, as it requires fewer and easier-to-obtain parameters.

Unlike the Powley calculator, it is only valid for reasonably-tapered rifle casings for calibers in the range of about 5mm to 14mm.

This function is the original work of the author.

Compare to known dimensions and weights:

   5.56x45mm:  95 gr, empty_brass predicts  95 = 1.000 actual, 0.0% error
   7.62x39mm: 100 gr, empty_brass predicts 105 = 1.050 actual, 5.0% error
   6.8mm SPC: 107 gr, empty_brass predicts 100 = 0.935 actual, 6.5% error
   7.62x51mm: 182 gr, empty_brass predicts 181 = 0.995 actual, 0.5% error
   12.7x99mm: 847 gr, empty_brass predicts 830 = 0.980 actual, 2.0% error

    parameter: (float) bullet_diameter_mm is the width of the bullet (in mm)

    parameter: (float) base_diameter_mm is the width of the case at its base, NOT its rim (in mm)

    parameter: (float) case_len_mm is the overall length of the case, including rim and neck (in mm)

    parameter: (float) psi is the peak pressure tolerated by the cartridge (in psi)

    parameter: (boolean) OPTIONAL: set want_powder_bool to a True value to approximate powder capacity instead of water capacity. This is intrinsically inaccurate, since different powders have different weights, but it does okay for typical powders.

    returns: (int) cartridge weight (in grains)

gunfire (psi, bullet_diameter_mm, barrel_length_inches, cartridge_diameter_mm, cartridge_length_mm, bullet_mass_gr)

The gunfire function attempts to approximate the performance of a cartridge/bullet/barrel combination in terms of muzzle velocity (and some related attributes).

It does a tolerable job, despite grossly oversimplifying the problem. Its principle charms are that it is easy to use, and there isn't much else available for solving this kind of problem. Improving this function is on my to-do list.

This function is the original work of the author.

Compare to known cartridge/bullet/barrel performance:

    270 Winchester Short Magnum, 140gr, 24" barrel:
        actual velocity:     3250 ft/s
        gunfire() predicts:  3489 ft/s (7% error)

    .300 Lapua Magnum, 185gr, 27" barrel:
        actual velocity:     3300 ft/s
        gunfire() predicts:  3527 ft/s (6% error)

    .25-06 Remington, 120gr, 24" barrel:
        actual velocity:     2990 ft/s
        gunfire() predicts:  3056 ft/s (2% error)

    .308 Winchester, 150gr, 24" barrel:
        actual velocity:     2820 ft/s
        gunfire() predicts:  2840 ft/s (1% error)

    12.7x99mm NATO, 655gr, 45" barrel:
        actual velocity:     3029 ft/s
        gunfire() predicts:  3033 ft/s (0.1% error)

    .223 Remington, 55gr, 24" barrel:
        actual velocity:     3240 ft/s
        gunfire() predicts:  3170 ft/s (2% error)

    .30-06, 180gr, 24" barrel:
        actual velocity:     2700 ft/s
        gunfire() predicts:  2580 ft/s (5% error)

    .375 Ruger, 300gr, 23" barrel:
        actual velocity:     2660 ft/s
        gunfire() predicts:  2431 ft/s (9% error)

In particular, take the "r,m" output field with a huge grain of salt. For a more accurate number, use Physics::Ballistics::External::flight_simulator(). The only advantage of "r,m" is that it is much much faster to derive (25 microseconds for gunfire(), vs an eighth of a second for flight_simulator() on my hardware).

    parameter: (float) peak chamber pressure (in psi, NOT cup!)

    parameter: (float) bullet diameter (in mm)

    parameter: (float) barrel length (in inches)

    parameter: (float) cartridge base diameter (in mm)

    parameter: (float) cartridge overall length (in mm)

    parameter: (float) bullet mass (in grains)

    returns: a reference to a hash, with the following fields:

        N*m: (int) muzzle energy (in joules)
        f/s: (float) muzzle velocity (in feet per second)
        m/s: (float) muzzle velocity (in meters per second)
        r,m: (int) approx range achieved when fired at a 45 degree angle (in meters)
        tm:  (float) time elapsed from ignition to bullet's egress from barrel (in seconds)

ogival_volume (length_mm, radius_mm, [C,] [granularity_mm])

This function calculates the volume of a Haak-series ogival nose shape, as often used for areodynamically streamlined projectiles. It is useful (for instance) for determining the mass of a nose, when nose composition (and therefore density) is known.

qv: http://en.wikipedia.org/wiki/Nose_cone_design#Haack_series

Quoting from that article:

  While the series is a continuous set of shapes determined by the value of
  C in the equations below, two values of C have particular significance:
  when C = 0, the notation LD signifies minimum drag for the given length
  and diameter, and when C = 1/3, LV indicates minimum drag for a given
  length and volume.  The Haack series nose cones are not perfectly tangent
  to the body at their base except for case where C = 2/3.  However, the
  discontinuity is usually so slight as to be imperceptible.  For C > 2/3,
  Haack nose cones bulge to a maximum diameter greater than the base diameter.
  Haack nose tips do not come to a sharp point, but are slightly rounded.

    parameter: (float) the length of the ogive, from base to tip (in mm)

    parameter: (float) the radius of the cross-section of the ogive (in mm)

    parameter: (float) OPTIONAL: the sharpness factor of the ogive, higher values providing a more fat, blunt nose shape (in range 0..2/3, default=2/3)

    parameter: (float) OPTIONAL: the granularity at which the volume will be calculated, lower values providing more accuracy but requiring more processing time (in mm, default=1/10000, provides < 0.1% error)

    returns: (float) volume (in cc)

powley (bore_diameter_inches, case_base_diameter_inches, case_length_inches, barrel_1_length_inches, barrel_2_length_inches)

This function implements Powley's formula for approximating the projectile velocity gained or lost from a change in barrel length.

Example of use:

    It is known that the muzzle velocity of a .223 Remington, 55gr bullet from a 24" barrel is 3240 ft/s.
    We want to know its muzzle velocity from a 16" barrel.

    powley (0.224, 0.378, 1.77, 24, 16) = 0.9205
    3240 ft/s * 0.9205 = 2982 ft/s

    parameter: (float) barrel's bore diameter (in inches)

    parameter: (float) cartridge's base case diameter (in inches)

    parameter: (float) cartridge's overall length (in inches)

    parameter: (float) the length of the barrel for which muzzle velocity is known (in inches)

    parameter: (float) the length of the barrel for which muzzle velocity is not known (in inches)

    returns: (float) the ratio of the muzzle velocities (unitless)

cup2psi_linear (cup[, want_range[, fractional_deviation]])

Approximates peak chamber pressure, in psi, given peak chamber CUP (copper crush test). Since there is a degree of error present in both kinds of pressure tests, this will often disagree with published measurements. To offset this, a range may be requested by passing a non-false second parameter. This will cause three values to be returned: A low-end psi estimate, the median psi estimate (which is the same as the value returned when called without a want_range parameter), and a high-end psi estimate. The degree of variation may be adjusted by passing a value between 0 and 1 as the third argument (default is 0.05).

Based on linear formula from Denton Bramwell's _Correlating PSI and CUP_, with curve-fitting enhancements by module author.

cup2psi (cup[, want_range[, fractional_deviation]])

Approximates peak chamber pressure, in psi, given peak chamber CUP (copper crush test). Since there is a degree of error present in both kinds of pressure tests, this will often disagree with published measurements. To offset this, a range may be requested by passing a non-false second parameter. This will cause three values to be returned: A low-end psi estimate, the median psi estimate (which is the same as the value returned when called without a want_range parameter), and a high-end psi estimate. The degree of variation may be adjusted by passing a value between 0 and 1 as the third argument (default is 0.04).

Based on exponential formula from http://kwk.us/pressures.html, with enhancements by module author.

recoil_mbt (gun_mass_kg, projectile_mass_kg, projectile_velocity_mps, [gas_mass_kg,] [gas_velocity_mps,] [recoil_distance_cm,] [english_or_metric_str])

Approximates the recoil force of a battletank's large-bore main gun (or any other large-bore, high-velocity gun).

Based on formula from Ogorkiewicz's _Design and Development of Fighting Vehicles_, page 58.

As a rule of thumb, the recoil force of an MBT-proportioned vehicle's main gun should not exceed twice the vehicle's mass.

If combustion gas mass and velocity are absent, they will be estimated from the projectile mass and velocity.

The gun mass includes all of the parts moving against the vechicle's recoil mechanism (principally, the barrel and breech).

    parameter: (float) gun mass (in kg)

    parameter: (float) projectile mass (in kg)

    parameter: (float) projectile muzzle velocity (in meters per second)

    parameter: (float) OPTIONAL: combustion gas mass, equal to the propellant mass, usually between one and one half the projectile mass (in kg)

    parameter: (float) OPTIONAL: combustion gas velocity (in meters per second, usually 1450).

    parameter: (float) OPTIONAL: recoil distance (in cm, default=20)

    returns: (float) recoil force exerted on the vehicle (in tonnes)

TODO

The accuracy of these estimating functions can be improved, and I intend to improve them.

In particular, empty_brass should be made to take a "parent case" option, because it tends to underestimate the weight of cartridges which are based on other cartridges which have been trimmed or necked down.