package Physics::Ballistics::Terminal;
use strict;
use warnings;
use vars qw/$VERSION/;
use Physics::Ballistics;
use Math::Trig;
BEGIN {
$VERSION = '1.00';
}
=head1 NAME
Physics::Ballistics::Terminal -- Various terminal ballistics formulae and functions.
=cut
=head1 ABSTRACT
Terminal ballistics is the study of what happens when a projectile impacts its target.
This module implements a variety of functions and mathematical formulae useful in the
analysis and prediction of terminal ballistic effects.
=head1 TWO DOMAINS OF VELOCITY
Some of these functions pertain to the "ballistic" domain, while others pertain to the
"hypervelocity" domain. These refer to two different and somewhat ill-defined ranges
of velocity. "Ballistic" velocity ranges from a few hundred to about 1100 meters per
second, while "Hypervelocity" ranges from about 1100 meters per second to several tens
of thousands of meters per second.
Why does this matter? Because successful models of ballistic interactions are not
accurate in the hypervelocity domain, and successful models of hypervelocty interactions
are not accurate in the ballistic domain. Thus it is crucial to use the model which is
valid for the velocity of the interaction you are attempting to predict.
Functions which are only valid in one domain or the other will be marked as such.
=head1 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. Please do not make assumptions;
look it up before plugging it in.
=head1 RHA
RHA is short for "Rolled Homogenous Armor". It is a commonly-used term for hardened
steel armor material in general, or for armor steel which complies with the military
specification MIL-A-12560. RHA is also a common standard material for normalizing
depth of penetration. It is approximately equivalent to AISI 4340 steel in character,
and AISI 4340 is often used in lieu of "real" RHA in laboratory experiments.
Unless otherwise noted, return values representing a depth of penetration should be
understood to represent depth of penetration into an RHA target.
=head1 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.
=head1 OOP INTERFACE
For an object-oriented interface to (most of) these functions, see Physics::Ballistics.
=head1 FUNCTIONS
=head2 anderson (length_cm, diam_cm, vel_kps, [penetrator_material,] [deg_angle,] [scaling_factor])
Attempts to estimate how deeply a long-rod projectile will penetrate into RHA (semi-infinite penetration).
This function is based on Anderson's _Accuracy of Perforation Equations_, less 11% correction per that paper's conclusions, and including adjustments from Lakowski for scale, material, and backsurface effects.
qv: http://208.84.116.223/forums/index.php?showtopic=10482&st=110
ONLY VALID IN HYPERVELOCITY DOMAIN.
=over 4
parameter: (float) penetrator length (in cm)
parameter: (float) penetrator diameter (in cm)
parameter: (float) penetrator velocity (in kilometers per second)
parameter: (float or string) OPTIONAL: penetrator material or material multiplier. (defaults to 1.0) Valid values are:
=over 4
* an integer, for custom material factors
* "steel": Hardened steel == 0.50
* "wha": Tungsten-heavy alloy (NOT tungsten carbide) == 1.00
* "du": Depleted uranium alloy == 1.13
=back
parameter: (float) OPTIONAL: angle of impact, 0 == perpendicular to target surface (in degrees, defaults to 0)
parameter: (float) OPTIONAL: scaling effect, relative to M829A2 dimensions (unitless, defaults to 1.0)
returns: (float) Depth of penetration (in cm)
=back
=cut
# Given attributes of a hypervelocity-domain long-rod penetrator, returns penetration into RHA, in cm.
# Based on Anderson TN, from _Accuracy of Perforation Equations_, less 11% correction per that paper's conclusions, and including adjustments from Lakowski for scale, material, and backsurface effects, qv: http://63.99.108.76/forums/index.php?showtopic=8332&pid=156211&mode=threaded&show=&st=& and http://63.99.108.76/forums/index.php?showtopic=10482&st=100
# NOTE: only valid in hypervelocity domain, above 1100 meters/second.
sub anderson {
my ($len, $diam, $vel, $material, $deg_angle, $scaling) = @_;
return ("usage: pen_cm = anderson(length_cm, diam_cm, vel_kps, material, [ deg_angle ]") unless (defined($len) && defined($vel));
$scaling = 1.0 unless (defined($scaling));
$material = 1.0 unless (defined($material)); # 1.00 = WHA
$material = lc($material);
$material = 1.00 if ($material eq 'wha');
$material = 1.13 if ($material eq 'du');
$material = 1.20 if ($material eq 'duv');
$material = 0.50 if ($material eq 'steel');
$material = 0.50 if ($material =~ /[^\d\.]/);
$deg_angle = 0 unless (defined($deg_angle));
my $angle = pi * $deg_angle / 180; # convert degrees to radians
my $baseline = (1.044 * $vel) - (0.194 * log($len / $diam)) - 0.212;
my $scale_effect = 1 + ($diam / (13 * $scaling));
my $backsurface = $diam / cos($angle);
my $base_pen = $baseline * $scale_effect * $len;
my $penetration = $base_pen * $material;
$penetration = $penetration + $backsurface;
$penetration = $penetration * .89; # less 11% -- Anderson's own analysis concluded that this formula overpredicts penetration by about this much
$penetration = int($penetration * 10 + 0.5) / 10;
return $penetration;
}
=head2 boxes (length, width, height, front thickness, back thickness, side thickness, top thickness, underside thickness, density)
Calculates the volumes, mass, and volume-to-mass ratio of a hollow box of rectangular cross-sections.
=over 4
parameter: (float) interior distance from front to back (in cm)
parameter: (float) interior distance from left to right (in cm)
parameter: (float) interior distance from top to bottom (in cm)
parameter: (float) thickness of front wall (in cm)
parameter: (float) thickness of back wall (in cm)
parameter: (float) thickness of side walls (in cm)
parameter: (float) thickness of bottom wall (in cm)
parameter: (float) specific density of wall material (g/cc)
returns: list containing the following:
=over 4
* (float) interior volume (in cc)
* (float) exterior volume (in cc)
* (float) total wall mass (in grams)
* (float) total wall mass (in pounds)
* (float) ratio of interior volume to mass (cc/g)
=back
=back
=cut
sub boxes { # params: length, width, height, thick / front, back, side, top, bottom, den
my ($inx, $iny, $inz, $tf, $tb, $ts, $tt, $tu, $den) = @_;
return "usage: boxes ( interior_x_cm, int_y, int_z, thickness_front_cm, thick_back, thick_side, thick_top, density ) = string" unless ( defined($inx) );
my ($inv, $ouv, $vdiff, $mass, $retval, $lbs, $rat);
$inv = $inx * $iny * $inz;
$ouv = ($inx + $tf + $tb) * ($iny + 2 * $ts) * ($inz + $tt + $tu);
$vdiff = $ouv - $inv;
$mass = $vdiff * $den;
$lbs = int(($mass * 2.2 / 100) + 0.5) / 10;
$rat = int($inv * 100 / $mass) / 100;
# returns: interior volume in cc, exterior volume, difference between interior and exterior volumes,
# mass in grams, mass in pounds, and ratio of interior volume to mass (cc/g)
return ($inv, $ouv, $vdiff, $mass, $lbs, $rat);
}
=head2 heat_dop(diameter_mm, standoff_distance, [target_density,] [precision_bool], [target_hardness_bhn])
Attempts to predict the depth of penetration of a copper-lined conical shaped charge into steel.
Based on Ogorkiewicz's book, _Design and Development of Fighting Vehicles_, and
modified as per _Journal of Battlefield Technology_ Vol 1-1 pp 1. A copy of
the JBT chart may be found at:
http://ciar.org/ttk/mbt/news/news.smm.ww2-armor-plate.de5bf54f.0110271532.871cbf@posting.google.com.txt
The author has modified this formula slightly to account for errors observed in
Ogorkiewicz's results, relative to empirically derived results.
For better understanding of shaped charge penetration, please review:
http://www.globalsecurity.org/military/systems/munitions/bullets2-shaped-charge.htm
=over 4
parameter: (float) cone diameter (in mm)
parameter: (float or str) standoff distance (multiple of cone diameter if float, else in mm, for instance "80.5mm")
parameter: (float) OPTIONAL: density of target material (in g/cc, default is 7.86, the density of RHA)
parameter: (boolean) OPTIONAL: assume precision shaped charge (default is False)
parameter: (float) OPTIONAL: hardness of target material (in BHN, default is 300, low in the range of RHA hardnesses)
returns: (int) depth of penetration (in mm)
=back
=cut
# Copper-lined shaped charge depth of penetration, lifted from Ogorkiewicz's _Design and Development of Fighting Vehicles_, and modified as per _Journal of Battlefield Technology_ Vol 1-1 pp 1, copy of chart from that article can be found at: http://ciar.org/ttk/mbt/news/news.smm.ww2-armor-plate.de5bf54f.0110271532.871cbf@posting.google.com.txt
# NOTE: does not take into account any advanced effects from composited targets.
# NOTE: removed jet density parameter from argument list because liner ductility effects eclipse liner density in practice, and I don't want to factor liner ductility into this code right now. (eg: according to Ogorkiewicz, a steel liner would increase penetration, but in practice steel liners reduce penetration due to their relatively low ductility.)
# NOTE: Ogorkiewicz's curve for nonprecision charges was a little low at optimal standoff and high elsewhere relative to the _JoBT_ article chart, so I split the difference. I suspect his precision charge curve is similarly a bit optimistic in favor of higher penetration, so take it with a grain of salt.
sub heat_dop {
my ($diam, $soff, $aden, $prec, $hard) = @_;
my $jden;
my $pen = 0;
return ("usage: heat_dop (diameter_mm, standoff[mm], [targ-den], [precision], [hard])\nDiameter units is mm\nstandoff assumed cd's unless 'mm' is specified\ntarget density default is 7.86 (RHA)\nprecision default is 0 (non-precision), 1 for high precision\nhardness is BHN, default is 300 (ignore if not steel)\nReturns depth of penetration in mm") unless (defined ($soff));
setundef (\$aden, 7.86);
setundef (\$jden, 8.96);
setundef (\$prec, 0 );
setundef (\$hard, 300 );
# print (" aden=$aden jden=$jden prec=$prec hard=$hard\n");
my $MIN_DENSITY = 0.00000000001;
$aden = $MIN_DENSITY if ($aden < $MIN_DENSITY); # avoid divide-by-zero error
if ($soff =~ /(\d+)mm/) { $soff = $1 / $diam; } # normalize to factor of cone diameters
# $soff *= ($hard / 300)**0.5; # I'm guessing here -- target hardness does appear to shift optimal standoff, but effects of nonoptimal standoff not quite proportional to this relation. -- zzapp, figure this out.
if ($prec) {
# precision shaped charge DoP curve looks something like this:
if ($soff <= 1) { $pen = 3.0 + 1.500 * ($soff - 0); }
elsif ($soff <= 3) { $pen = 4.5 + 0.350 * ($soff - 1); }
elsif ($soff <= 6) { $pen = 5.2 + 0.100 * ($soff - 3); }
elsif ($soff <= 9) { $pen = 5.5 - 0.033 * ($soff - 6); }
else { $pen = 5.4 - (($soff - 9) / 4.117); }
}
else {
# nonprecision shaped charge DoP curve looks something like this:
if ($soff <= 1) { $pen = 3.00 + 1.200 * ($soff - 0); }
elsif ($soff <= 2) { $pen = 4.20 + 0.150 * ($soff - 1); }
elsif ($soff <= 3) { $pen = 4.35 - 0.150 * ($soff - 2); }
elsif ($soff <= 4) { $pen = 4.20 - 0.400 * ($soff - 3); }
elsif ($soff <= 7) { $pen = 4.00 - 0.550 * ($soff - 4); }
elsif ($soff <= 10) { $pen = 2.35 - 0.170 * ($soff - 7); }
else { $pen = 1.84 - (($soff - 10) / 7.95); }
}
$pen *= (($jden / $aden) / (8.96 / 7.86))**0.5;
$pen *= $diam;
# round off, this is *not* any kind of precise estimate!
$pen = int($pen + 0.5);
return $pen; # returns millimeters
}
=head2 ke (velocity, mass)
Calculates kinetic energy of a mass in motion.
=over 4
parameter: (float) projectile velocity (in meters per second)
parameter: (float) projectile weight (in grams)
returns: (float) projectile kinetic energy (in joules)
=back
=cut
sub ke {
my ($v, $w) = @_;
return ("usage: ke (meters-per-second, grams) = joules\n") unless (defined($v));
my $ret = $v * $v * $w / 1000000;
# convert to joules
$ret *= 2.9833;
# round over to nearest thousandth
$ret = int($ret * 1000 + 0.5) / 1000;
return $ret;
}
=head2 me2te (mass_efficiency, density)
Given the mass efficiency of a material, returns its thickness efficiency.
This function is used when comparing armor materials on the basis of their RHA
equivalence. Mass efficiency is a factor of how much armor mass than RHA mass
provides the same resistance to penetration. Conversely, thickness efficiency
is a factor of how much less armor thickness than RHA thickness provides the
same resistance to penetration.
For instance, if an armor material has a mass efficiency of 4.0, then only a
quarter as much mass is needed to provide a given protection level compared to
RHA of equivalent protection. A pound of the armor material provides the same
protection as four pounds of RHA.
Similarly, if an armor material has a thickness efficiency of 3.0, then only a
third as much thickness is needed to provide a given protection level compared
to RHA of equivalent protection. An inch of the armor material provides the
same protection as three inches of RHA.
If the density of the armor material is known, me2te() and te2me() may be used
to convert back and forth between mass efficiency or thickness efficiency,
depending on which is known.
=over 4
parameter: (float) armor material mass efficiency (unitless, factor relative to RHA)
parameter: (float) armor material density (g/cc)
returns: (float) armor material thickness efficiency (unitless, factor relative to RHA)
=back
=cut
sub me2te { # given mass efficiency and density, returns thickness efficiency
my ($me, $den) = @_;
return $me * $den / 7.86;
}
=head2 me2ce (mass_efficiency, cost_usd_per_pound)
Given the mass efficiency of a material, returns its cost efficiency.
See the description of me2te() for more explanation.
This actually returns the cost efficiency relative to AISI 4340 steel, which is
often used as a close approximation to RHA. The costs of actual MIL-A-12560
compliant steel are dominated by political factors, which are beyond the scope
of this module.
=over 4
parameter: (float) armor material mass efficiency (unitless, factor relative to RHA)
parameter: (float) armor material cost (USA dollars / pound)
returns: (float) armor material cost efficiency (unitless, factor relative to RHA)
=back
=cut
sub me2ce { # given mass efficiency and cost per pound, returns cost efficiency relative to AISI 4340 steel (which closely approximates characteristics of RHA).
my ($me, $cost) = @_;
# AISI 4340 steel is about $3.80/lb; qv https://www.metalsupermarkets.com/CART.ASPX?PRODUCTID=MR4340/9
return $me * 3.80 / $cost;
}
=head2 me2cem (mass_efficiency, cost_usd_per_pound)
Given the mass efficiency of a material, returns its cost efficiency relative to mild steel.
See the description of me2ce() for more explanation.
=over 4
parameter: (float) armor material mass efficiency (unitless, factor relative to RHA)
parameter: (float) armor material cost (USA dollars / pound)
returns: (float) armor material cost efficiency (unitless, factor relative to mild steel)
=back
=cut
sub me2cem { # given mass efficiency and cost per pound, returns cost efficiency relative to mild steel
my ($me, $cost) = @_;
my $mild_steel_cost = 0.40; # Mild Steel 1" Plate is about $0.40/lb
my $mild_steel_me = 0.81; # Mild Steel 1" Plate has mass efficiency of about 0.81
return ($me * $mild_steel_cost) / ($cost * $mild_steel_me);
}
=head2 odermatt (length_cm, diam_cm, vel_kps, target_density, target_uts_kpsi, rod_density, deg_angle, kps_drop_per_km, range_km, target_thickness_cm, [tip_length_cm, kA1, kA2])
Attempts to estimate perforation limit for a long-rod projectile penetrating RHA. Produces more accurate results than Anderson, but also requires more hard-to-get information, and doesn't exactly measure the same thing (perforation limit, vs depth into semi-infinite target).
This function is based on Lanz and Odermatt's paper _Post Perforation Length & Velocity of KE Projectiles with single Oblique Targets_, published in the 15th International Symposium of Ballistics.
ONLY VALID IN HYPERVELOCITY DOMAIN.
Only valid for penetrator length/diameter ratios of 10.0 or higher, unless kA1 and kA2 are provided (which afaik can only be derived empirically, so good luck).
=over 4
parameter: (float) penetrator length (in cm)
parameter: (float) penetrator diameter (in cm)
parameter: (float) penetrator velocity (in kilometers per second)
parameter: (float) target density (in g/cc)
parameter: (float) target ultimate tensile strength (in kpsi)
parameter: (float) penetrator density (in g/cc)
parameter: (float) angle of impact (in degrees, 0 == perpendicular to target surface)
parameter: (float) target thickness (in cm)
parameter: (float) OPTIONAL: penetrator tip length (in cm, defaults to three times penetrator diameter)
parameter: (float) OPTIONAL: kA1 empirically discovered constant (only required for L/D < 10.0)
parameter: (float) OPTIONAL: kA2 empirically discovered constant (only required for L/D < 10.0)
returns: (float) Target's perforation limit (in cm)
=back
=cut
# Given attributes of a hypervelocity-domain long-rod penetrator and its target, returns penetration into RHA, in cm.
# based on Lanz/Odermatt depth of penetration equation for long rod penetrators, valid for L:D of 10 or over.
# 15th international symposium of ballistics - "Post Perforation Length & Velocity of KE Projectiles with Single Oblique Targets".
# NOTE: only works for L:D of 10 or greater, unless kA1 and kA2 are defined. For smaller penetrators, use anderson or pc.
# NOTE: only valid in hypervelocity domain, above 1100 meters/second.
sub odermatt {
my ($len, $diam, $vel, $targden, $targ_kpsi, $penden, $deg_angle, $targthick, $tip_len, $kA1, $kA2) = @_;
return ("usage: pen_cm = odermatt (length_cm, diam_cm, vel_kps, target_den, target_uts_kpsi, pen_density, deg_angle, target_thick, [tip_length_cm, kA1, kA2 ]") unless (defined($len) && defined($targthick));
return ("error, L:D of $len:$diam is outside this formula's domain\n") unless (($len / $diam >= 10) || (defined($kA1) && defined($kA2)));
my $targ_mpa = $targ_kpsi * 6.895; # converting kpsi to MPa
my $targ_den_gm3 = $targden * 1000; # converting g/cc to kg/m3
my $pen_den_gm3 = $penden * 1000; # converting g/cc to kg/m3
my $diam_mm = $diam * 10; # cm to mm
my $len_mm = $len * 10; # cm to mm
my $vel_mps = $vel * 1000; # km/sec to m/sec
my $targ_mm = $targthick * 10; # cm to mm
$kA1 = $kA1 || 3.94;
$kA2 = $kA2 || 11.20;
$tip_len = $tip_len || $diam * 3; # if no tip length given, assume three diameters long
$tip_len = $tip_len * 10; # cm to mm
# length to diameter ratio influence (valid for Lw/D of at least 10 -- if Lw/D is lower, use anderson):
my $Lw = $len_mm - 2 * $tip_len / 3 - 1.5 * $diam_mm; # approximation of length of penetrator after replacing conical tip with cylinder of equal mass and diameter and reducing remaining length by 1.5 diameters
my $facA = 1 + $kA1 * $diam_mm / ($Lw * (1 - Math::Trig::tanh(($Lw / $diam_mm) - 10) / $kA2));
# target obliquity:
my $rad_angle = pi * $deg_angle / 180; # convert degrees to radians
my $facB = 0; # target obliquity
$facB = cos($rad_angle)**-0.225;
# density ratio of penetrator to target
my $facC = ($pen_den_gm3 / $targ_den_gm3)**0.5;
# material properties and impact velocity
my $targMatFac = 22.1 + 0.01274 * $targ_mpa - 0.00000947 * $targ_mpa**2;
my $facD = exp(-1 * $targMatFac * $targ_mpa / ($pen_den_gm3 * $vel_mps**2));
my $penetration = $len_mm * $facA * $facB * $facC * $facD;
$penetration = int($penetration + 0.5) / 10; # rounding to nearest mm, then converting to cm
return $penetration;
}
=head2 pc (mass_grains, velocity_fps, diameter_inches, shape_str)
Attempts to estimate how deeply a small-arms projectile will penetrate into RHA.
Optimized for projectiles near 7.5mm in diameter, works okay for projectiles as small as 5mm or as large as 14mm.
This function is the original work of the author.
ONLY VALID IN BALLISTIC DOMAIN.
Not recommended for masses outside 55..450 grains range,
Not recommended for velocities outside 1200..3500 fps range,
Not recommended for unjacketed lead projectiles.
=over 4
parameter: (float) penetrator mass (in grains)
parameter: (float) penetrator velocity (in feet per second)
parameter: (float) penetrator diameter (in inches)
parameter: (string) penetrator type, describing very approximately the general shape and composition of the projectile. Valid values are:
=over 4
* "hp": Hollowpoint, composed of thin brass lining over lead core.
* "sp": Softpoint (exposed lead tip), composed of thin brass lining over lead core.
* "bp": FMJ "ball", composed of thin brass lining over lead core.
* "ms": Mild steel core, with ogival nose shape.
* "sc": Hard steel core, with truncated-cone nose shape.
* "hc": Synonym for "sc".
* "tc": Tungsten-carbide core (not WHA), with truncated-cone nose shape.
* "wc": Synonym for "tc".
* "wha": Tungsten heavy alloy core (eg, 90% W / 7% Ni / 3% Fe), with truncated-cone nose shape.
* "du": Depleted uranium alloy core (99.25% U / 0.75% Ti), with truncated-cone nose shape.
=back
returns: (float) estimated depth of penetration into RHA (in mm)
=back
=cut
sub pc {
my ($grain, $fps, $diam, $typ, $te) = @_;
return "mm = pc(grains, velocity_fps, diam_inches, {hp,sp,bp,ms,hs,sc,wc,tc,wha,du} [, Te])" unless (defined ($diam));
$te = 1 unless (defined ($te)); # thickness efficiency of target material, relative to RHA
$fps /= 1000;
my $KED = ($grain ** 1.29) * ($fps ** 1.51) / ($diam ** 1.05); # energy density, sorta (fits empirical data)
if ($typ eq 'hp') { $KED /= 2.2; } # hollowpoint lead with gliding material jacket
elsif ($typ eq 'sp') { $KED /= 2.0; } # softpoint lead with gliding material jacket
elsif ($typ eq 'bp') { $KED /= 1.6; } # ballpoint lead with gliding material jacket
elsif ($typ eq 'ms') { $KED *= 1.5; } # mild steel core AP
elsif ($typ eq 'hs') { $KED *= 1.8; } # hard steel core AP
elsif ($typ eq 'sc') { $KED *= 1.8; } # hard steel core AP
elsif ($typ eq 'wc') { $KED *= 3.3; } # tungsten-carbide core AP (not WHA)
elsif ($typ eq 'tc') { $KED *= 3.3; } # tungsten-carbide core AP (not WHA)
elsif ($typ eq 'wha'){ $KED *= 3.5; } # tungsten heavy alloy (WHA) core AP, guesstimate
elsif ($typ eq 'du') { $KED *= 3.7; } # uranium/titanium alloy core AP
my $RHA = $KED / 2785; # estimated depth of penetration of RHA, in mm
$RHA /= $te; # target material specific adjustment
$RHA = int (($RHA * 10) + 0.5) / 10; # this still gives more precision than it deserves
return $RHA;
}
sub sigma {
my $n = scalar(@_);
my $tot = 0;
my $sqs = 0;
my ($avg, $sig);
foreach my $term (@_) { $tot += $term; }
$avg = $tot / $n;
foreach my $term (@_) {
my $dif = abs($term - $avg);
$sqs += $dif * $dif;
}
$sig = ($sqs / $n)**0.5;
return $sig;
}
sub average {
my (@ar) = @_;
my $n = scalar(@ar);
my $sum = 0;
return (0) if ($n < 1);
foreach my $x (@ar) { $sum += $x; }
return $sum / $n;
}
sub rndto {
my ($x, $n) = @_;
my ($ret);
$ret = int(($x / (10**$n)) + 0.5) * (10**$n);
$n = 3 if ($n == 0);
$n *= -1 if ($n < 0);
return $ret . ("0" x ($n - length($1))) if ($ret =~ /\.(\d+)/);
return "$ret." . ("0" x $n);
}
sub r2d {
return 360 * $_[0] / (2 * pi);
}
sub ratios {
my ($base, @rats) = (@_);
my @base_list = split(/\s+/, $base);
my $n = 0;
my @retval = ();
foreach my $r (@rats) {
$n++;
my $name = "set$n";
if ($r =~ /^\s*([a-zA-Z_]+)\s*(.+)/) {
$name = $1;
$r = $2;
}
my @t = split(/\s+/, $r);
for (my $i = 0 ; $i < scalar(@base_list) ; $i++) {
next if ($i >= scalar(@t));
my $base_name = $base_list[$i];
my $base_value = $base_list[$i];
if ($base_name =~ /(.+?)\=(.+)/) {
$base_name = $1;
$base_value = $2;
}
my $ratio = int(1000 * $base_value / $t[$i] + 0.5) / 1000;
$ratio .= ".00" unless ($ratio =~ /\./);
while (length($ratio) < 7) { $ratio .= "0"; }
my $pad = ' ' x (3 - length($t[$i]));
push(@retval, "$name\t$base_name / $pad$t[$i] \t= $ratio");
}
}
return @retval;
}
=head2 poncelet(diameter_mm, mass_grains, velocity_fps, target_shear_strength_mpa, target_density)
Jean-Victor Poncelet was one of the first to attempt mathematical models of
depth of penetration. His formula, developed in the 19th century, attempts
to predict the penetration of bullets into flesh-like materials. It is not
very good, failing to take into account such factors as bullet nose shape,
bullet tumbling within the target, and impacts with bone, horn, or cartilage.
ONLY VALID IN BALLISTIC DOMAIN.
=over 4
parameter: (float) penetrator diameter (in mm)
parameter: (float) penetrator mass (in grains)
parameter: (float) penetrator velocity (in feet per second)
parameter: (float) target material shearing strength (in MPa)
parameter: (float) target density (in g/cc)
returns: (int) depth of penetration (in mm)
=back
=cut
# Old, not very useful formula by Poncelet for predicting depth of penetration into flesh.
sub poncelet {
my ($cal, $mass, $vel, $c0, $c1) = @_;
return 'usage: ponce (cal_mm, mass_grain, vel_fps, targ_shear_MPa, targ_density) = pen_cm' unless(defined($c1));
# c0 = Shearing strength
# c1 = Specific density (water = 1 = 1 g/cc)
$mass /= 15.43; # converting grains to grams
$vel /= 3.28; # converting ft/s to m/s
$c0 /= 145.04; # converting psi to MPa
my $depth_cm = ($mass / (2 * $c1 * 3.141592 * $cal**2 / 4)) * log(($c1 * $vel**2 + $c0) / $c0);
return int($depth_cm * 10 + 0.5); # converting cm to nearest mm, which is still way more precision than this deserves.
}
=head2 te2me (thickness_efficiency, density)
Given the mass efficiency of a material, returns its thickness efficiency.
See the description of me2te() for more explanation.
=over 4
parameter: (float) armor material thickness efficiency (unitless, factor relative to RHA)
parameter: (float) armor material density (g/cc)
returns: (float) armor material mass efficiency (unitless, factor relative to RHA)
=back
=cut
sub te2me { # given thickness efficiency and density, returns mass efficiency
my ($te, $den) = @_;
return $te * 7.86 / $den;
}
1;