Files
2026-02-03 15:24:07 +03:00

111 lines
4.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Точка входа для RFG ADC Data Plotter.
Реалтайм-плоттер для свипов из виртуального COM-порта.
Формат строк:
- "Sweep_start" — начало нового свипа (предыдущий считается завершённым)
- "s X Y" — точка (индекс X, значение Y), все целые со знаком
Отрисовываются шесть графиков:
- Левый верхний: последний полученный свип (Y vs X)
- Правый верхний: водопад (последние N свипов во времени)
- Левый средний: FFT спектр текущего свипа
- Правый средний: B-scan (водопад FFT спектров)
- Левый нижний: Фаза спектра (развернутая)
- Правый нижний: Водопад фазы
Оптимизации для скорости:
- Парсинг и чтение в фоновой нити
- Анимация с обновлением только данных (без лишнего пересоздания фигур)
- Кольцевой буфер под водопад с фиксированным числом свипов
Зависимости: matplotlib, numpy. PySerial опционален — при его отсутствии
используется сырой доступ к TTY через termios.
"""
import argparse
import sys
def main():
"""Основная функция CLI."""
parser = argparse.ArgumentParser(
description=(
"Читает свипы из виртуального COM-порта и рисует: "
"последний свип и водопад (реалтайм)."
)
)
parser.add_argument(
"port",
help="Путь к порту, например /dev/ttyACM1 или COM3 (COM10+: \\\\.\\COM10)",
)
parser.add_argument("--baud", type=int, default=115200, help="Скорость (по умолчанию 115200)")
parser.add_argument("--max-sweeps", type=int, default=200, help="Количество видимых свипов в водопаде")
parser.add_argument("--max-fps", type=float, default=30.0, help="Лимит частоты отрисовки, кадров/с")
parser.add_argument("--cmap", default="viridis", help="Цветовая карта водопада")
parser.add_argument(
"--spec-clip",
default="2,98",
help=(
"Процентильная обрезка уровней водопада спектров, % (min,max). "
"Напр. 2,98. 'off' — отключить"
),
)
parser.add_argument("--title", default="ADC Sweeps", help="Заголовок окна")
parser.add_argument(
"--fancy",
action="store_true",
help="Заполнять выпавшие точки средними значениями между соседними",
)
parser.add_argument(
"--ylim",
type=str,
default=None,
help="Фиксированные Y-пределы для кривой формата min,max (например -1000,1000). По умолчанию авто",
)
parser.add_argument(
"--backend",
choices=["auto", "pg", "mpl"],
default="auto",
help="Графический бэкенд: pyqtgraph (pg) — быстрее; matplotlib (mpl) — совместимый. По умолчанию auto",
)
parser.add_argument(
"--ref-out",
type=str,
default=None,
help="Сохранить медиану последних 1000 свипов в указанный файл при накоплении данных",
)
parser.add_argument(
"--ref-in",
type=str,
default=None,
help="Загрузить медиану из файла и вычитать её из входящего сигнала",
)
args = parser.parse_args()
# Попробуем быстрый бэкенд (pyqtgraph) при auto/pg
if args.backend in ("auto", "pg"):
try:
from .visualization.pyqtgraph_backend import run_pyqtgraph
return run_pyqtgraph(args)
except Exception as e:
if args.backend == "pg":
sys.stderr.write(f"[error] PyQtGraph бэкенд недоступен: {e}\n")
sys.exit(1)
# При auto — тихо откатываемся на matplotlib
# Fallback на matplotlib
try:
from .visualization.matplotlib_backend import run_matplotlib
return run_matplotlib(args)
except Exception as e:
sys.stderr.write(f"[error] Matplotlib бэкенд недоступен: {e}\n")
sys.exit(1)
if __name__ == "__main__":
main()