# Air along the path

How air density and the speed of sound change with height during the flight.

## Generated table

**Setting:** Air along the path

| Choice | Used by |
|---|---|
| Line of sight (Standard) | Standard |
| Bullet’s real height | Physics, Spin |
| Classic (line of sight, from your altitude) | Classic |
| Classic, cooler air higher up | Custom only |
| Classic, bullet’s real height | Custom only |

## What it does

Air gets thinner as you climb, and thinner air means less drag. This setting decides which height the solver uses for the air at each point of the flight.

- **Line of sight:** the air changes only with the height of the straight line from the rifle to the target. A level shot flies in the same air all the way, even though the bullet arcs above that line.
- **Bullet's real height:** the air is taken at the height the bullet actually reaches on the trajectory you dial: up to the top of the arc and back down, and uphill or downhill.
- **Classic and its variants:** the Classic model has its own rules for altitude. They count height on the line of sight, with a limit on how far below sea level the air keeps getting denser. One variant also lets the speed of sound change with height; another does that too and also uses the bullet's real height, so its speed of sound follows height as well.

## When to choose it

Leave it on the model's own choice unless you are comparing models. The choices differ most on steep shots and on very long flights.

## How to picture it

Draw the shot from the side. Two lines leave the rifle and meet again at the target:

- **The line of sight** is the straight line from the sight to the target. It is level on a level shot, climbs on an uphill shot and drops on a downhill one.
- **The arc** is the path the bullet really flies. The barrel points above the line of sight, so the bullet starts just under it (by the height of the sight over the bore), climbs above it, reaches a top somewhere past the middle and falls back onto it at the target.

At any distance along the line of sight, drop a vertical ruler to a horizontal line drawn through the rifle. Label two heights on it. **Line-of-sight height** is how far the line of sight is above (or below) the rifle there. **Bullet's real height** is how far the bullet is above (or below) the rifle there; it is the line-of-sight height plus the gap between the arc and the line of sight. Shade the background darker toward the bottom and lighter toward the top to show the air thinning with height.

Each value reads the air off that shading at one of the two heights:

| Value | Height it reads the air at |
|---|---|
| `'baseline'`, `'classic'`, `'classic-table'` | the line of sight's |
| `'path'`, `'spinref'` | the bullet's real one |

**Level.** The line of sight stays at the rifle's own height all the way, so the three line-of-sight values never see the air change: the whole flight is in the air measured at the rifle. The arc is not level. On a very long shot it rises far above the rifle, into thinner air with less drag, and only the two real-height values see that. On the diagram, the line of sight stays in one band of shading and the arc crosses several.

**Uphill.** The line of sight itself climbs into thinner air, so every value now sees the air thin out with distance. The real-height values add the arc's extra height on top.

**Downhill.** The line of sight drops into denser air, and the arc's height above it takes some of that back. This is also where the Classic choices part from the baseline. Draw a horizontal dashed line 650 ft below sea level (800 ft for the cooler-air variant, and for all three Classic choices when the temperature-on-slopes setting is on): below it their shading stops getting darker. With that setting on, the speed of sound follows height too. A rifle near sea level firing steeply downhill sends the line of sight through that line part-way to the target, and from there the Classic air stays as it is while the baseline's keeps getting denser. Whether the line of sight reaches the dashed line depends on the site. From a rifle 5,500 ft above sea level, a 10° downhill shot of 3,520 yd ends about 1,800 ft lower (the range times the sine of the slope, computed, not from the table), still about 3,700 ft above sea level and far above the dashed line, so only the shape of the density law separates the Classic values from the baseline there (see On a real shot).

Where the rifle sits on the shading matters only to the Classic choices, which count from the site's altitude above sea level. `'baseline'` and `'path'` use only the height relative to the rifle; `'spinref'` reads the site altitude as the other Classic values do.

## The math

Every value answers the same question: given the air at the rifle and a height $h$, what are the density $\rho$ and the speed of sound $c$ there? They differ in which height is used and in the two formulas.

| Symbol | Meaning | Unit |
|---|---|---|
| $x$ | distance from the sight along the line of sight | m |
| $y$ | the bullet's distance above the line of sight in that pass of the flight, at right angles to it (negative below) | m |
| $\theta$ | inclination of the line of sight, positive uphill | rad |
| $\alpha$ | aim offset: what the pass's flight is raised by on top of $y$. Under `flight` `'dialed'` the barrel is already raised, so $\alpha = 0$; under `'zeroed'` the card is flown with the zero dialed and $\alpha$ supplies the difference (see The algorithm) | rad |
| $h$ | height above the sight at which the air is read | m |
| $A$ | site altitude above sea level; 0 when none is given | m |
| $z_f$ | a value's floor: the lowest altitude at which its air still changes | m |
| $A'$, $z$ | the site's altitude and the altitude of the point at height $h$, after the floor is applied | m |
| $\rho_0$ | drag density of the air at the rifle (set by `airDensity` and `vapour`) | kg/m³ |
| $T_0$ | air temperature at the rifle | K |
| $c_0$ | speed of sound at the rifle (dry or humid, by `soundSpeed`) | m/s |
| $\rho$, $c$ | density and speed of sound at height $h$ | kg/m³, m/s |
| $L$ | standard lapse rate, 0.0065 | K/m |
| $T_s$ | standard sea-level temperature, 288.15 | K |
| $n$ | density exponent, 4.2559 | none |
| $\lambda$ | $L / T_s$, the density law's rate per metre of altitude (the three Classic values) | 1/m |
| $\phi$ | `'path'` only: $\max(1 - L\,h/T_0,\ 0.01)$, the temperature at height $h$ divided by $T_0$ | none |

**The two heights.** The line-of-sight values use

$$h = x \sin\theta$$

and the bullet's-real-height values use

$$h = x \sin\theta + (y + x\,\alpha)\cos\theta$$

On a level shot the first is 0 everywhere. Here $y$ is the height above the line of sight as flown in that pass, and $x\,\alpha$ is the height gained by raising the whole pass by $\alpha$; it is added as written (a shear, not a rotation of $x$). Under `flight` `'dialed'` the barrel itself is raised for each row, so $y$ is already the real one and $\alpha = 0$; under `'zeroed'` the card is flown with the zero dialed and $\alpha$ supplies the difference.

**`'baseline'`.** Height: line of sight.

$$\rho = \rho_0 \left[\max\!\left(1 - \frac{L\,h}{T_s},\ 0.01\right)\right]^{n} \qquad c = c_0$$

The base temperature is the standard 288.15 K whatever the temperature at the rifle. The speed of sound is held constant. No floor.

**`'path'`.** Height: the bullet's real one. With $\phi$ from the table:

$$\phi = \max\!\left(1 - \frac{L\,h}{T_0},\ 0.01\right) \qquad \rho = \rho_0\,\phi^{\,n} \qquad c = c_0\sqrt{\phi}$$

The temperature falls 6.5 K per km from the temperature at the rifle, and both the density and the speed of sound follow it. No floor.

**`'classic'`.** Height: line of sight. Floor $z_f$ = −650 ft = −198.12 m. With $\lambda$ from the table:

$$A' = \max(A,\ z_f) \qquad z = \max(A' + h,\ z_f)$$

$$\rho = \rho_0 \left[\frac{\max(1 - \lambda z,\ 0.01)}{\max(1 - \lambda A',\ 0.01)}\right]^{n} \qquad c = c_0$$

This is the baseline's density ratio taken between two altitudes above sea level, each stopped at the floor. With $A = 0$ and the point above the floor it is exactly the baseline's equation. Once $A' + h$ is below the floor, $z$ stays at $z_f$ and the density stops rising.

**`'classic-table'`.** Height: line of sight. Floor $z_f$ = −800 ft = −243.84 m. $A'$, $z$ and $\rho$ exactly as for `'classic'` with this floor, and

$$c = c_0\sqrt{\max\!\left(1 - \frac{L\,(z - A')}{T_0},\ 0.01\right)}$$

The density keeps the 288.15 K base; the speed of sound lapses from the temperature at the rifle, along the same floored height. When $h = 0$, $z = A'$, so a level shot has the same air as `'classic'`.

**`'spinref'`.** Height: the bullet's real one. Floor $z_f$ = −650 ft = −198.12 m. $A'$, $z$, $\rho$ and $c$ exactly as for `'classic-table'` with this floor and this height.

In every bracket the 0.01 is a guard that keeps the quantity positive; it is reached only at heights far above any shot.

**The temperature taper.** When `tempClamp` is `'classic'`, the three equations above for `'classic'`, `'classic-table'` and `'spinref'` are not used at all. Each of those values keeps its own height $h$ and takes $\rho$ and $c$ from the taper's air, whose equations are on [tempClamp](tempClamp.md) (The math). With the taper on, the three values differ only in the height they use, so `'classic'` and `'classic-table'` give identical air; the floor is −800 ft for all three; and the speed of sound always follows the temperature. `'baseline'` and `'path'` ignore `tempClamp`.

## The algorithm

One function turns the air at the rifle and a height into the air at that height. Its branches, in the order the code tests them:

```text
airAt(air, h, lapse, sound, tempClamp) -> (rho, c)
  in:  air    the air at the rifle: rho0 (kg/m3), T0 (K), c0_dry and c0_moist (m/s), alt (m, 0 if not given)
       h      height above the sight (m), chosen by the caller
       lapse  'baseline' | 'path' | 'classic' | 'classic-table' | 'spinref'   (default 'baseline')
       sound  'dry' | 'moist'                                                  (default 'dry')
       tempClamp  'off' | 'classic'                                            (default 'off')
  out: rho (kg/m3), c (m/s)

  c0 = c0_moist if sound == 'moist' else c0_dry

  1. if tempClamp == 'classic' and lapse is 'classic', 'classic-table' or 'spinref':
         return classicTaperAir(air, h, c0)

  2. if lapse == 'baseline':
         fi = max(1 - 0.0065*h/288.15, 0.01)
         return (rho0 * fi^4.2559, c0)

  3. if lapse is 'classic', 'classic-table' or 'spinref':
         floor = -198.12 for 'classic', -243.84 for 'classic-table', -198.12 for 'spinref'    (m)
         A   = max(alt, floor)
         lam = 0.0065/288.15
         at  = max(A + h, floor)
         rho = rho0 * ( max(1 - lam*at, 0.01) / max(1 - lam*A, 0.01) )^4.2559
         if lapse == 'classic': return (rho, c0)
         return (rho, c0 * sqrt(max(1 - 0.0065*(at - A)/T0, 0.01)))

  4. otherwise ('path'):
         f = max(1 - 0.0065*h/T0, 0.01)
         return (rho0 * f^4.2559, c0 * sqrt(f))
```

Branch 1 hands the air to the temperature taper; its steps are on [tempClamp](tempClamp.md) (The algorithm).

**Where it is called.** The flight is integrated in a frame whose first axis runs along the line of sight, by a fourth-order Runge-Kutta step (0.001 s unless changed). Each of the step's four evaluations of the bullet's acceleration works out the height and calls `airAt`:

```text
onPath = pathHeight(lapse)                 // true for 'path' and 'spinref'
h = x*sin(theta)                                        if not onPath
    x*sin(theta) + (y + x*aim)*cos(theta)               if onPath
(rho, c) = airAt(air, h, lapse, sound, tempClamp)
mach = speed / c                           // picks the drag coefficient; speed is the speed as windDrag defines it
drag acceleration = -k * rho * Cd(mach) * speed * (velocity - wind)    // k: a constant of the bullet
```

Before the loop, `rho0` is set to the drag density that `airDensity` selects, so the taper's deviation is worked out from that density. `airAt` is called again once for each range asked for, at the height the bullet (or the line of sight) has there, to report the Mach number (the ground speed over `c`, under both `windDrag` values); and once at height 0 for the muzzle Mach number when the Spin model's modified point-mass dynamics run. The zeroing flight uses the same call with the zero's own air and slope and `aim` = 0.

**How `aim` is found.** The card is first flown with the zero dialed, so its arc sits lower than the arc of a shot dialed for a far target. For `'path'` and `'spinref'` with `flight` at `'zeroed'`, the whole card is flown again at six fixed values of `aim` spanning the card's elevations, each row is interpolated linearly in `aim`, and the row's `aim` is repeated (at most six times, to within 1e-7 rad) until it equals the elevation that row needs, −y / range. The line-of-sight values never read `aim`.

## On a real shot

Read from the first table below (every number in this paragraph is copied from it); the geometry behind each case is in How to picture it. The shot is fired from a site 5,500 ft above sea level, and the three Classic values count from that altitude. On the two level shots `'classic'` and `'classic-table'` show 0.000 / 0.000 / 0.0, like the reference row (`'baseline'`): the line of sight does not change height, so their density ratio is 1 and, with no change in height, the speed of sound has nothing to follow. The two values that read the bullet's real height need less elevation firing north, -0.260 mil for `'path'` and -0.271 mil for `'spinref'`, with the bullet arriving +1.7 fps (`'path'`) and +1.8 fps (`'spinref'`) faster. On the slopes the Classic values differ from the reference row by only a few hundredths of a mil, in opposite directions: 10° uphill `'classic'` needs -0.043 mil and 10° downhill +0.041 mil. The floor does not act in this table. A 10° downhill shot of 3,520 yd drops the line of sight about 1,800 ft below the rifle, to about 3,700 ft above sea level, and the floor is 650 ft below sea level, so the density never stops rising and the floor does not enter. What remains is the shape of the density ratio: the reference row counts height from the rifle and uses the sea-level rate of thinning whatever the site's altitude, while the Classic value takes the ratio between two absolute altitudes, at the site's real altitude, where the air thins slightly faster with height, so the line of sight meets slightly less air uphill and slightly more downhill. `'classic-table'` adds a speed of sound that follows height, which pulls the elevation back toward zero on both slopes: -0.033 mil uphill and +0.024 mil downhill, with arrival velocity -2.2 fps uphill and +2.3 fps downhill. `'spinref'` combines that speed of sound with the bullet's real height: -0.301 mil uphill and -0.225 mil downhill. The floor still matters for a low site: a rifle near sea level firing steeply downhill does reach it, and there the Classic values part from the reference row by a much larger amount (this table, at a high site, does not show that).

The first table changes only this one setting on the Standard model. The Classic model also turns on temperature on slopes (`tempClamp`), which replaces the air of the three classic values, so the `'classic'` row of the first table is not what the Classic model as a whole computes. The second table shows the Classic model as a whole: the other settings are its own, and the reference row is `'classic'`. Read it as follows (every number is copied from it). With the temperature taper in force the three classic values differ only in the height they read, so `'classic'` and `'classic-table'` are the same air: the `'classic-table'` row is 0.000 / 0.000 / 0.0 in every column. `'spinref'` reads the bullet's real height and changes the elevation by -0.260 mil on both level shots, with the bullet arriving +1.7 fps faster; on both slopes the change is -0.258 mil. The Standard value `'baseline'` is 0.000 / 0.000 / 0.0 on the level shots here and needs less elevation than `'classic'` on both slopes: -0.012 mil uphill and -0.070 mil downhill.

**Changing only this setting on the Standard model**

The shot: a 350 gr 0.375 in bullet at 3048 fps muzzle velocity, fired at 3520 yd in air of 60 °F, 40 % humidity, 24.43 inHg at the firing line, latitude 42.1°, wind 10 mph from the right (90° to the line of fire), the same wind in every column; site altitude 5,500 ft. In the app, type it as "Site altitude" (shown when the profile's model reads one); left blank, the classic values count from sea level and can differ from this table. All other settings are the Standard model's. In the first column (North, level) the reference arc reaches 223 ft above the line of sight at 2160 yd.

| Value | Shown in the app as | North, level | East, level | North, 10° uphill | North, 10° downhill |
|---|---|---|---|---|---|
| `'baseline'` | Line of sight (Standard) | reference | reference | reference | reference |
| `'path'` | Bullet’s real height | -0.260 / -0.018 / +1.7 | -0.255 / -0.018 / +1.7 | -0.246 / -0.013 / -0.9 | -0.258 / -0.023 / +4.4 |
| `'classic'` | Classic (line of sight, from your altitude) | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 | -0.043 / -0.003 / +0.5 | +0.041 / +0.003 / -0.5 |
| `'classic-table'` | Classic, cooler air higher up | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 | -0.033 / +0.002 / -2.2 | +0.024 / -0.002 / +2.3 |
| `'spinref'` | Classic, bullet’s real height | -0.271 / -0.019 / +1.8 | -0.265 / -0.019 / +1.8 | -0.301 / -0.017 / -0.3 | -0.225 / -0.020 / +3.9 |

Each cell is the change from the reference row (`'baseline'`) in the same shot, as elevation (mil) / windage (mil) / velocity at the target (fps). Elevation: plus means more elevation must be dialed. Windage: plus means the windage correction moves to the right (dial further right); this is a correction, not where the bullet lands. Velocity: plus means the bullet arrives faster. A zero means no difference at the shown precision.

**Each value under the Classic model's other settings (including temperature on slopes)**

The shot: a 350 gr 0.375 in bullet at 3048 fps muzzle velocity, fired at 3520 yd in air of 60 °F, 40 % humidity, 24.43 inHg at the firing line, latitude 42.1°, wind 10 mph from the right (90° to the line of fire), the same wind in every column; site altitude 5,500 ft. In the app, type it as "Site altitude" (shown when the profile's model reads one); left blank, the classic values count from sea level and can differ from this table. All other settings are the Classic model's. In the first column (North, level) the reference arc reaches 223 ft above the line of sight at 2160 yd.

| Value | Shown in the app as | North, level | East, level | North, 10° uphill | North, 10° downhill |
|---|---|---|---|---|---|
| `'baseline'` | Line of sight (Standard) | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 | -0.012 / -0.007 / +2.8 | -0.070 / -0.001 / -0.9 |
| `'path'` | Bullet’s real height | -0.260 / -0.016 / +1.7 | -0.260 / -0.016 / +1.7 | -0.258 / -0.016 / +1.7 | -0.328 / -0.024 / +3.4 |
| `'classic'` | Classic (line of sight, from your altitude) | reference | reference | reference | reference |
| `'classic-table'` | Classic, cooler air higher up | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 | 0.000 / 0.000 / 0.0 |
| `'spinref'` | Classic, bullet’s real height | -0.260 / -0.016 / +1.7 | -0.260 / -0.016 / +1.7 | -0.258 / -0.016 / +1.7 | -0.258 / -0.017 / +1.7 |

Each cell is the change from the reference row (`'classic'`) in the same shot, as elevation (mil) / windage (mil) / velocity at the target (fps). Elevation: plus means more elevation must be dialed. Windage: plus means the windage correction moves to the right (dial further right); this is a correction, not where the bullet lands. Velocity: plus means the bullet arrives faster. A zero means no difference at the shown precision.

---

[All reference pages](../index.md)
