Как подключить модем к стенду
Ваша команда пишет две программы: узел A (передатчик) и узел B (приёмник). Стенд — это радиоэфир между ними: он принимает сигнал от A, пропускает его через моделируемый радиоканал и отдаёт B. От B к A идёт такой же отдельный канал. Задача — чтобы B восстановил переданный файл как можно полнее и быстрее.
1. Как подключиться
- Получите ключ команды у организаторовС ним вы входите в консоль команды и создаёте тестовые сессии.
- Войдите в консоль команды и создайте сессиюВыберите сценарий и нажмите «Создать сессию». Стенд выдаст два разных токена — для узла A и для узла B — и адреса подключения.
- Запустите узел A и узел BДве программы или один Docker-образ, запущенный дважды с разной ролью. Параметры подключения передаются через переменные окружения (ниже). Узел A скачивает файл, который нужно передать; узел B файла не видит.
- Дождитесь конца эфираКогда оба узла подключены и прислали
ready, начинается эфир. После его окончания узел B отправляет восстановленный файл, и стенд показывает результат в консоли.
SIGNAL_ROLE = A или B · SIGNAL_SESSION_ID · SIGNAL_NODE_TOKEN · SIGNAL_API_URL (адрес REST API) · SIGNAL_WS_URL (база адреса WebSocket).
Программа должна читать всё из этих переменных и работать без ручных действий.2. Бейзлайн — готовый пример решения
Рабочее решение-образец: оба узла в одном проекте, запуск одной командой. С него удобно начать, чтобы увидеть весь путь от файла до результата.
- Скачайте и распакуйтеradioshtorm-baseline.zip — внутри README с описанием.
- Создайте сессию в консоли командыНа странице сессии есть блок «session.env для бейзлайна» — скопируйте его в файл
session.envв папке бейзлайна. - Запустите оба узлаВ командной строке из папки бейзлайна (PowerShell на Windows, Терминал на macOS и Linux):
docker compose --env-file session.env up --build— нужен Docker. Без Docker:python run_local.py— нужен Python 3.11+. Работает на Windows, macOS и Linux; подробности и команды для каждой системы — в README бейзлайна.
3. Как идёт сессия
4. Эфир
Как в настоящем радиоканале, сигнал по пути может ослабевать, тонуть в шуме, приходить с задержкой и со сдвигом по частоте и фазе, рядом могут появляться посторонние сигналы. Условия меняются во время сессии и различаются от сценария к сценарию. Сигнал от B к A идёт по своему каналу со своими условиями.
Стенд ничего не сообщает о состоянии канала — ни узлам, ни в консоли. Узел B знает только то, что сам принял. Узел A знает о приёме на стороне B только то, что B сообщит ему по радио.
5. Формат сигнала и правила обмена
- Стенд ведёт эфир по своим часам: каждые 20,48 мс берёт у каждого узла по одному блоку и отдаёт каждому по одному блоку.
- Если к очередному такту блок от узла не пришёл, в эфир уходит тишина. Вперёд стенд принимает не больше 10 блоков, лишние отбрасываются.
- Значения I и Q за пределами ±1 обрезаются. NaN и Inf запрещены.
- Узел B сдаёт файл один раз, после окончания эфира. Стенд сравнивает байты по их позициям в исходном файле.
import numpy as np
# один блок: 4096 комплексных отсчётов -> 32 768 байт I0,Q0,I1,Q1,... (float32 little-endian)
def pack(iq):
buf = np.empty(8192, dtype="<f4"); buf[0::2] = iq.real; buf[1::2] = iq.imag
return buf.tobytes()
def unpack(data):
v = np.frombuffer(data, dtype="<f4"); return v[0::2] + 1j * v[1::2]
ws_url = f"{SIGNAL_WS_URL}/sessions/{SIGNAL_SESSION_ID}/nodes/{SIGNAL_ROLE}?token={SIGNAL_NODE_TOKEN}"
# hello -> {"type":"ready"} -> start -> обмен блоками -> stop
# узел A: GET {SIGNAL_API_URL}/sessions/{id}/input (Authorization: Bearer токен A)
# узел B: PUT {SIGNAL_API_URL}/sessions/{id}/result (Content-Type: application/octet-stream)Полное описание протокола — все сообщения, коды ошибок и ограничения.
6. Частые ошибки
| Что видите | Почему |
|---|---|
| Эфир не начинается | Старт — только когда оба узла подключились и прислали {"type":"ready"}. |
| Много «пропусков такта» | Узел не успевает присылать блоки, и в эфир уходит тишина. |
| «Переполнения» / отброшенные блоки | Узел присылает блоки быстрее, чем стенд их забирает. |
| Клиппинг | Значения I или Q выходят за ±1. |
bad_frame_size | Бинарное сообщение должно быть ровно 32 768 байт. |
| Результат не принят | Файл сдаётся только после stop, только узлом B и только один раз. |