feat: Pluto TX LO powerdown gated by PTT

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 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 22:07:06 +03:00
co-authored by Claude Opus 4.8
parent 2ab1f4f9ac
commit ff331fa2a0
+22 -1
View File
@@ -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);