# Выходные данные Флоуграф сам пишет на диск только водопад. Всё остальное он публикует в ZMQ-сокеты на localhost, а на диск это кладут отдельные процессы-подписчики, которые поднимает диспетчер. ## Каналы ZMQ | Порт | Что публикует флоуграф | Тип данных | Подписчик | Результат | |---|---|---|---|---| | `base` (16887) | `zeromq_pub_msg_sink` после декодера кадров | PMT-сообщение | `zmq_frame_decoder_sub` | по одному JSON-файлу на кадр | | `base + 1` (16888) | `zeromq_pub_sink` после доплер-компенсации | `short`, vlen 2 | `zmq_iq_sub` | один `.raw` за наблюдение | | `base + 2` (16889) | `zeromq_pub_sink` после демодулятора | `float` | `zmq_audio_sub` | один OGG за наблюдение | `base` задаётся аргументом `--zmq-base-port` диспетчера и по умолчанию равен 16887. Диспетчер передаёт его во флоуграф как `--zmq-base-port`, и все три адреса выводятся из одного параметра `zmq_base_port` в `.grc`: ```yaml address: '"tcp://127.0.0.1:" + str(zmq_base_port + 2)' ``` Число живёт в одном месте на каждой стороне, поэтому две станции на одной машине разводятся одним аргументом. Подписчики опрашивают сокет с интервалом 500 мс, поэтому после сигнала на завершение выходят примерно за полсекунды. ## Кадры телеметрии Порт `base`, подписчик `zmq_frame_decoder_sub`, запускается только для режимов с флагом «кадры» (см. [](modes.md)). **Имя файла:** `<--decoded-data-file-path>_` — префикс, подчёркивание и метка времени `ГГГГ-ММ-ДДTчч-мм-сс.ssssssZ`. Расширения нет. Микросекунды в метке делают имя уникальным даже при плотном потоке кадров. **Содержимое:** JSON с отступом 4 и отсортированными ключами. ```json { "decoder_corrected_bits": 0, "decoder_crc_valid": true, "decoder_name": "satnogs_frame_decoder", "decoder_version": "1.0", "pdu": "QUJDREVGRw==", "sample_cnt": 4096, "sample_start": 122880, "time": "2026-08-22T14:31:07.482915Z" } ``` | Ключ | Тип | Смысл | |---|---|---| | `pdu` | строка | полезная нагрузка кадра в base64. **Единственное гарантированное поле** | | `decoder_name` | строка | блок-декодер, породивший кадр | | `decoder_version` | строка | версия декодера | | `decoder_crc_valid` | bool | контрольная сумма сошлась | | `decoder_corrected_bits` | int | сколько бит исправила коррекция ошибок | | `sample_start` | int | номер первого отсчёта кадра от начала наблюдения | | `sample_cnt` | int | длина кадра в отсчётах | | `time` | строка | метка времени приёма, ISO 8601 | :::{note} Набор ключей, кроме `pdu`, целиком задаёт публикующий блок. Декодеры gr-satellites (Geoscan, USP) метаданных не отдают вовсе, поэтому их файлы содержат ровно `{"pdu": "…"}`. Апстрим в этом случае падал; форк добавил подстановку пустых метаданных, так что кадр всё равно сохраняется. ::: ## Аудио Порт `base + 2`, подписчик `zmq_audio_sub`. Запускается **всегда**, независимо от режима. `--file-path` здесь — полный путь к результату, а не префикс: метка времени не добавляется. Если файл уже существует, он **удаляется** перед записью. Формат зафиксирован в коде подписчика: OGG Vorbis, 48000 Гц, моно, входные отсчёты `float32`. Флоуграф обязан привести звук именно к 48 кГц — рассогласование частот не обнаруживается, аудио просто окажется ускоренным или замедленным. Если за наблюдение не пришло ни одного отсчёта, подписчик пишет предупреждение в `stderr`: пустой OGG больше не выглядит как успешная запись. Так проявляет себя PHASMA, у которого аудиоветки нет вовсе. Что попадает в аудио, зависит от режима: для FM — демодулированный НЧ-сигнал, для BPSK — сигнал, перенесённый на 12 кГц и взятый по действительной части, для Geoscan и USP — выход отдельного когерентного контура, работающего параллельно декодеру. ## IQ Порт `base + 1`, подписчик `zmq_iq_sub`. Запускается только при `--enable-iq-dump=1`. **Имя файла:** `<--iq-file-path>_cs16_.raw`, метка времени берётся один раз при старте. **Формат:** чередующиеся комплексные знаковые 16-битные целые (I, Q, I, Q, …), порядок байтов машинный. Отсчёты получены умножением комплексного потока на 16384. Данные сняты **после** доплеровской компенсации. Частота дискретизации в файле никак не отражена, а зависит она от режима: - FM и SSTV (оба идут через `fm.grc`) — 48000 Гц; - APT и SSTV_PD120 — `4*4160*4` = 66560 Гц. `audio_samp_rate = 48000` в этих графах относится только к последнему ресемплеру аудио, не к IQ; - все режимы с бодрейтом — `baudrate × decimation`, где децимация вычисляется флоуграфом (см. [](dev/grc-conventions.md)). Открыть в GNU Radio: `blocks_file_source` типа `short` → `blocks_interleaved_short_to_complex`, множитель `1/16384`. ## Водопад Пишет сам флоуграф блоком `satnogs_waterfall_sink` в файл `--waterfall-file-path`. Параметры зашиты во всех флоуграфах одинаково: БПФ на 1024 точки, 10 строк в секунду. Частота дискретизации на входе водопада та же, что у IQ, — то есть **полоса и разрешение водопада зависят от режима**. Для FM это 48 кГц, для FSK 9600 — 57.6 кГц (`find_decimation(9600, 2, 48000)` = 6, не 4), для BPSK 9600 — 76.8 кГц (`sps` = 4), для APT/SSTV — 66.56 кГц, для PHASMA — 200 кГц. Геометрия (частота, число каналов, число БПФ на строку) записана в заголовок `.dat`; клиент отдаёт её порталу в `client_metadata.signal` вместе с уровнем шума, нормированным на ширину бина (`noise_dbhz`). ## Живой поток по UDP Независимо от файлов флоуграф всегда шлёт доплер-скорректированный поток в `network_udp_sink` на `--udp-dump-host:--udp-dump-port`. Формат — комплексные 16-битные целые, размер полезной нагрузки пакета 1472 байта. Частота дискретизации та же, что у IQ-дампа. Предназначен для анализа в реальном времени во время наблюдения; на диск ничего не пишется.