Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ repos:
'numpy==2.3.5',
'pandas-stubs==2.3.3.251219',
'prometheus-client==0.24.0',
'prometheus-api-client==0.7.2',
'pyparsing==3.3.1',
'pytest==9.0.3',
'pytest-asyncio==1.4.0',
'redis==7.1.0', # Indirect dependency of katsdptelstate
'spead2==4.4.1',
'types-decorator==5.2.0.20251101',
'types-docutils==0.21.0.20250809',
'types-python-dateutil==2.9.0.20260716',
'types-six==1.17.0.20251009',
'typing-extensions==4.15.0',
]
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ test = [
"baseband",
"katsdpsigproc[CUDA]",
"matplotlib",
"prometheus-api-client>=0.7.0",
"pytest>=8",
"pytest-asyncio>=1.4.0",
"pytest-check>=1.3,<2.2.3", # Upper bound due to https://github.com/okken/pytest-check/issues/173
Expand Down
7 changes: 6 additions & 1 deletion qualification/cbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@
if TYPE_CHECKING:
# This is only imported for type checkers, because importing at runtime
# would create a cyclic dependency.
from .recv import BaselineCorrelationProductsReceiver, TiedArrayChannelisedVoltageReceiver
from .recv import (
BaselineCorrelationProductsReceiver,
TiedArrayChannelisedVoltageReceiver,
TiedArrayResampledVoltageReceiver,
)

logger = logging.getLogger(__name__)
DEFAULT_MAX_DELAY = 1000000 # Around 0.5-1ms, depending on band. Increase if necessary
Expand Down Expand Up @@ -75,6 +79,7 @@ class CBFRemoteControl(CBFBase):
# These are filled in by conftest.py.
baseline_correlation_products_receiver: "BaselineCorrelationProductsReceiver | None" = None
tied_array_channelised_voltage_receiver: "TiedArrayChannelisedVoltageReceiver | None" = None
tied_array_resampled_voltage_receiver: "TiedArrayResampledVoltageReceiver | None" = None

@property
def init_sensors(self) -> aiokatcp.SensorSet:
Expand Down
32 changes: 30 additions & 2 deletions qualification/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,22 @@
from katgpucbf.pytest_plugins.reporter import Reporter, custom_report_log

from .cbf import CBFCache, CBFRemoteControl, FailedCBF
from .recv import DEFAULT_TIMEOUT, BaselineCorrelationProductsReceiver, TiedArrayChannelisedVoltageReceiver
from .recv import (
DEFAULT_TIMEOUT,
BaselineCorrelationProductsReceiver,
TiedArrayChannelisedVoltageReceiver,
TiedArrayResampledVoltageReceiver,
)

pytest_plugins = ["katgpucbf.pytest_plugins.numpy_dump", "katgpucbf.pytest_plugins.reporter_plugin"]
logger = logging.getLogger(__name__)
FULL_ANTENNAS = [1, 4, 8, 20, 32, 40, 64, 80]
MAX_PASS_FRACTION = 0.7 # Maximum fraction of total narrowband bandwidth to use as pass_bandwidth
_CAPTURE_TYPES = {"gpucbf.baseline_correlation_products", "gpucbf.tied_array_channelised_voltage"}
_CAPTURE_TYPES = {
"gpucbf.baseline_correlation_products",
"gpucbf.tied_array_channelised_voltage",
"gpucbf.tied_array_resampled_voltage",
}

# Storing ini options this way makes pytest.ini easier to validate up-front.
IniOption = namedtuple("IniOption", ["name", "help", "type", "default"], defaults=[None])
Expand Down Expand Up @@ -544,6 +553,7 @@ async def cbf(
capture_start_streams: list[str],
capture_stop_streams: list[str],
tied_array_channelised_voltage_receive_streams: list[str],
vlbi: bool,
pdf_report: Reporter,
) -> AsyncGenerator[CBFRemoteControl, None]:
"""Set up a CBF for a single test.
Expand Down Expand Up @@ -580,6 +590,13 @@ async def cbf(
interface_address=interface_address,
use_ibv=use_ibv,
)
if cbf.tied_array_resampled_voltage_receiver is None and vlbi:
logger.info("Subscribing to tied-array-resampled-voltage")
cbf.tied_array_resampled_voltage_receiver = TiedArrayResampledVoltageReceiver(
cbf=cbf,
stream_names=["tied-array-resampled-voltage"],
interface_address=interface_address,
)

# Reset the CBF to default state
pcc = cbf.product_controller_client
Expand All @@ -598,6 +615,8 @@ async def cbf(
await pcc.request("beam-quant-gains", name, 1.0)
await pcc.request("beam-delays", name, *(("0:0",) * n_inputs))
await pcc.request("beam-weights", name, *((1.0,) * n_inputs))
elif conf["type"] == "gpucbf.tied_array_resampled_voltage":
await pcc.request("vlbi-delay", name, "0.0")

for name in capture_start_streams:
await pcc.request("capture-start", name)
Expand Down Expand Up @@ -663,3 +682,12 @@ async def receive_tied_array_channelised_voltage(
):
await receiver.wait_complete_chunk(max_delay=0, timeout=3 * DEFAULT_TIMEOUT)
return receiver


@pytest.fixture
async def receive_tied_array_resampled_voltage(
cbf: CBFRemoteControl,
) -> TiedArrayResampledVoltageReceiver | None:
"""Get the receiver for ingesting the tied-array-resampled-voltage streams."""
receiver = cbf.tied_array_resampled_voltage_receiver
return receiver
23 changes: 23 additions & 0 deletions qualification/recv.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ast
import asyncio
import ctypes
import json
import logging
import math
import os
Expand All @@ -45,6 +46,8 @@
from .cbf import DEFAULT_MAX_DELAY, CBFRemoteControl

DEFAULT_TIMEOUT = 10.0
IP_MULTICAST_ALL = 49

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -642,3 +645,23 @@ def chunk_place(data_ptr, data_size, user_data_ptr):
sink=stream_group,
),
)


class TiedArrayResampledVoltageReceiver:
"""Receive tied-array-resampled-voltage streams from the V-engines."""

def __init__(
self,
cbf: CBFRemoteControl,
stream_names: Sequence[str],
interface_address: str,
) -> None:
self.stream_names = stream_names
self.n_chans = cbf.init_sensors[f"{stream_names[0]}.n-chans"].value
self.pol_ordering = json.loads(cbf.init_sensors[f"{stream_names[0]}.pol-ordering"].value.decode())
self.n_threads = self.n_chans * len(self.pol_ordering)
self.veng_out_bits_per_sample = cbf.init_sensors[f"{stream_names[0]}.veng-out-bits-per-sample"].value
self.scale_factor_timestamp = cbf.init_sensors[f"{stream_names[0]}.scale-factor-timestamp"].value
self.power_int_time = cbf.init_sensors[f"{stream_names[0]}.power-int-time"].value
self.bandwidth = cbf.init_sensors[f"{stream_names[0]}.bandwidth"].value
self.sync_time: float = cbf.init_sensors[f"{stream_names[0]}.sync-time"].value
1 change: 1 addition & 0 deletions qualification/report/generate_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
GROUP_NAMES = {
"general": "General tests",
"antenna_channelised_voltage": "Antenna channelised voltage tests",
"tied_array_resampled_voltage": "Tied-array resampled voltage tests",
"baseline_correlation_products": "Baseline correlation products tests",
"tied_array_channelised_voltage": "Tied-array channelised voltage tests",
"demo": "Report demonstration tests",
Expand Down
24 changes: 16 additions & 8 deletions qualification/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ dask==2025.12.0
# -c qualification/../requirements-dev.txt
# -c qualification/../requirements.txt
# katgpucbf (pyproject.toml)
dateparser==1.2.2
# via prometheus-api-client
dateparser==1.4.1
# via
# -c qualification/../requirements-dev.txt
# prometheus-api-client
decorator==5.2.1
# via
# -c qualification/../requirements-dev.txt
Expand Down Expand Up @@ -267,8 +269,10 @@ pluggy==1.6.0
# via
# -c qualification/../requirements-dev.txt
# pytest
prometheus-api-client==0.7.0
# via katgpucbf (pyproject.toml)
prometheus-api-client==0.7.2
# via
# -c qualification/../requirements-dev.txt
# katgpucbf (pyproject.toml)
prometheus-async==26.1.0
# via
# -c qualification/../requirements-dev.txt
Expand Down Expand Up @@ -362,8 +366,10 @@ redis==7.1.0
# -c qualification/../requirements-dev.txt
# -c qualification/../requirements.txt
# katsdptelstate
regex==2026.1.15
# via dateparser
regex==2026.7.19
# via
# -c qualification/../requirements-dev.txt
# dateparser
requests==2.33.0
# via
# -c qualification/../requirements-dev.txt
Expand Down Expand Up @@ -423,8 +429,10 @@ tzdata==2025.3
# -c qualification/../requirements-dev.txt
# -c qualification/../requirements.txt
# pandas
tzlocal==5.3.1
# via dateparser
tzlocal==5.4.4
# via
# -c qualification/../requirements-dev.txt
# dateparser
urllib3==2.7.0
# via
# -c qualification/../requirements-dev.txt
Expand Down
1 change: 1 addition & 0 deletions qualification/tied_array_resampled_voltage/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# noqa: D104
26 changes: 26 additions & 0 deletions qualification/tied_array_resampled_voltage/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
################################################################################
# Copyright (c) 2026, National Research Foundation (SARAO)
#
# Licensed under the BSD 3-Clause License (the "License"); you may not use
# this file except in compliance with the License. You may obtain a copy
# of the License at
#
# https://opensource.org/licenses/BSD-3-Clause
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################

"""Fixtures and options for testing of tied-array-resampled-voltage streams."""

import pytest

_vlbi_only = pytest.mark.vlbi_only


def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
"""Apply vlbi_only before parametrisation in the parent conftest."""
metafunc.definition.add_marker(_vlbi_only)
Loading