=================
Observation Modes
=================
Different observing strategies require different reference selection
and data preparation. This page describes the supported modes and how
to add new ones.
Mode Detection
--------------
The engine auto-detects the observation mode from the data:
1. Check the ``instmode`` attribute (e.g., ``"OTF"``)
2. Examine ``sobsmode`` strings across subscans
3. Fall back to ``TotalPower`` if ambiguous
This can be overridden with ``--mode otf`` or ``--mode totalpower``
on the command line.
**Implementation:** ``cal-core/src/config.rs`` → ``ObsMode`` enum
Supported Modes
---------------
TotalPower
~~~~~~~~~~
Single-point position-switched observations with discrete ON/OFF pairs.
.. mermaid::
graph LR
OFF1[OFF] --> ON1[ON]
ON1 --> OFF2[OFF]
OFF2 --> ON2[ON]
ON2 --> OFF3[OFF]
style OFF1 fill:#bbdefb
style OFF2 fill:#bbdefb
style OFF3 fill:#bbdefb
style ON1 fill:#c8e6c9
style ON2 fill:#c8e6c9
- **ON subscans:** single dump per pointing
- **Reference:** nearest-time OFF (first dump only)
- **Matching:** each ON is paired with the temporally closest OFF by MJD
**Implementation:** ``cal-core/src/modes/totalpower.rs``
OTF TotalPower
~~~~~~~~~~~~~~
On-the-fly scanning where multiple dumps trace a path across the source.
.. mermaid::
graph LR
OFF1[OFF] --> OTF1[OTF-ON
D dumps]
OTF1 --> OFF2[OFF]
OFF2 --> OTF2[OTF-ON
D dumps]
OTF2 --> OFF3[OFF]
style OFF1 fill:#bbdefb
style OFF2 fill:#bbdefb
style OFF3 fill:#bbdefb
style OTF1 fill:#c8e6c9
style OTF2 fill:#c8e6c9
- **ON subscans:** multiple dumps along scan direction (D > 1)
- **Reference:** nearest-time OFF, averaged over all dumps (NaN-aware)
- **OTF coordinates:** ``otf_lon`` and ``otf_lat`` are propagated
to the output as ``[D, S]`` arrays
**Implementation:** ``cal-core/src/modes/otf.rs``
Data Preparation
----------------
**File:** ``cal-core/src/modes/prepare.rs``
The preparation phase decouples reference selection from calibration
math, enabling vectorized processing:
1. Identify ON subscan indices from ``sobsmode``
2. For each ON, find the nearest-time OFF by MJD
3. Deduplicate OFF references (compute average once, reuse for all ONs
sharing the same reference)
4. Build ``ref_data[C, R, A, S_on]`` from deduplicated OFF averages
5. Compute integration time ``t_int[S_on]``
The ON data is **not copied** — ``PreparedData`` stores indices into
``ScanData.data``, and the calibration loop reads from there directly.
This avoids a ~1 GB allocation for large OTF datasets.
Future Modes
------------
The ``ObsMode`` enum includes placeholders for:
- **FrequencySwitch** — reference from frequency-shifted spectra
- **BeamSwitch** — reference from offset beam position
These will be implemented when test data becomes available.
See :doc:`/source/developer/adding-observation-mode` for the extension
guide.