docs: update Pluto integration plan for recent TX fixes

Document the TX-path work landed this session:
- §4.6: polyphase FIR interpolator + sample-rate-scaled TX buffer +
  SoapyPlutoSDR confirmation of 32768 full-scale.
- §4.8 (new): power-linear drive→atten mapping, full WDSP digital level,
  TX LO powerdown gated by PTT.
- Phase 4 status updated.
- Related fixes: per-band FM settings (SQL/CTCSS/step/repeater) restore on
  startup — was dropped by LoadDevice; affects all backends.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 22:08:45 +03:00
co-authored by Claude Opus 4.8
parent ff331fa2a0
commit 17d0af4910
+52 -15
View File
@@ -239,14 +239,22 @@ end;
- **RX:** `TPlutoBackend` читает int16 из `iio_buffer`, конвертирует 16→24-бит, - **RX:** `TPlutoBackend` читает int16 из `iio_buffer`, конвертирует 16→24-бит,
упаковывает в `TDDCIQPacket` (seq синтезируется), вызывает `OnDDCIQ`. упаковывает в `TDDCIQPacket` (seq синтезируется), вызывает `OnDDCIQ`.
- **TX:** ✅ `SendDUCIQ` апсемплит 192k→device-rate (целочисленно, линейная - **TX:** ✅ `SendDUCIQ` апсемплит 192k→device-rate **полифазным FIR-интерполятором**
интерполяция; пресеты рейта кратны 192k), конвертирует 24→16-бит (`>>8`, ×L (`BuildTxResampler`: оконный sinc-ФНЧ, окно Блэкмана ~−58 дБ, `TX_FIR_TAPS=16`
full-scale MSB-aligned), инвертирует Q (симметрично RX) и кладёт в кольцевой отводов/фазу, срез `TX_FIR_CUT=40 кГц`, нормировка на единичное DC-усиление фазы;
FIFO. Отдельный `TPlutoTXThread` льёт пары в tx-буфер libiio и `iio_buffer_push` пресеты рейта кратны 192k → L целое), конвертирует 24→16-бит (`>>8`, full-scale
MSB-aligned), инвертирует Q (симметрично RX) и кладёт в кольцевой FIFO. Линия
задержки `FTxDlI/Q` живёт между вызовами, сбрасывается в `StartTX`/`ClearDUCIQQueue`.
Отдельный `TPlutoTXThread` льёт пары в tx-буфер libiio и `iio_buffer_push`
(блокирующий push = пейсинг на device-rate); при underrun — нули (непрерывный (блокирующий push = пейсинг на device-rate); при underrun — нули (непрерывный
full-duplex). Решение rate-mismatch (риск §6.2) — апсемпл в host (RX/TX делят full-duplex). Решение rate-mismatch (риск §6.2) — апсемпл в host (RX/TX делят
один `sampling_frequency`). TODO: полифазный FIR вместо линейной интерполяции один `sampling_frequency`).
для лучшего подавления образов на аплинке. - **Размер TX-буфера** масштабируется от device-rate (модель SoapyPlutoSDR):
`round(rate/60)` → следующая степень 2, кламп `[4096..65536]` (576k→16384,
1536k→32768). Фикс 4096 был мал для full-duplex выше ~1 Msps → дропы/щелчки.
FIFO держит ~4 таких буфера запаса (`TxBufPairsForRate`, пересчёт в `StartTX`).
- Подтверждено по каноничному драйверу (SoapyPlutoSDR): TX full-scale = 32768,
MSB-aligned → наш `>>8` (24→16) верен; занижения уровня по дизайну нет.
### 4.7 Усиление / телеметрия ### 4.7 Усиление / телеметрия
@@ -257,6 +265,23 @@ end;
`ServicePlutoTelemetry` (контроллер, опрос ~2 Гц с фильтром выбросов) → поле 3 `ServicePlutoTelemetry` (контроллер, опрос ~2 Гц с фильтром выбросов) → поле 3
статус-бара (Temp/RSSI вместо Supply, т.к. у Pluto нет PA). статус-бара (Temp/RSSI вместо Supply, т.к. у Pluto нет PA).
### 4.8 TX-мощность / drive (Pluto)
-**Мощность задаётся ОДИН раз — железной аттенюацией** (`hardwaregain`), а не
цифрой WDSP. `ApplyWDSPDrive` (контроллер): на Pluto `SetDriveLevel(1.0)` (полная
цифра), HPSDR — `Pct/100`. Раньше drive резался дважды (цифра × атт).
-**`PlutoTxAttForDrive` — power-linear:** `дБ = потолок + 20·log10(pct/100)`
(100% → потолок, 50% → −6, 10% → −20). Старый dB-линейный маппинг от −89.75 уводил
низкие % в −80 дБ — из-за этого TUN (TUNLevel 10%) давал −81.8 дБ → тон не слышен.
Потолок — `FPlutoTxMaxAttDb` (дефолт −10 дБ), на приёме −89.75 (≈выкл).
-**TX LO (`altvoltage1`) гасится по PTT** (`SetTxLOPowerdown`): на приёме
`powerdown=1` → нет утечки несущей TX на частоте VFO в RX-спектре и нет излучения в
простое; на передаче `powerdown=0`. `ApplyTxLO` ставит powerdown по `FTransmitting`
(заодно возвращает LO, если стороннее ПО его погасило). RX LO (`altvoltage0`) —
всегда вкл (приём непрерывен, QO-100 full-duplex не ломается). Цена: повторное
включение LO запускает калибровку синтезатора AD9361 (единицы–десятки мс) → первый
слог SSB может чуть подрезаться.
--- ---
## 5. Поэтапный план (фазы) ## 5. Поэтапный план (фазы)
@@ -283,13 +308,16 @@ end;
**Фаза 4 — TX-тракт Pluto** **Фаза 4 — TX-тракт Pluto**
-`SendDUCIQ` 24→16 + апсемпл 192k→device-rate + пейсинг (FIFO + push-поток, §4.6). -`SendDUCIQ` 24→16 + апсемпл 192k→device-rate + пейсинг (FIFO + push-поток, §4.6).
-Управление мощностью через TX-аттенюацию (ADI-модель): непрерывный full-duplex -**Полифазный FIR-интерполятор** вместо линейной интерполяции (§4.6) — образы на
стрим, drive% → `hardwaregain` (потолок `PlutoTxMaxAttDb`, дефолт 10 дБ, кратных 192k давятся ~−58 дБ (раньше только sinc²), чище аплинк, громкость не меняется.
настраиваемый под внешний усилитель); на приёме −89.75 дБ (≈выкл). Маппинг/ -**TX-буфер по sample-rate** (§4.6) — устранены щелчки/дропы на full-duplex >1 Msps.
политика — в контроллере (`PlutoTxAttForDrive`/`ApplyPlutoTxAtten`), бэкенд — - ✅ Управление мощностью через TX-аттенюацию (ADI-модель), маппинг **power-linear**
тонкий `SetTxAtten`. Без PA → нет drive-байта/SWR/Alex/keyer. + полная цифра WDSP (§4.8). Без PA → нет drive-байта/SWR/Alex/keyer.
- TODO: проверка на железе (ориентация SSB по Q-инверсии, уровни); полифазный - **TX LO powerdown по PTT** (§4.8) — нет утечки несущей TX в RX-спектре в простое.
ресэмпл (см. §4.6); опц. зануление IQ на приёме. - TODO: проверка на железе на rate ≥1536k (ориентация SSB по Q-инверсии, уровни);
опц. headroom 6 дБ для FM (full-scale const-envelope → нелинейность ЦАП); опц.
зануление IQ на приёме. Опц. поддержка F5OEO-прошивки (PTT внешнего PA через
`hardwaregain=40`) — отложено, нужно только под конкретное железо.
**Фаза 5 — Режим QO-100** **Фаза 5 — Режим QO-100**
- ✅ Калибровка LNB по маяку (beacon lock) — стабилизация дрейфа. - ✅ Калибровка LNB по маяку (beacon lock) — стабилизация дрейфа.
@@ -307,6 +335,14 @@ end;
- Web/CAT-фронтенды (команды уже агностичны) + гейтинг полей; демон `ewsdrd.lpr` - Web/CAT-фронтенды (команды уже агностичны) + гейтинг полей; демон `ewsdrd.lpr`
(discovery/connect Pluto headless); кросс-платформенная сборка с/без libiio; доки. (discovery/connect Pluto headless); кросс-платформенная сборка с/без libiio; доки.
**Сопутствующие исправления (найдены при тесте Pluto VHF/UHF FM, но баги общие):**
- ✅ Восстановление per-band FM-настроек на старте (`Settings.LoadDevice`): bulk-
загрузчик бэндов читал только freq/mode/filter/AGC/CTun/center/span и **пропускал
FM-поля** (`fmsq_on`/`fmsq_level`/`ctcss_*`/`fmstep_*`/`fmrpt_*`), хотя `SaveBand`
их пишет, а `LoadBand` читает. Итог: SQL/CTCSS/шаг/репитер-сдвиг сохранялись на
выходе, но сбрасывались в дефолт при следующем запуске (смена бэндов работала —
идёт через in-memory band-cache). Затрагивало **все бэкенды**, не только Pluto.
--- ---
## 6. Риски и открытые вопросы ## 6. Риски и открытые вопросы
@@ -314,8 +350,9 @@ end;
1. **2 м / 70 см ниже 325 МГц** → требуется freq-range мод прошивки Pluto. 1. **2 м / 70 см ниже 325 МГц** → требуется freq-range мод прошивки Pluto.
Документировать; возможно гейтить эти кнопки при стоковой прошивке. Документировать; возможно гейтить эти кнопки при стоковой прошивке.
2.**TX sample-rate mismatch** (192k WDSP vs ≥521k Pluto) — решено host-апсемплом 2.**TX sample-rate mismatch** (192k WDSP vs ≥521k Pluto) — решено host-апсемплом
192k→device-rate в `SendDUCIQ` (целочисленно, пресеты кратны 192k). Качество 192k→device-rate в `SendDUCIQ` (целочисленно, пресеты кратны 192k). Качество
образов — линейная интерполяция; апгрейд до полифазного FIR в бэклоге. образов — **полифазный FIR-интерполятор** (окно Блэкмана ~−58 дБ). ✅ Щелчки на
full-duplex >1 Msps — TX-буфер масштабируется от rate (модель SoapyPlutoSDR).
3. **QO-100 display-duplex** — hardware full-duplex есть (Фаза 4), остаётся довести 3. **QO-100 display-duplex** — hardware full-duplex есть (Фаза 4), остаётся довести
`SetDuplex` (водопад RX во время TX); проверить латентность/буферы libiio. `SetDuplex` (водопад RX во время TX); проверить латентность/буферы libiio.
4. **LNB дрейф** — калибровка `LnbPpm` по маяку (ручная/полуавтомат). 4. **LNB дрейф** — калибровка `LnbPpm` по маяку (ручная/полуавтомат).