mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
TX: фиксированный sample rate, per-device grid, CTUN-aware overlay, alpha-blend filter bands
Декаплинг TX от RX sample rate (как в Thetis):
- WDSPEngine.pas: константа TX_SAMPLE_RATE=192000, поля FTXSampleRate/FTXOutBufSize.
TXA OpenChannel теперь использует FTXSampleRate как out_rate, TX-анализатор
через SetDisplaySampleRate(TX_DISP_ID, FTXSampleRate). ProcessTXBlock работает
с FTXOutBufSize вместо FBufSize. Public TXSampleRate для MainForm.
- MainForm.SendDUCSpecificFromSettings: DUC0Rate теперь берётся из
FDSPEngine.TXSampleRate, а не из RX-настроек — TX всегда 192k независимо от
выбранного RX-rate (48/96/192/384k).
DUC Specific cache + keepalive resend (HPSDRNetwork.pas):
- FCachedDUCSpec/FCachedDUCValid параллельно DDC-кэшу.
- KeepAlive thread в первые 5s после Run=1 переотправляет и DDC, и DUC
Specific — устраняет гонку, когда DUC настройки терялись железом.
- Disconnect сбрасывает оба valid-флага.
Per-device TX grid settings (Thetis-style):
- Settings.pas: TXSpecRefLevel/TXSpecRange/TXSpecGridStep в TTXSettings
(defaults 0.0/80.0/10.0). LoadTX/SaveTX — ключи tx_spec_ref_level/range/grid_step.
- SettingsForm.pas: новая группа \"TX Grid\" во вкладке Transmit
(RefLevel edit, Range edit, GridStep combo). CollectTXFromUI читает значения,
LoadTXSettings заполняет UI.
- MainForm.pas: поля FTXSpecRefLevel/Range/GridStep, ApplySpecViewGridFromState
пушит в FSpecView либо TX, либо RX параметры в зависимости от FTransmitting.
ApplyGridParams (RX-путь) уважает FTransmitting и не перебивает TX-grid.
OnTXSettingsChange при активном TX моментально применяет новый grid.
TX-aware spectrum/waterfall с CTUN-выравниванием (SpectrumView.pas):
- Поля FTXMode/FTXFreq/FTXSpanHz/FTXVfoIndex. TXSpanHz=192000 при создании.
- DrawSpectrum/DrawWaterfall в FTXMode мапят данные TX-анализатора (192k вокруг
FTXFreq) в RX-координаты FCenterFreq/FSpanHz. Формула:
freq = FCenterFreq - FSpanHz/2 + x*FSpanHz/W
idx = (freq-FTXFreq + TXSpanHz/2)/TXSpanHz * (SrcCount-1)
Вне диапазона — спектр уходит в -200 dB; водопад копирует пиксель из
предыдущей строки (FWfPixels[X+W]) — вместо чёрной полосы продолжает
скроллиться старая RX-картинка.
- Эффект: при CTUN ON TX-сигнал рисуется на полосе фильтра (на VFO), а не в
центре. При RX rate ≠ 192k частотная сетка совпадает между RX и TX
автоматически (ruler всегда в RX-координатах).
- MainForm.SyncSpecViewFreq/ApplyMOX обновляют TXFreq/TXVfoIndex/TXMode при
каждом PTT и смене VFO; учитывается split (FSplitTxB → TXVfoIndex=1).
Alpha-blended filter bands (визуальный feedback TX/RX):
- SpectrumView: PixelFormat:=pf32bit, процедура BlendBand через ScanLine[Y]
внутри BeginUpdate/EndUpdate. Альфа-смешение по формуле
(a*src + (255-a)*dst) / 255 для каждого канала BGR.
- В FTXMode полоса фильтра становится полупрозрачно красной. Если split
(FTXVfoIndex<>FActiveVfo): на RX-частоте полоса зелёная, на TX-частоте —
красная (CalcFilterBandX вычисляет границы для произвольной VFO-freq).
- При FTXMode=False — старое поведение (сплошная заливка SpecFilter).
Build: lazbuild --ws=qt6 ewsdr.lpi — clean, 0 errors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,10 @@ type
|
||||
FCmbTXWfDet: TComboBox;
|
||||
FCmbTXWfAvg: TComboBox;
|
||||
FEdTXWfAvgTime: TFloatSpinEdit;
|
||||
// TX Grid (отдельные от RX grid в Display)
|
||||
FEdTXRefLevel: TEdit;
|
||||
FEdTXRange: TEdit;
|
||||
FCmbTXGridStep: TComboBox;
|
||||
|
||||
// ---- CAT tab controls ----
|
||||
FCATSerialEn: array[0..3] of TCheckBox;
|
||||
@@ -1084,6 +1088,37 @@ begin
|
||||
FCmbTXWfAvg.ItemIndex := 3;
|
||||
MakeLbl(Grp, 'Avg time (ms)', PAD + 430, R1 + 5 * STEP + 5, 100);
|
||||
FEdTXWfAvgTime := MkFloat(Grp, PAD + 540, R1 + 5 * STEP, 120.0, 1.0, 5000.0, 1.0);
|
||||
|
||||
// ---- TX Grid (RefLevel / Range / GridStep — отдельные от RX) ----
|
||||
Inc(Y, 290 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'TX Grid', MARGIN, Y, 700, 170);
|
||||
|
||||
MakeLbl(Grp, 'Reference level', PAD, R1 + 5, LW);
|
||||
FEdTXRefLevel := TEdit.Create(Self);
|
||||
FEdTXRefLevel.Parent := Grp;
|
||||
FEdTXRefLevel.SetBounds(CX, R1, 96, BTN_H);
|
||||
FEdTXRefLevel.Color := CLR_INPUT;
|
||||
FEdTXRefLevel.Font.Color := CLR_INPUT_TEXT;
|
||||
FEdTXRefLevel.Font.Name := UI_FONT;
|
||||
FEdTXRefLevel.Font.Size := 9;
|
||||
FEdTXRefLevel.Text := '0';
|
||||
FEdTXRefLevel.OnExit := OnTXAnyChange;
|
||||
|
||||
MakeLbl(Grp, 'Range (dB)', PAD, R1 + STEP + 5, LW);
|
||||
FEdTXRange := TEdit.Create(Self);
|
||||
FEdTXRange.Parent := Grp;
|
||||
FEdTXRange.SetBounds(CX, R1 + STEP, 96, BTN_H);
|
||||
FEdTXRange.Color := CLR_INPUT;
|
||||
FEdTXRange.Font.Color := CLR_INPUT_TEXT;
|
||||
FEdTXRange.Font.Name := UI_FONT;
|
||||
FEdTXRange.Font.Size := 9;
|
||||
FEdTXRange.Text := '80';
|
||||
FEdTXRange.OnExit := OnTXAnyChange;
|
||||
|
||||
MakeLbl(Grp, 'Grid step', PAD, R1 + 2 * STEP + 5, LW);
|
||||
FCmbTXGridStep := MkCmb(Grp, CX, R1 + 2 * STEP, 130);
|
||||
for i := 0 to High(GRID_STEP_NAMES) do FCmbTXGridStep.Items.Add(GRID_STEP_NAMES[i]);
|
||||
FCmbTXGridStep.ItemIndex := 1;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.CollectTXFromUI;
|
||||
@@ -1139,6 +1174,19 @@ begin
|
||||
if (FCmbTXWfAvg <> nil) and (FCmbTXWfAvg.ItemIndex >= 0) then
|
||||
FTX.TXWfAvgMode := WF_AVGMODE_VALUES[FCmbTXWfAvg.ItemIndex];
|
||||
if FEdTXWfAvgTime <> nil then FTX.TXWfAvgTimeMS := FEdTXWfAvgTime.Value;
|
||||
if FEdTXRefLevel <> nil then
|
||||
begin
|
||||
Val(FEdTXRefLevel.Text, FTX.TXSpecRefLevel, i);
|
||||
if i <> 0 then FTX.TXSpecRefLevel := 0.0;
|
||||
end;
|
||||
if FEdTXRange <> nil then
|
||||
begin
|
||||
Val(FEdTXRange.Text, FTX.TXSpecRange, i);
|
||||
if i <> 0 then FTX.TXSpecRange := 80.0;
|
||||
end;
|
||||
if (FCmbTXGridStep <> nil) and (FCmbTXGridStep.ItemIndex >= 0)
|
||||
and (FCmbTXGridStep.ItemIndex <= High(GRID_STEPS)) then
|
||||
FTX.TXSpecGridStep := GRID_STEPS[FCmbTXGridStep.ItemIndex];
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.FireTXChange;
|
||||
@@ -1241,6 +1289,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
if FEdTXWfAvgTime <> nil then FEdTXWfAvgTime.Value := T.TXWfAvgTimeMS;
|
||||
if FEdTXRefLevel <> nil then FEdTXRefLevel.Text := FormatFloat('0.#', T.TXSpecRefLevel);
|
||||
if FEdTXRange <> nil then FEdTXRange.Text := FormatFloat('0.#', T.TXSpecRange);
|
||||
if FCmbTXGridStep <> nil then
|
||||
begin
|
||||
FCmbTXGridStep.ItemIndex := 1; // дефолт 10 dB
|
||||
for i := 0 to High(GRID_STEPS) do
|
||||
if Abs(GRID_STEPS[i] - T.TXSpecGridStep) < 0.5 then
|
||||
begin
|
||||
FCmbTXGridStep.ItemIndex := i;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
FLoading := False;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user