From 09c9109491457e0da674f25505704286f3fb9b58 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 19 Jun 2026 21:20:57 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20Pluto=20TX=20drive=20mapping=20=E2=80=94?= =?UTF-8?q?=20power-linear=20+=20full=20digital=20level?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TUN produced no tone: TUNLevel default 10% mapped via the old dB-linear attenuation curve (−89.75..ceiling) to −81.8 dB → effectively off. Now power-linear: dB = ceiling + 20*log10(pct/100), so 10%→−30, 50%→−16, 100%→ceiling — usable across the whole slider. Also keep WDSP digital level at full-scale for Pluto (ApplyWDSPDrive): power is set once via hardware attenuation, not by scaling the WDSP path. HPSDR unchanged (drive byte still drives the radio PA). Note: at a given slider position Pluto TX is now much hotter than before (50%: −49.9→−16 dB). Ceiling stays PlutoTxMaxAttDb (default −10 dB). Co-Authored-By: Claude Opus 4.8 --- RadioController.pas | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/RadioController.pas b/RadioController.pas index 6fa1e75..9725ba6 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -463,6 +463,7 @@ type function PlutoTxAttForDrive: Double; // дБ<0 под текущий FDrivePercent procedure ApplyPlutoTxAtten; // ставит att по FTransmitting/FTuning procedure SetPlutoTxMaxAtt(Db: Double); // потолок на drive=100% (внешний усилитель) + procedure ApplyWDSPDrive(Pct: Integer); // цифровой drive WDSP: Pluto=1.0 (мощность — атт), HPSDR=Pct/100 // Диапазоны / трансвертеры / спан procedure SetBand(Idx: Integer); @@ -2104,7 +2105,7 @@ begin if V < 0 then V := 0 else if V > 100 then V := 100; FDrivePercent := V; FDriveLevel := CalcDriveByte; - if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetDriveLevel(FDrivePercent / 100.0); + ApplyWDSPDrive(FDrivePercent); ApplyPlutoTxAtten; // Pluto: drive живьём меняет TX-аттенюацию во время передачи PushNetworkState; // протолкнуть новый drive в радио (если подключено+Running) Changed(rfDrive); @@ -2122,8 +2123,10 @@ begin // На тюне (TUN) уровень берём из TX-настроек (TUNLevel), иначе из drive%. if FTuning then Pct := FTXSettings.TUNLevel else Pct := FDrivePercent; if Pct < 0 then Pct := 0 else if Pct > 100 then Pct := 100; - // dB-линейно: 0% → TX_OFF, 100% → FPlutoTxMaxAttDb (потолок под внешний тракт). - Result := TX_OFF + (Pct / 100.0) * (FPlutoTxMaxAttDb - TX_OFF); + if Pct <= 0 then begin Result := TX_OFF; Exit; end; // 0% → TX практически выкл + // power-linear: мощность ∝ drive%. dB = потолок + 20·log10(pct/100); 100% → потолок, + // 50% → −6 дБ, 10% → −20 дБ. (Раньше dB-линейно от −89.75 — низкие % улетали в −80 дБ.) + Result := FPlutoTxMaxAttDb + 20.0 * Log10(Pct / 100.0); if Result > FPlutoTxMaxAttDb then Result := FPlutoTxMaxAttDb; if Result < TX_OFF then Result := TX_OFF; end; @@ -2146,6 +2149,16 @@ begin SaveGlobalSettings; // персист потолка (per-device) end; +procedure TRadioController.ApplyWDSPDrive(Pct: Integer); +// На Pluto мощность задаётся ОДИН раз — железной аттенюацией (PlutoTxAttForDrive), +// поэтому цифровой уровень WDSP держим на максимуме (1.0), а не режем по drive%. +// HPSDR — как раньше, Pct/100 (реальная мощность там — drive-байт в радио). +begin + if not (FWDSPReady and Assigned(FDSPEngine)) then Exit; + if IsPluto then FDSPEngine.SetDriveLevel(1.0) + else FDSPEngine.SetDriveLevel(EnsureRange(Pct, 0, 100) / 100.0); +end; + procedure TRadioController.SetAtten(Idx: Integer); begin if Idx < 0 then Idx := 0 else if Idx > 2 then Idx := 2; @@ -2603,8 +2616,7 @@ begin FDSPEngine.SetTXTone(True, FTXSettings.TUNFreq, 1.0); FTuning := True; FDriveLevel := CalcDriveByte; // CalcDriveByte увидит FTuning=True (TUN-уровень) - if FWDSPReady and Assigned(FDSPEngine) then - FDSPEngine.SetDriveLevel(FTXSettings.TUNLevel / 100.0); + ApplyWDSPDrive(FTXSettings.TUNLevel); if not FTransmitting then SetMOX(True); // PTT + run TXA-канал end else @@ -2614,8 +2626,7 @@ begin FDSPEngine.SetTXTone(False, 0, 0); FTuning := False; FDriveLevel := CalcDriveByte; // вернуть обычный drive% - if FWDSPReady and Assigned(FDSPEngine) then - FDSPEngine.SetDriveLevel(FDrivePercent / 100.0); + ApplyWDSPDrive(FDrivePercent); if Assigned(FNetwork) and FNetwork.Connected and FNetwork.Running then begin FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslateTX(ActiveTXFreqHz),