Всплесков на передаче нет, инструмент своё отработал и больше не нужен в
горячем пути. Снято ровно то, что ставил d209697, и ничего сверх:
* удалён юнит TxTrace.pas (кольцо + сброс дампа + TraceInit);
* TCIAdapter: точки съёма маркеров и TX-аудио, поля FTxTraceLast/FTxTraceAudio;
* HPSDRNetwork: DUC-DRY/DUC-RUN и переменная DryFrom (жила только для них),
вместе с ними ушли из uses TxTrace и PlatformUtils — их добавлял тот же
коммит, MonotonicUs в этом файле больше нигде не встречается;
* RadioController: PTT-метка в SetMOX и сброс дампа на снятии PTT;
* TraceInit из ewsdr.lpr и ewsdrd.lpr.
Каждая удалённая строка стояла под `if TraceOn` — вычислений, от которых
зависит тракт, в них не было. ★PlatformUtils.MonotonicUs НЕ тронут: на нём
абсолютные дедлайны планировщика TX, это не отладка.
Скрипт разбора test/hpsdr/txtrace_scan.py оставлен, формат дампа не менялся;
в README стенда записан рецепт возврата зондов из d209697.
Проверено: lazbuild --ws=qt6 и build-ewsdrd.sh собираются, test/tci 260/260,
test/cat 50/50 — те же числа, что и с зондами.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bkwwyj7xVRrqnSVEseTRfV
Посреди передачи из MSHV на водопаде появлялись всплески своего сигнала.
Цепочка: очередь DUC пустеет дольше подушки отправителя (DUC_FIFO_THROTTLE
= 2000 отсчётов = 10.4 мс) → FIFO радио сохнет → модуляция обрывается → в
эфире остаётся голая несущая на частоте гетеродина DUC, в стороне от тона
ровно на звуковой сдвиг. Доказано pcap-съёмом: шесть всплесков в дампе —
ровно столько, сколько видел оператор, и каждый стоит за паузой 10.3-23.5 мс,
а паузы 8 мс и короче не дали ни одного.
Виноват не клиент и не блокировка UI, а зернистость НАШЕГО запроса. Слой
первый: PushTxChrono жил на общем тике сервера 20 мс, а просил блок клиента
целиком (2048 отсчётов = 42.7 мс) — маркер выходил через два или три тика,
то есть через 40 или 60 мс. Слой второй: MSHV отвечает пачками по 4-5 блоков
раз в ~44 мс (STREAM_C = 4096 при 96 кГц), и мелкий квант этого не лечит —
нужен запас не меньше пачки.
Сделано:
* квант запроса = один блок TXA (512 отсчётов движка), а не блок клиента;
* свой поток-планировщик TxTickLoop с АБСОЛЮТНЫМИ дедлайнами (опоздание
одного пробуждения не сдвигает сетку); общий тик маркеров больше не шлёт;
* бухгалтерия Owed/InFlight в кадрах на канал, гасится по k до интерполятора;
потолок долга обязан быть выше окна в полёте (TCI_TX_OWED_HEADROOM_Q),
иначе связывающим становится он и подача падает до 58% реального времени
при полностью исправном клиенте;
* SendBinNow: маркеры пишутся в сокет напрямую под FWriteLock, минуя очередь
(та выпускается лишь на пробуждении потока клиента, TCI_POLL_MS = 20 мс —
вдвое больше кванта, и подача снова рвалась);
* FReapLock: планировщик TX — новый поток, а правило «клиента освобождает
только тик-поток» держалось на том, что им же он и пользуется;
* аванс под зернистость клиента: измеряется по ПЕРИОДУ между пачками (размер
пачки зависит от того, сколько мы запросили ⇒ положительная обратная связь),
переживает конец передачи, умеет уменьшаться по выдержке TCI_TX_LEAD_DOWN_MS,
потолок TCI_TX_LEAD_MAX_MS;
* старт передачи: KickTxTick будит планировщика на фронте PTT, TxPreWarm шлёт
один маркер ДО SetMOX (41 мс раздумий клиента накладываются на нашу же
подготовку тракта) под гейтом «передатчик свободен и чужого источника нет»,
PrimeDUCIQ для источника TCI растянут до Max(6096, аванс×4) — путь микрофона
радио, CW и web не затронут;
* посев аванса TCI_TX_LEAD_DEF_MS = 50 мс, пока про клиента ничего не известно:
обучение к первому осушению физически не успевает.
Монотонные часы одного источника для всех потоков — PlatformUtils.MonotonicUs
(абсолютные дедлайны не терпят часов, способных прыгнуть от NTP).
На железе: опасных осушений посреди передачи НОЛЬ (было 12 за 11 с), четыре
передачи из пяти вообще без единого, включая старт; прогон 15:21 чист везде,
в том числе на первой передаче после подключения. Всплесков оператор больше
не видит.
Приборы: TxTrace.pas (EWSDR_TXTRACE=1) и стенд test/hpsdr — кольцевой tcpdump
capture.sh, разбор дампа pcap_tx_scan.py, разбор трассы txtrace_scan.py.
Стенд test/tci: часть F «Пейсинг TX», 260 проверок, провалов нет; живой клиент
с рампой, RTT и потерями — test/tci/tx_chrono_bench.py.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gmVQnna1i4EbSZ2VGm6KD