======================= Calibration Equation ======================= This page presents the final calibration formula that produces antenna temperature :math:`T_A^*` from raw counts. The Calibration Equation ------------------------ For each spectral channel :math:`\nu`, dump :math:`d`, receiver :math:`r`, array :math:`a`, and subscan :math:`s`: .. math:: T_A^*(\nu, d, r, a, s) = \frac{\big(C_{ON}(\nu,d,r,a,s) - C_{REF}(\nu,r,a,s)\big) \cdot \gamma(\nu,r,a)} {\big(C_{hot}(\nu,r,a) - C_{cold}(\nu,r,a)\big) \cdot t_r^{sig}(\nu)} where: - :math:`C_{ON}` — raw counts from the ON-source subscan - :math:`C_{REF}` — reference counts (mode-dependent, see :doc:`observation-modes`) - :math:`\gamma` — gain calibration factor (see :doc:`calibration-loads`) - :math:`C_{hot}, C_{cold}` — mean HOT/COLD load counts - :math:`t_r^{sig}` — signal sideband atmospheric transmission (see :doc:`atmosphere`) Atmospheric Correction ~~~~~~~~~~~~~~~~~~~~~~ Only the **signal sideband** transmission is applied in the denominator. The image sideband contribution is already accounted for in :math:`\gamma` through the sideband gain weighting :math:`(g_s x_s + g_i x_i)`. This is the standard single-sideband (SSB) calibration convention. **Implementation:** ``cal-core/src/calibrate.rs`` → ``calibrate_full()`` Vectorized Implementation -------------------------- The inner loop precomputes a combined factor to minimise per-element operations: .. math:: F(\nu, r, a) = \frac{\gamma(\nu, r, a)} {\big(C_{hot}(\nu, r, a) - C_{cold}(\nu, r, a)\big) \cdot t_r^{sig}(\nu)} Then the calibration reduces to: .. math:: T_A^*(\nu, d, r, a, s) = \big(C_{ON}(\nu,d,r,a,s) - C_{REF}(\nu,r,a,s)\big) \cdot F(\nu, r, a) Loop order is ``C → R → A → D → S`` for row-major cache-friendly access, with the innermost loop (S) achieving stride-1 memory access on the subscan axis. System Temperature ------------------ The system temperature includes receiver noise, load coupling, and atmospheric contributions: .. math:: T_{sys} = T'_{rec} + T'_{hot} + (1 - f_{amb}) \Big[ g_s x_s \cdot T_{hot,eff}^{sig} \cdot \big(a_s (1 - t_r^{sig}) - 1\big) + g_i x_i \cdot T_{hot,eff}^{img} \cdot \big(a_i (1 - t_r^{img}) - 1\big) \Big] :math:`T_{sys}` is computed per channel, per pixel, per subscan and written to the L1 output. **Implementation:** ``cal-core/src/math/temperature.rs`` → ``tsys_formula()`` Flag Propagation ---------------- The calibration stage propagates flags from the bad channel mask (bit 0 = ``BAD_CHANNEL``) to the output ``flags`` array. All dumps and subscans for a flagged channel receive the flag. The corresponding spectral values are set to ``NaN``. See :doc:`/source/developer/flag-system` for the complete flag architecture. Output: CalibrationResult -------------------------- The calibration produces a ``CalibrationResult`` containing: .. list-table:: :header-rows: 1 :widths: 25 20 55 * - Field - Shape - Description * - ``spectra`` - [C, D, R, A, S] - Calibrated :math:`T_A^*` (K) * - ``t_sys`` - [C, R, A, S] - System temperature (K) * - ``t_int`` - [S] - Integration time (s) * - ``t_rec_ssb`` - [C, R, A] - Receiver temperature SSB (K) * - ``gamma`` - [C, R, A] - Gain factor * - ``tau_signal`` - [C] - Zenith opacity, signal (Np) * - ``tau_image`` - [C] - Zenith opacity, image (Np) * - ``t_sky`` - [C, R, A] - Sky contribution (K) * - ``flags`` - [C, D, R, A, S] - u16 quality bitmask * - ``signal_freqs`` - [C] - Signal frequencies (Hz) * - ``image_freqs`` - [C] - Image frequencies (Hz) * - ``pwv`` - scalar - Fitted PWV (mm) Plus scan metadata (source, mode, arrays, pixel names, strategies). QA Metrics ---------- Quality metrics are computed per scan and stored as L1 attributes: - Mean and median :math:`T_{sys}` across channels - Fraction of flagged channels - PWV convergence information **Implementation:** ``cal-core/src/qa.rs`` → ``QaMetrics``