new project structure

This commit is contained in:
awe
2026-02-11 16:32:21 +03:00
parent 0eaa07c03a
commit c3acd0c193
16 changed files with 1576 additions and 0 deletions

108
rfg_adc_plotter/main.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
"""
Реалтайм-плоттер для свипов из виртуального COM-порта.
Формат строк:
- "Sweep_start" — начало нового свипа (предыдущий считается завершённым)
- "s CH X Y" — точка (номер канала, индекс X, значение Y), все целые со знаком
Отрисовываются четыре графика:
- Сырые данные: последний полученный свип (Y vs X)
- Водопад сырых данных: последние N свипов
- FFT текущего свипа
- B-scan: водопад FFT-строк
Зависимости: numpy. PySerial опционален — при его отсутствии
используется сырой доступ к TTY через termios.
GUI: matplotlib (совместимый) или pyqtgraph (быстрый).
"""
import argparse
import sys
def build_parser() -> argparse.ArgumentParser:
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(
"--spec-mean-sec",
type=float,
default=0.0,
help=(
"Вычитание среднего по каждой частоте за последние N секунд "
"в водопаде спектров (0 — отключить)"
),
)
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(
"--norm-type",
choices=["projector", "simple"],
default="projector",
help="Тип нормировки: projector (по огибающим в [-1000,+1000]) или simple (raw/calib)",
)
return parser
def main():
args = build_parser().parse_args()
if args.backend == "pg":
from rfg_adc_plotter.gui.pyqtgraph_backend import run_pyqtgraph
try:
run_pyqtgraph(args)
except Exception as e:
sys.stderr.write(f"[error] PyQtGraph бэкенд недоступен: {e}\n")
sys.exit(1)
return
if args.backend == "auto":
try:
from rfg_adc_plotter.gui.pyqtgraph_backend import run_pyqtgraph
run_pyqtgraph(args)
return
except Exception:
pass # Откатываемся на matplotlib
from rfg_adc_plotter.gui.matplotlib_backend import run_matplotlib
run_matplotlib(args)
if __name__ == "__main__":
main()