Files
RFG_stm32_ADC_receiver_GUI/rfg_adc_plotter/main.py

118 lines
4.6 KiB
Python
Executable File
Raw 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
"""
Реалтайм-плоттер для свипов из виртуального 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)",
)
parser.add_argument(
"--bin",
dest="bin_mode",
action="store_true",
help=(
"Бинарный протокол: старт свипа 0xFFFF,0xFFFF,0xFFFF,(CH<<8)|0x0A; "
"точки step,uint32(hi16,lo16),0x000A"
),
)
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()