From ff331fa2a05fcbca5173d4752425a0e5be6ab63a Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 19 Jun 2026 22:07:06 +0300 Subject: [PATCH] feat: Pluto TX LO powerdown gated by PTT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TX LO (altvoltage1) is now powered down on RX and enabled on PTT, instead of staying on continuously. Removes the TX carrier leakage that showed up at the VFO frequency in the RX spectrum (and persisted after MOX), and stops idle TX-LO radiation. ApplyTxLO sets powerdown from FTransmitting, which also recovers the LO if external software (e.g. SDR Console) left it powered down. RX LO (altvoltage0) is kept on — receive is continuous; QO-100 full-duplex still works (RX LO separate). Trade-off: re-enabling the TX LO re-runs the AD9361 synth calibration (a few ms), so the first syllable on SSB may be slightly clipped. Co-Authored-By: Claude Opus 4.8 --- PlutoBackend.pas | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/PlutoBackend.pas b/PlutoBackend.pas index 73ff256..629d637 100644 --- a/PlutoBackend.pas +++ b/PlutoBackend.pas @@ -85,6 +85,7 @@ type // Низкоуровневые помощники применения атрибутов к ad9361-phy procedure ApplyRxLO(Hz: Double); procedure ApplyTxLO(Hz: Double); + procedure SetTxLOPowerdown(PoweredOn: Boolean); // TX LO вкл/выкл (по PTT) procedure ApplySampleRate(Hz: Integer); procedure BuildTxResampler; // (пере)строить полифазные коэффициенты под FTxRatio procedure ApplyGain; @@ -562,7 +563,23 @@ begin if (FPhy = nil) or (Hz <= 0) then Exit; Ch := iio_device_find_channel(FPhy, 'altvoltage0', 1); if Ch <> nil then + begin + iio_channel_attr_write(Ch, 'powerdown', '0'); // вернуть LO, если внешнее ПО его погасило iio_channel_attr_write_longlong(Ch, 'frequency', Round(Hz)); + end; +end; + +procedure TPlutoBackend.SetTxLOPowerdown(PoweredOn: Boolean); +// TX LO (altvoltage1) вкл/выкл. Гасим на приёме → нет утечки несущей TX на частоте +// VFO в RX-спектре; включаем на PTT. Также возвращает LO, если стороннее ПО его +// погасило. RX LO (altvoltage0) не трогаем — приём непрерывен. +var Ch: Piio_channel; +begin + if FPhy = nil then Exit; + Ch := iio_device_find_channel(FPhy, 'altvoltage1', 1); + if Ch = nil then Exit; + if PoweredOn then iio_channel_attr_write(Ch, 'powerdown', '0') + else iio_channel_attr_write(Ch, 'powerdown', '1'); end; procedure TPlutoBackend.ApplyTxLO(Hz: Double); @@ -572,6 +589,8 @@ begin Ch := iio_device_find_channel(FPhy, 'altvoltage1', 1); if Ch <> nil then iio_channel_attr_write_longlong(Ch, 'frequency', Round(Hz)); + // powerdown TX LO по состоянию передачи (на приёме гасим — убирает спайк-утечку). + SetTxLOPowerdown(FTransmitting); end; procedure TPlutoBackend.ApplySampleRate(Hz: Integer); @@ -797,7 +816,9 @@ end; procedure TPlutoBackend.SendPTT(Active: Boolean); begin FTransmitting := Active; - // Реальный RX↔TX (вкл/выкл стримов) — фаза 4. + // TX LO включаем на передаче, гасим на приёме (нет утечки несущей в RX-спектр). + // TX-стрим живёт непрерывно (full-duplex); реальная мощность — через аттенюацию. + if FConnected then SetTxLOPowerdown(Active); end; procedure TPlutoBackend.SetRxGain(ModeIdx: Integer; GainDb: Integer);