Module recoil

Module recoil 

Source
Expand description

SAAMI free-recoil calculator (MBA-1372).

Source: SAAMI “Gun Recoil - Technical” (Rev. 7/9/2018), the Sporting Arms and Ammunition Manufacturers’ Institute’s freely downloadable momentum-balance formula: https://saami.org/wp-content/uploads/2025/03/Gun-Recoil-Formulae-2018-07-9.pdf

§The physics

Recoil is conservation of momentum: the momentum of the free-recoiling firearm is equal and opposite to the momentum of everything that leaves the muzzle – the bullet plus the propellant gas. SAAMI’s document equates the propellant gas mass to the powder charge weight (“because the propellant gases are extremely difficult to weigh”), giving:

firearm_mass * V_recoil = bullet_mass * V_muzzle + charge_mass * V_gas

and free recoil energy is then simply 0.5 * firearm_mass * V_recoil^2.

§Gas-velocity convention (a deliberate modelling choice, not an implementation detail)

The propellant gas leaves the muzzle faster than the bullet, but its true velocity is hard to measure directly. Two conventions are in circulation:

  1. SAAMI’s own type-keyed multiplier (page 2 of the source PDF): V_gas = f * V_muzzle, with f sourced from 1929-era British ballistic testing and keyed to firearm class: high-powered rifle f = 1.75, pistol/revolver f = 1.50, average-length shotgun f = 1.50, long-barrel shotgun f = 1.25.
  2. A fixed constant (commonly ~4700 fps / ~1433 m/s for smokeless powder), popularized by several reloading references, independent of muzzle velocity.

This module defaults to the SAAMI type-keyed factor (GasVelocityModel::Saami) rather than the fixed constant, because: it is the cited, auditable industry-standard source with a worked example we reproduce in the tests below; it scales with muzzle velocity, so it stays physically sane across drastically different loads (a fixed constant over-states gas momentum for a slow subsonic load and under-states it for a magnum); and it is keyed to firearm class the way the industry actually publishes it. The fixed-velocity model is still exposed (GasVelocityModel::Fixed) for callers who want to reproduce that older convention or plug in a chronographed gas velocity – “expose both,” per the brief, rather than silently picking one and hiding the other.

§Units

free_recoil takes and returns pure SI (kg, m/s, J, N*s) – the same internal convention cli_api/the rest of this crate uses; CLI/WASM front ends convert to/from display units (imperial: grains for bullet/charge, pounds for firearm weight, fps; metric: grams, kilograms, m/s).

Note this deliberately differs from SAAMI’s own metric appendix (page 4 of the source PDF), which divides a weight-in-kilograms by g = 9.8 to produce energy in legacy “kilogram-meters” (kgf*m) rather than joules. This crate already treats every other mass input (bullet grams/grains, in cli_api) as a true SI mass rather than a gravity-dependent “weight,” so free_recoil performs genuine F = m*a physics in kg/m/s/J throughout. No g factor is needed for the recoil velocity at all (it cancels in the momentum ratio – see the SAAMI PDF’s own algebra, page 1); g only ever entered SAAMI’s imperial derivation to convert weight (pounds) to mass (slugs) for the energy step, which plain kilograms sidesteps entirely. The tests below confirm this reproduces the SAAMI worked example (page 3) to within its own rounding.

Structs§

FreeRecoilInputs
SI inputs (kg, m/s) to free_recoil.
FreeRecoilResult
Free recoil result, SI units throughout.

Enums§

FirearmType
Firearm type, selecting SAAMI’s empirical propellant-gas-velocity multiplier f (V_gas = f * V_muzzle). See the module docs for the source and rationale.
GasVelocityModel
How the propellant gas velocity (SAAMI’s V_PG) is resolved from the muzzle velocity. See the module docs for why the SAAMI type-keyed factor is the default.

Constants§

POUNDS_TO_KG
Avoirdupois pound in kilograms, exact by definition (1 lb = 0.45359237 kg). Used to convert firearm weight (pounds, imperial units) to the SI mass free_recoil needs – the only pound-denominated input in this crate (bullet/charge weight use grains, via constants::GRAINS_TO_KG).

Functions§

free_recoil
SAAMI free-recoil momentum balance (see module docs): firearm_mass * V_recoil = bullet_mass * V_muzzle + charge_mass * V_gas, FRE = 0.5 * firearm_mass * V_recoil^2, impulse = firearm_mass * V_recoil.