# Particle size distributions
A radar observable is an integral over the number concentration of
scatterers per unit volume per unit diameter, $N(D)$. `rustmatrix.psd`
provides the standard analytical forms plus a generic binned
distribution, all compatible with `PSDIntegrator`'s cached
tabulation.
## Exponential (Marshall–Palmer)
{cite}`MarshallPalmer1948` observed that stratiform rain drop-size
distributions are well approximated by
$$
N(D) = N_0 \exp(-\Lambda D),
$$
with $N_0 \approx 8000$ mm⁻¹ m⁻³ and $\Lambda$ set by the rain rate.
The two-parameter exponential is the simplest non-trivial PSD and is
wired up as `psd.ExponentialPSD(N0=..., Lambda=...)`.
Use it when you want a tractable stress test — it has no free shape
parameter, so convergence and band dependence are easy to isolate.
The [radar-band sweep tutorial](../tutorials/05_radar_band_sweep)
uses it for exactly that reason.
## Gamma (Ulbrich)
Real rain spectra show a roll-off at small diameters that the
exponential cannot capture. {cite}`Ulbrich1983` proposed
$$
N(D) = N_0 D^\mu \exp(-\Lambda D),
$$
adding a shape parameter $\mu$ — positive for convective rain,
negative for drizzle-dominated distributions. Implemented as
`psd.UnnormalizedGammaPSD(N0, mu, Lambda)`.
The three Ulbrich parameters are strongly correlated across rain
events, so `rustmatrix` also provides the *normalised* form below
which disentangles concentration from shape.
## Normalised gamma (Testud / Bringi–Chandrasekar)
The normalised-gamma PSD {cite}`Testud2001,BringiChandrasekar2001` is
parameterised by quantities that are roughly independent across rain
events:
* $D_0$ — median volume diameter (mm),
* $N_w$ — normalised intercept, constant for a Marshall–Palmer
distribution,
* $\mu$ — dimensionless shape parameter.
$$
N(D) = N_w \, f(\mu) \, \left(\frac{D}{D_0}\right)^\mu
\exp\!\left[-(3.67 + \mu)\,\frac{D}{D_0}\right],
$$
where $f(\mu)$ is a normalisation that keeps $N_w$ fixed across
$\mu$. This is the form used in the
[gamma-PSD rain tutorial](../tutorials/03_psd_gamma_rain) and
throughout the operational-radar literature. Constructed as
`psd.GammaPSD(D0=..., Nw=..., mu=...)`.
## Binned / empirical
For disdrometer observations, reanalysis output, or any case where
you have $N$ in arbitrary diameter bins, use
`psd.BinnedPSD(bin_edges, N)` — it interpolates linearly within bins
and evaluates to zero outside. The standard `PSDIntegrator` machinery
works unchanged.
## Numerical integration
`psd.PSDIntegrator`:
1. On `init_scatter_table(s)`, evaluates $\mathbf{S}(D)$ and
$\mathbf{Z}(D)$ at `num_points` diameters between $D_\min$ and
$D_\max$. This is the parallel Rust kernel — the only expensive
step.
2. For each PSD assigned to `s.psd`, integrates the cached tables
against $N(D)$ by trapezoidal rule.
3. Any number of different PSD shapes can be evaluated from the same
cached table — swap `s.psd = psd.GammaPSD(...)` and re-read the
observables at a cost near zero.
Tips:
* **`D_max`**: set a few times the expected largest drop. Too small
truncates the tail and under-estimates $Z_h$ at C-band and below;
too large wastes quadrature points on near-zero contributions.
* **`num_points`**: 64 is almost always enough for rain; oriented ice
at the Mie-resonance bands may want 128.
* **`geometries`**: pass both back-scatter and forward-scatter in the
same tuple so the table is built once for all observables you need.
## Further reading
* {cite}`BringiChandrasekar2001`, chapter 7 — the canonical treatment
of PSD retrieval from polarimetric radar.
* {cite}`Testud2001` — the original normalised-gamma paper.
* [The gamma-PSD tutorial](../tutorials/03_psd_gamma_rain) — shows
$Z_h, Z_{dr}, K_{dp}, A_i$ as functions of rain rate over an
ensemble of $D_0, N_w, \mu$.
```{bibliography}
:filter: docname in docnames
```