mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
fix(tx): боковая по режиму на всех путях + единая оркестрация TX/RX (эталон Thetis)
Боковая TX теперь строится ЕДИНЫМ конвертером знака TXSignedEdges (порт Thetis UpdateTXLowHighFilterForMode): магнитуда TX-полосы → знаковые края bp0 по боковой режима. Через него идут ApplyTXChainSettings и SetTXFilterFull — LSB/DIGL больше не уходят в USB, когда пуш оказывается последним (MOX). Убраны оба SetTXABandpassRun(1): этот сеттер дёргает bp1 (aux), а не bp0. При выкл. компрессоре bp1 держал стартовую полосу (−5000,−100) и глушил вход модулятора — FM/WFM/FMRAW не заводились без «тычка» компрессором. bp1 отдан компрессору через TXASetupBPFilters, как в Thetis. Оркестрация сведена: ApplyTXMode (SetTXAMode+ApplyTXModeSettings) — единая точка TX-перехода для Open/SetMode/SetTXMode (в т.ч. слайс-TX); ApplyRXModeSettings (WFM/DMR/FMRAW) — для главного RXA и слайсов. Убраны ручной DMR-инлайн в SetMode и двойной вызов WFM; ApplyWFMSettings→ApplyTXWFMSettings. Дефолт TX-полосы 100/2800 → 200/3100 (Thetis-паритет). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -1253,8 +1253,8 @@ begin
|
||||
T.TUNLevel := 10;
|
||||
T.TUNFreq := 750;
|
||||
// SSB-фильтр по умолчанию
|
||||
T.FilterLow := 100;
|
||||
T.FilterHigh := 2800;
|
||||
T.FilterLow := 200;
|
||||
T.FilterHigh := 3100;
|
||||
T.FilterNC := 1024;
|
||||
T.FilterMP := 1; // Low Latency (как в piHPSDR)
|
||||
T.FilterWindow := 1; // BH4 / Blackman-Harris
|
||||
|
||||
+2
-2
@@ -1390,9 +1390,9 @@ begin
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'TX Filter (bandpass)', MARGIN, Y, GRP_W, 220);
|
||||
|
||||
MakeLbl(Grp, 'Low cut (Hz)', PAD, R1 + 5, LW);
|
||||
FEdTXFiltLow := MkSpin(Grp, CX, R1, 0, 8000, 100);
|
||||
FEdTXFiltLow := MkSpin(Grp, CX, R1, 0, 8000, 200);
|
||||
MakeLbl(Grp, 'High cut (Hz)', PAD + 320, R1 + 5, 90);
|
||||
FEdTXFiltHigh := MkSpin(Grp, PAD + 320 + 100, R1, 100, 12000, 2800);
|
||||
FEdTXFiltHigh := MkSpin(Grp, PAD + 320 + 100, R1, 100, 12000, 3100);
|
||||
|
||||
MakeLbl(Grp, 'FIR length', PAD, R1 + STEP + 5, LW);
|
||||
FCmbTXFiltNC := MkCmb(Grp, CX, R1 + STEP, 140);
|
||||
|
||||
+81
-31
@@ -493,10 +493,20 @@ type
|
||||
procedure ApplyRXWFMToChan(Chan: Integer);
|
||||
procedure ApplyRXDMRToChan(Chan: Integer);
|
||||
procedure ApplyRXRawToChan(Chan: Integer);
|
||||
procedure ApplyWFMSettings;
|
||||
procedure ApplyTXWFMSettings;
|
||||
// Единая RX-режимная надстройка канала (WFM/DMR/FM RAW). Одна точка для
|
||||
// главного RXA и для слайсов — иначе дублирование по трём местам.
|
||||
procedure ApplyRXModeSettings(Chan, Mode: Integer);
|
||||
// Магнитуда TX-полосы (FTXFilter*) → знаковые края bp0 по боковой режима.
|
||||
// Порт Thetis UpdateTXLowHighFilterForMode: единственный конвертер знака,
|
||||
// через который обязан идти ЛЮБОЙ пуш TX-bandpass, иначе LSB уходит в USB.
|
||||
procedure TXSignedEdges(Mode: Integer; out Lo, Hi: Double);
|
||||
// Mode-dependent TX overlay. FM RAW uses the flat WFM modulator and
|
||||
// bypasses every speech processor without overwriting the saved TX setup.
|
||||
procedure ApplyTXModeSettings(Mode: Integer);
|
||||
// ЕДИНАЯ точка перевода TX-тракта в режим (модулятор + режимная цепь).
|
||||
// Через неё идут ВСЕ переходы: Open, SetMode, SetTXMode (в т.ч. слайс-TX).
|
||||
procedure ApplyTXMode(Mode: Integer);
|
||||
// --- Мультислайсы ---
|
||||
function FindSliceIdx(Id: Integer): Integer; // -1 если нет
|
||||
function SliceInRate(Idx: Integer): Integer; // входной rate слайса (его пан)
|
||||
@@ -1159,15 +1169,50 @@ begin
|
||||
SetRXAWFMLimRun (Chan, 0);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.ApplyWFMSettings;
|
||||
procedure TWDSPEngine.ApplyTXWFMSettings;
|
||||
// TX-часть широкого ЧМ. RX-сторона WFM ставится через ApplyRXModeSettings.
|
||||
begin
|
||||
ApplyRXWFMToChan(RXA_CHAN);
|
||||
SetTXAWFMDeviation (TXA_CHAN, WFM_DEVIATION);
|
||||
SetTXAWFMAFFreqs (TXA_CHAN, WFM_AF_LOW, WFM_AF_HIGH);
|
||||
SetTXAWFMPreEmphRun (TXA_CHAN, 1);
|
||||
SetTXAWFMPreEmphTau (TXA_CHAN, WFM_TAU_DE_US);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.ApplyRXModeSettings(Chan, Mode: Integer);
|
||||
// Режимная RX-надстройка канала. Для «нормальных» режимов ничего не нужно —
|
||||
// всё делает SetRXAMode; спец-обвязку требуют только FM-семейства.
|
||||
begin
|
||||
if Mode = MODE_WFM then ApplyRXWFMToChan(Chan)
|
||||
else if Mode = MODE_DMR then ApplyRXDMRToChan(Chan)
|
||||
else if Mode = MODE_FMRAW then ApplyRXRawToChan(Chan);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.TXSignedEdges(Mode: Integer; out Lo, Hi: Double);
|
||||
// Порт Thetis UpdateTXLowHighFilterForMode. Вход — магнитуда TX-аудио-полосы
|
||||
// (FTXFilterLow/High, всегда положительная); выход — знаковые края bp0 под
|
||||
// боковую режима. Нижняя боковая зеркалит полосу в отрицательные частоты.
|
||||
var
|
||||
L, H, Half: Double;
|
||||
begin
|
||||
L := FTXFilterLow;
|
||||
H := FTXFilterHigh;
|
||||
case Mode of
|
||||
MODE_LSB, MODE_CWL, MODE_DIGL:
|
||||
begin Lo := -H; Hi := -L; end; // нижняя боковая
|
||||
MODE_USB, MODE_CWU, MODE_DIGU:
|
||||
begin Lo := L; Hi := H; end; // верхняя боковая
|
||||
MODE_DSB, MODE_AM, MODE_SAM:
|
||||
begin Lo := -H; Hi := H; end; // симметрично
|
||||
MODE_FM:
|
||||
begin // Карсон: ±(девиация + верхний срез)
|
||||
Half := FTXFMDeviation + FTXFMHighCut;
|
||||
Lo := -Half; Hi := Half;
|
||||
end;
|
||||
else
|
||||
begin Lo := L; Hi := H; end; // прочее — как есть
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.ApplyTXModeSettings(Mode: Integer);
|
||||
begin
|
||||
if not FInitialized then Exit;
|
||||
@@ -1180,7 +1225,6 @@ begin
|
||||
SetTXAWFMAFFreqs (TXA_CHAN, 20.0, 7000.0);
|
||||
SetTXAWFMPreEmphRun (TXA_CHAN, 0);
|
||||
SetTXABandpassFreqs (TXA_CHAN, 20.0, 7000.0);
|
||||
SetTXABandpassRun (TXA_CHAN, 1);
|
||||
SetTXAPanelGain1 (TXA_CHAN, 1.0);
|
||||
SetTXACompressorRun (TXA_CHAN, 0);
|
||||
SetTXALevelerSt (TXA_CHAN, 0);
|
||||
@@ -1192,12 +1236,22 @@ begin
|
||||
else
|
||||
begin
|
||||
// Restore the user's normal voice/data chain after leaving FM RAW.
|
||||
SetTXABandpassRun(TXA_CHAN, 1);
|
||||
// bp1 (aux bandpass) НЕ трогаем вручную — им управляет компрессор через
|
||||
// TXASetupBPFilters (как в Thetis). bp0 всегда активен сам.
|
||||
ApplyTXChainSettings;
|
||||
if Mode = MODE_WFM then ApplyWFMSettings;
|
||||
if Mode = MODE_WFM then ApplyTXWFMSettings;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.ApplyTXMode(Mode: Integer);
|
||||
// ЕДИНАЯ точка перевода TX-тракта в режим. SetTXAMode пересобирает модулятор и
|
||||
// bp0/bp1 под режим (TXASetupBPFilters), ApplyTXModeSettings кладёт режимную цепь.
|
||||
begin
|
||||
if not FInitialized then Exit;
|
||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(Mode));
|
||||
ApplyTXModeSettings(Mode);
|
||||
end;
|
||||
|
||||
function TWDSPEngine.ClampToNyquist(Hz, Rate: Integer): Integer;
|
||||
var Limit: Integer;
|
||||
begin
|
||||
@@ -1340,8 +1394,8 @@ begin
|
||||
FillChar(FTXMicRing, SizeOf(FTXMicRing), 0);
|
||||
|
||||
// TX-цепь — дефолты, согласуются с Settings.DefaultTX
|
||||
FTXFilterLow := 100;
|
||||
FTXFilterHigh := 2800;
|
||||
FTXFilterLow := 200;
|
||||
FTXFilterHigh := 3100;
|
||||
FTXFilterNC := 1024;
|
||||
FTXFilterMP := 1;
|
||||
FTXFilterWindow := 1;
|
||||
@@ -1741,7 +1795,6 @@ begin
|
||||
);
|
||||
|
||||
FTXMode := FMode;
|
||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(FTXMode));
|
||||
SetTXAPanelRun(TXA_CHAN, 1);
|
||||
// PatchPanel: 1=Q, 2=I. Mic подаётся в I (FTXIn[i*2]), Q=0 — выбираем I.
|
||||
SetTXAPanelSelect(TXA_CHAN, 2);
|
||||
@@ -1753,12 +1806,14 @@ begin
|
||||
// SetFilter пересчитает полосу уже под новый dsp_rate.
|
||||
if FMode = MODE_WFM then
|
||||
begin
|
||||
SetMode(FMode);
|
||||
SetMode(FMode); // внутри: ApplyRXModeSettings + ApplyTXMode
|
||||
SetFilter(FFilterLow, FFilterHigh);
|
||||
end;
|
||||
// Прокидываем все TX-параметры из FTX*-полей: фильтр, mic gain, EQ,
|
||||
// Leveler, ALC, Compressor, Phase Rotator, AM Carrier, FM, CTCSS.
|
||||
ApplyTXChainSettings;
|
||||
// Перевод TX-тракта в режим через единую точку (для WFM уже сделал SetMode).
|
||||
if FMode <> MODE_WFM then ApplyTXMode(FTXMode);
|
||||
ApplyNoiseFilterState;
|
||||
|
||||
// Переоткрываем WDSP-каналы активных слайсов (например после ChangeSampleRate,
|
||||
@@ -2382,9 +2437,7 @@ begin
|
||||
create_nobEXT(Chan, 1, 0, InSize, InRate, 0.0001, 0.0001, 0.0001, 0.05, 20);
|
||||
SetRXABandpassWindow(Chan, 1);
|
||||
SetRXAMode(Chan, ModeToWDSP(FSlices[Idx].Mode));
|
||||
if FSlices[Idx].Mode = MODE_WFM then ApplyRXWFMToChan(Chan);
|
||||
if FSlices[Idx].Mode = MODE_DMR then ApplyRXDMRToChan(Chan);
|
||||
if FSlices[Idx].Mode = MODE_FMRAW then ApplyRXRawToChan(Chan);
|
||||
ApplyRXModeSettings(Chan, FSlices[Idx].Mode);
|
||||
SetRXAShiftRun(Chan, 1);
|
||||
SetRXAShiftFreq(Chan, FSlices[Idx].ShiftHz);
|
||||
RXASetPassband(Chan, ClampToNyquist(FSlices[Idx].FilterLo, DSPRate),
|
||||
@@ -2688,9 +2741,7 @@ begin
|
||||
else if FSlices[idx].Opened then
|
||||
begin
|
||||
SetRXAMode(FSlices[idx].Chan, ModeToWDSP(Mode));
|
||||
if Mode = MODE_WFM then ApplyRXWFMToChan(FSlices[idx].Chan);
|
||||
if Mode = MODE_DMR then ApplyRXDMRToChan(FSlices[idx].Chan);
|
||||
if Mode = MODE_FMRAW then ApplyRXRawToChan(FSlices[idx].Chan);
|
||||
ApplyRXModeSettings(FSlices[idx].Chan, Mode);
|
||||
if Mode in [MODE_DMR, MODE_FMRAW] then
|
||||
SetRXAPanelGain1(FSlices[idx].Chan, 1.0)
|
||||
else
|
||||
@@ -2895,16 +2946,8 @@ begin
|
||||
// а SetRXAMode затем пересчитает bpsnba под уже актуальный dsp_rate.
|
||||
ApplyDSPRate(Mode);
|
||||
SetRXAMode(RXA_CHAN, ModeToWDSP(Mode));
|
||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(Mode));
|
||||
if Mode = MODE_WFM then ApplyWFMSettings
|
||||
else if Mode = MODE_DMR then
|
||||
begin
|
||||
SetRXAWFMDeviation (RXA_CHAN, DMR_DEVIATION);
|
||||
SetRXAWFMAFFilter (RXA_CHAN, 20.0, 7000.0);
|
||||
SetRXAWFMDeemphRun (RXA_CHAN, 0);
|
||||
end
|
||||
else if Mode = MODE_FMRAW then ApplyRXRawToChan(RXA_CHAN);
|
||||
ApplyTXModeSettings(FTXMode);
|
||||
ApplyRXModeSettings(RXA_CHAN, Mode);
|
||||
ApplyTXMode(FTXMode);
|
||||
// НЕ вызываем ApplyDefaultFilter — фильтр устанавливается явно из UI
|
||||
end;
|
||||
|
||||
@@ -3202,8 +3245,7 @@ procedure TWDSPEngine.SetTXMode(Mode: Integer);
|
||||
begin
|
||||
FTXMode := Mode;
|
||||
if not FInitialized then Exit;
|
||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(FTXMode));
|
||||
ApplyTXModeSettings(FTXMode);
|
||||
ApplyTXMode(FTXMode);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetTXFilter(Low, High: Integer);
|
||||
@@ -3498,12 +3540,17 @@ procedure TWDSPEngine.ApplyTXChainSettings;
|
||||
var
|
||||
i: Integer;
|
||||
Gains, Freqs, Qs: array[0..10] of Double;
|
||||
BpLo, BpHi: Double;
|
||||
begin
|
||||
if not FInitialized then Exit;
|
||||
|
||||
// Bandpass
|
||||
// Bandpass — магнитуду TX-полосы прогоняем через знак боковой режима
|
||||
// (иначе LSB/DIGL уходят в USB, когда этот пуш оказывается последним, напр. MOX).
|
||||
if (FTXFilterLow > 0) and (FTXFilterHigh > FTXFilterLow) then
|
||||
SetTXABandpassFreqs(TXA_CHAN, FTXFilterLow, FTXFilterHigh);
|
||||
begin
|
||||
TXSignedEdges(FTXMode, BpLo, BpHi);
|
||||
SetTXABandpassFreqs(TXA_CHAN, BpLo, BpHi);
|
||||
end;
|
||||
if FTXFilterWindow >= 0 then
|
||||
SetTXABandpassWindow(TXA_CHAN, FTXFilterWindow);
|
||||
if FTXFilterNC > 0 then
|
||||
@@ -3672,6 +3719,7 @@ begin
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetTXFilterFull(Low, High, NC, MP, Window: Integer);
|
||||
var BpLo, BpHi: Double;
|
||||
begin
|
||||
FTXFilterLow := Low;
|
||||
FTXFilterHigh := High;
|
||||
@@ -3681,7 +3729,9 @@ begin
|
||||
FFilterLow := Low;
|
||||
FFilterHigh := High;
|
||||
if not FInitialized then Exit;
|
||||
SetTXABandpassFreqs(TXA_CHAN, Low, High);
|
||||
// Магнитуда диалога → знаковые края под боковую режима (см. TXSignedEdges).
|
||||
TXSignedEdges(FTXMode, BpLo, BpHi);
|
||||
SetTXABandpassFreqs(TXA_CHAN, BpLo, BpHi);
|
||||
SetTXABandpassWindow(TXA_CHAN, Window);
|
||||
if NC > 0 then TXASetNC(TXA_CHAN, EffectiveTXNC);
|
||||
if MP >= 0 then TXASetMP(TXA_CHAN, MP);
|
||||
|
||||
Reference in New Issue
Block a user