Equations

Every numbered equation of Miller et al. (2017), in the form this package implements: the 26 February 2020 erratum for Eqs. 7, 21, 22, 24 and 25, and the three prose-based corrections argued out in Deviations, each flagged below.

Brightness temperatures are written \(T_{\lambda}\) for the band centred near \(\lambda\) µm; \(\theta\) is the solar zenith angle.

The normalization primitive

Almost every test is a clipped linear ramp between a MIN and a MAX bound (Eq. 3), which is where the tuning constants enter:

\[ N(x; x_{\min}, x_{\max}) = \operatorname{clip}\!\left( \frac{x - x_{\min}}{x_{\max} - x_{\min}},\; 0,\; 1 \right) \]

MIN may exceed MAX, which reverses the ramp; the cos-zenith blends below rely on that. → shachen.norm.normalize()

Clear-sky background (§3.2)

The dynamic background separates DEBRA from a fixed-threshold test. It is estimated by one of two schemes.

Scheme A, semi-analytic. Surface emissivity \(\varepsilon_\lambda\) modifies the Planck radiance of the reanalysis skin temperature, inverted back to a brightness temperature:

\[ T^{\text{bg}}_{\lambda} = B^{-1}\!\left(\lambda,\; \varepsilon_\lambda \, B(\lambda, T_{\text{skin}})\right), \qquad B(\lambda, T) = \frac{c_1 / \lambda^{5}}{\exp\!\left(c_2 / \lambda T\right) - 1} \]

with \(c_1 = 2hc^2\) and \(c_2 = hc/k\). Missing emissivity (ocean) is treated as \(\varepsilon = 1\), which makes the transform the identity. → shachen.background.background_signals()

Scheme B, cloud-cleared composite. Over a stack of \(n\) same-time-of-day scenes, take the warmest window pixel and read all three bands from that same day \(d^*\). Clouds are cold, so the warmest day is taken as the clear-sky estimate:

\[ d^{*} = \operatorname*{arg\,max}_{d \in \mathcal{C}} \; T_{10.4}^{(d)}, \qquad T^{\text{bg}}_{\lambda} = T_{\lambda}^{(d^{*})} \]

where \(\mathcal{C}\) is the set of days finite in all three bands at that pixel. → shachen.composite.composite_background()

Either way, the two background signals fed to the dust tests are

\[ \mathrm{RSW}_{\text{bg}} = T^{\text{bg}}_{12.3} - T^{\text{bg}}_{10.4}, \qquad \mathrm{BTD}_{\text{bg}} = T^{\text{bg}}_{8.6} - T^{\text{bg}}_{10.4} \]

Cloud mask (Eqs. 1–12)

Four continuous cloud tests, damped by two dust-restoral terms so that dust is not masked away as cloud. → shachen.cloudmask.cloud_mask()

\begin{align*} \mathrm{CM1} &= 1 - N(T_{10.4};\; T_{\text{skin}} - 50,\; T_{\text{skin}}) & &\text{(Eqs. 1–2, cold relative to skin)} \\ \mathrm{CM2} &= 1 - N(T_{10.4} - T_{6.2};\; 0,\; 25) & &\text{(Eq. 4, deep convection)}^{\dagger} \\ \mathrm{CM3} &= N(T_{10.4} - T_{12.3};\; 2.0,\; 4.5) & &\text{(Eq. 5, thin cirrus, day + night)} \\ \mathrm{CM4} &= N(T_{3.9} - T_{10.4};\; 5.0,\; 8.0) & &\text{(Eq. 6, thin cirrus, night only)} \end{align*}

The restoral terms: a pixel that looks like dust in the reverse split window subtracts from the cloud confidence.

\begin{align*} R_1 &= N(T_{12.3} - T_{10.4};\; 0,\; 3.5)\,(1 - \mathrm{CM1}) & &\text{(Eq. 7, erratum)} \\ R_2^{\text{day}} &= N(T_{8.6} - T_{10.4};\; -1,\; 3)\, (1 - \mathrm{CM2})(1 - \mathrm{CM3}) & &\text{(Eq. 8)} \\ R_2^{\text{ngt}} &= N(T_{8.6} - T_{10.4};\; -1,\; 3)\, (1 - \mathrm{CM2})(1 - \mathrm{CM4}) & &\text{(Eq. 9)} \end{align*}

Combined, then put on a common scale:

\begin{align*} \mathrm{CM}^{\text{ngt}} &= (\mathrm{CM1} + \mathrm{CM2} + \mathrm{CM4}) \left(1 - \max(R_1, R_2^{\text{ngt}})\right) & &\text{(Eq. 10)} \\ \mathrm{CM}^{\text{day}} &= (\mathrm{CM1} + \mathrm{CM2} + \mathrm{CM3}) \left(1 - \max(R_1, R_2^{\text{day}})\right) & &\text{(Eq. 11)}^{\ddagger} \\ \mathrm{CM}_{\text{norm}} &= N(\mathrm{CM};\; 0.45,\; 0.80) & &\text{(Eq. 12)} \end{align*}

\(^\dagger\) Eq. 4 is implemented magnitude-reversed; as printed it saturates the mask over clear sky. \(^\ddagger\) Eq. 11 uses CM3 in place of the misprinted CM4: the 3.9 µm test is night-only. Both are argued in Deviations.

Dust tests (Eqs. 13–15)

DT1 and DT2 are the same ramp as Eq. 3 with the per-pixel background as the MIN bound; that substitution is what makes the test dynamic. Writing the observed signals \(\mathrm{RSW} = T_{12.3} - T_{10.4}\) and \(\mathrm{BTD} = T_{8.6} - T_{10.4}\):

\begin{align*} \mathrm{DT1} &= \operatorname{clip}\!\left( \frac{\mathrm{RSW} - \mathrm{RSW}_{\text{bg}}} {3.5 - \mathrm{RSW}_{\text{bg}}},\; 0,\; 1 \right) & &\text{(Eq. 13)} \\ \mathrm{DT2} &= \operatorname{clip}\!\left( \frac{\mathrm{BTD} - \mathrm{BTD}_{\text{bg}}} {3.0 - \mathrm{BTD}_{\text{bg}}},\; 0,\; 1 \right) & &\text{(Eq. 14)} \end{align*}

DT3 is the thermal-contrast test, implemented magnitude-reversed per the paper’s prose (“observations that are relatively cold compared to MERRA produce high value for DT3”):

\[ \mathrm{DT3} = \operatorname{clip}\!\left( \frac{(T_{\text{MERRA}} - S) - T_{10.4}}{50},\; 0,\; 1 \right), \qquad S = \begin{cases} -10\ \mathrm{K} & \text{land} \\ +5\ \mathrm{K} & \text{ocean} \end{cases} \]

shachen.dust_tests.dust_tests()

Confidence factor (Eqs. 16–22)

Three illumination regimes, each suppressed by the matching cloud mask. Night drops to \(\max(\mathrm{DT1}, \mathrm{DT2})\) because the two split-window tests stop being independent without solar heating. → shachen.confidence.confidence()

\begin{align*} \mathrm{CF}^{*}_{\text{day}} &= (\mathrm{DT1} + \mathrm{DT2} + \mathrm{DT3}) \left(1 - \mathrm{CM}^{\text{day}}_{\text{norm}}\right) & &\text{(Eq. 16)} \\ \mathrm{CF}^{*}_{\text{trm}} &= (\mathrm{DT1} + \mathrm{DT2} + \tfrac{1}{2}\mathrm{DT3}) \left(1 - \mathrm{CM}^{\text{day}}_{\text{norm}}\right) & &\text{(Eq. 17)} \\ \mathrm{CF}^{*}_{\text{ngt}} &= \left(\max(\mathrm{DT1}, \mathrm{DT2}) + \tfrac{1}{2}\mathrm{DT3}\right) \left(1 - \mathrm{CM}^{\text{ngt}}_{\text{norm}}\right) & &\text{(Eq. 18)} \\ \mathrm{CF} &= N(\mathrm{CF}^{*};\; 0.25,\; 2.50) & &\text{(Eq. 19)} \end{align*}

The terminator is crossed smoothly, with weights evaluated in cosine-zenith space:

\begin{align*} B_{\text{ngt}}^{\text{trm}} &= N(\cos\theta;\; \cos 105^{\circ},\; \cos 90^{\circ})^{1.5} & &\text{(Eq. 20)} \\ B_{\text{trm}}^{\text{day}} &= N(\cos\theta;\; \cos 90^{\circ},\; \cos 75^{\circ})^{1.5} & &\text{(Eq. 21, erratum)} \end{align*}
\begin{equation*} \mathrm{CF}_{\text{comb}} = B_{\text{trm}}^{\text{day}}\,\mathrm{CF}_{\text{day}} + \left(1 - B_{\text{trm}}^{\text{day}}\right) \left[ B_{\text{ngt}}^{\text{trm}}\,\mathrm{CF}_{\text{trm}} + \left(1 - B_{\text{ngt}}^{\text{trm}}\right)\mathrm{CF}_{\text{ngt}} \right] \tag{Eq. 22, erratum} \end{equation*}

\(\mathrm{CF}_{\text{comb}} \in [0, 1]\) is the algorithm’s output field.

Enhanced imagery (Eqs. 23–29)

A greyscale baseline image, blended day-to-night, then modulated by the confidence factor in each colour gun. Domain min/max are taken over the whole scene, skipping NaN. → shachen.imagery.debra_imagery()

\begin{align*} \mathrm{VIS}_{\text{bg}} &= \frac{\rho - \rho_{\min}}{\rho_{\max} - \rho_{\min}} & &\text{(Eq. 23)} \\ \mathrm{IR}_{\text{bg}} &= 1 - \frac{T_{10.4} - T_{\min}}{T_{\max} - T_{\min}} & &\text{(Eq. 24, erratum)} \\ B_{\text{bg}} &= 1 - N(\theta;\; 79^{\circ},\; 89^{\circ})^{1.5} & &\text{(Eq. 25, erratum)} \\ \mathrm{BI} &= B_{\text{bg}}\,\mathrm{VIS}_{\text{bg}} + \left(1 - B_{\text{bg}}\right)\mathrm{IR}_{\text{bg}} & &\text{(Eq. 26)} \end{align*}

Eq. 25 is evaluated in zenith degree space, unlike the cos-space Eqs. 20–21. Each gun then gets the same form, differing only in the coefficient \(D_G\) applied to the confidence factor:

\[ G = N\!\left(\mathrm{BI}\left(1 - \min(\mathrm{CF}_{\text{comb}}, 0.5)\right) + D_G\,\mathrm{CF}_{\text{comb}};\; 0,\; 1.2\right), \qquad G \in \{R, G, B\} \]

The printed Eqs. 27–29 are \(D_R = D_G = 1\) and \(D_B = 0.10\), which paints dust yellow. The paper’s §4.2 alternatives are generalised in shachen.constants.COLOR_DIMMING:

Preset

\((D_R, D_G, D_B)\)

yellow (Eqs. 27–29)

\((1.0,\ 1.0,\ 0.10)\)

pink

\((1.0,\ 0.25,\ 0.25)\)

green

\((0.10,\ 1.0,\ 0.10)\)

blue

\((0.25,\ 0.25,\ 1.0)\)

The \(\min(\mathrm{CF}, 0.5)\) cap keeps dust translucent: even at full confidence, half the underlying scene still shows through.