Исходный код soniks_client.post_processing
"""Постобработка прохода: водопад и метаданные сигнала.
Отправкой на портал занимается вызывающий: блок ``signal`` отсюда — только
часть метаданных наблюдения, остальное собирает ``Observation``.
"""
from pathlib import Path
from core.configs import logger, settings
from core.exceptions import (
EmptyWaterfallError,
TimestampError,
WaterfallFileError,
)
from soniks_client.waterfall import Waterfall
[документация]
def build_waterfall(
raw_path: str,
png_path: str,
observation_id: str,
) -> dict | None:
"""Построить PNG водопада и вернуть метаданные сигнала.
Возвращает ``None``, если водопад не построен или анализ ничего не дал.
Сырой ``.dat`` удаляется только при успешном построении: при упавшем он
единственное, с чем можно разбираться.
"""
waterfall: Waterfall | None = None
signal_metadata: dict | None = None
waterfall_built = False
try:
waterfall = Waterfall(raw_path, png_path)
# Границы шкалы не передаются: plot() сам берёт их из настроек, а
# при WATERFALL__AUTORANGE=True подбирает по данным. Передача
# MIN_VALUE/MAX_VALUE отсюда делала автоподбор недостижимым.
waterfall.plot()
waterfall_built = True
logger.info(
"Водопад построен [наблюдение: %s]: %s",
observation_id,
png_path,
)
try:
signal_metadata = waterfall.get_signal_metadata()
if signal_metadata:
logger.info(
"Анализ сигнала выполнен [наблюдение: %s]: "
"modulation=%s, deviation=%s",
observation_id,
signal_metadata.get("modulation"),
signal_metadata.get("deviation_hz"),
)
except Exception as e:
logger.warning(
"Ошибка при анализе сигнала [наблюдение: %s]: %s",
observation_id,
e,
)
except (EmptyWaterfallError, TimestampError, WaterfallFileError) as e:
# Исключения водопада без сообщения: подробности уже в логе
# waterfall/plot.py, здесь важен сам факт и класс ошибки.
logger.error(
"Водопад не построен [наблюдение: %s]: %s",
observation_id,
type(e).__name__,
)
except Exception as e:
logger.error(
"Ошибка при построении водопада [наблюдение: %s]: %s",
observation_id,
e,
)
if settings.observation.REMOVE_WATERFALL_RAW_FILES:
if waterfall_built:
Path(raw_path).unlink(missing_ok=True)
else:
# Упавшее построение — единственный случай, когда сырой файл
# ещё нужен: без него разбираться не с чем.
logger.warning(
"Сырой файл водопада сохранён для разбора [наблюдение: %s]: %s",
observation_id,
raw_path,
)
return signal_metadata