89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
"""Neutral preprocessing-set helpers for Kamil ADC acquisition."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import time
|
|
|
|
import numpy as np
|
|
|
|
from python_app.hardware_full.kamil_adc import (
|
|
KamilAdcProcessingParams,
|
|
KamilAdcSweepProcessor,
|
|
)
|
|
from python_app.models.dataset_model import ComboKey, SweepCollection, TraceData
|
|
from python_app.models.run_config_model import ComboModel, RunConfigModel
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def build_kamil_adc_neutral_s21_sets(
|
|
config: RunConfigModel,
|
|
) -> tuple[SweepCollection, SweepCollection]:
|
|
"""Build neutral S21 calibration/reference collections for the Kamil ADC radar.
|
|
|
|
The calibration uses unit S21 (1+0j) and the reference uses zero S21 across
|
|
every configured combo, so applying them in the preprocessing pipeline leaves
|
|
the input S21 unchanged. The frequency axis is the exact acquisition grid
|
|
(``radar.kamil_adc.band``), so neutral sets line up sample-for-sample with
|
|
live sweeps. Returns the ``(calibration, reference)`` collections.
|
|
"""
|
|
if not config.is_kamil_adc:
|
|
raise ValueError("Neutral Kamil ADC sets require radar.model='kamil_adc'")
|
|
|
|
combos = list(config.combos)
|
|
if not combos:
|
|
combos = RunConfigModel.build_full_combos(
|
|
config.input_switch.positions, config.output_switch.positions
|
|
)
|
|
if not combos:
|
|
raise ValueError("Kamil ADC neutral sets require at least one switch combo")
|
|
|
|
# Single source of truth for the axis: the same grid the processor emits.
|
|
processor = KamilAdcSweepProcessor(KamilAdcProcessingParams.from_kamil_model(config.radar.kamil_adc))
|
|
frequency_hz = processor.grid_hz
|
|
|
|
now_ns = time.monotonic_ns()
|
|
calibration = _neutral_collection(
|
|
combos=combos,
|
|
frequency_hz=frequency_hz,
|
|
s21_value=np.complex64(1.0 + 0.0j),
|
|
monotonic_ns=now_ns,
|
|
)
|
|
reference = _neutral_collection(
|
|
combos=combos,
|
|
frequency_hz=frequency_hz,
|
|
s21_value=np.complex64(0.0 + 0.0j),
|
|
monotonic_ns=now_ns,
|
|
)
|
|
logger.info(
|
|
"Built neutral Kamil ADC S21 sets: combos=%d points=%d", len(combos), int(frequency_hz.size)
|
|
)
|
|
return calibration, reference
|
|
|
|
|
|
def _neutral_collection(
|
|
*,
|
|
combos: list[ComboModel],
|
|
frequency_hz: np.ndarray,
|
|
s21_value: np.complex64,
|
|
monotonic_ns: int,
|
|
) -> SweepCollection:
|
|
point_count = int(frequency_hz.size)
|
|
traces = [
|
|
TraceData(
|
|
combo=ComboKey(input=int(combo.input), output=int(combo.output)),
|
|
frequency_hz=frequency_hz.copy(),
|
|
s11=np.zeros(point_count, dtype=np.complex64),
|
|
s21=np.full(point_count, s21_value, dtype=np.complex64),
|
|
)
|
|
for combo in combos
|
|
]
|
|
return SweepCollection(
|
|
collection_id=1,
|
|
monotonic_ns=monotonic_ns,
|
|
traces=traces,
|
|
capture_start_ns=monotonic_ns,
|
|
capture_end_ns=monotonic_ns,
|
|
)
|