mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(slices): XVTR-трансляция частот панов N
Частота пана хранится ВИДИМОЙ (как FVfoA/FCenterFreq) и транслируется в IF через XvtrTranslate только на границе с железом (AddPanDDC, SetPanDDCFreq, SetPanDDCRate, SetPanADC) — раньше DDC пана получал видимую частоту сырьём, а drag водопада пана N клампился пределами АЦП (~61 МГц) вместо диапазона трансвертера. Новое: controller.VisibleFreqBounds (диапазон активного XVTR | пределы железа) для UI-клампа драга; RefreshPanDDCs — на входе/выходе XVTR и правке LO/LOError клампит видимые центры живых панов, перешивает freq-слова DDC и прижимает выпавшие слайсы к краям полосы захвата. Подтверждено юзером на трансвертере. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+72
-10
@@ -565,13 +565,21 @@ type
|
||||
function SliceFitsCapture(TargetHz: Double; PanId: Integer = 0): Boolean;
|
||||
|
||||
// ---- Панадаптеры на аппаратных DDC (этап 3.1; UI/движок — 3.2/3.3) ----
|
||||
// Создаёт пан PanId (1..MAX_PANS-1) на своём DDC: FreqHz = центр (сырые Гц
|
||||
// железа, XVTR-трансляции у панов нет), RateKHz ∈ PanRateAllowed (иначе 384),
|
||||
// ADCSource — АЦП платы. False = нет слота/бэкенд не умеет/не Running.
|
||||
// Создаёт пан PanId (1..MAX_PANS-1) на своём DDC: FreqHz = центр в ВИДИМЫХ
|
||||
// Гц (как FVfoA/FCenterFreq: при активном XVTR транслируется в IF только
|
||||
// на границе с железом, XvtrTranslate), RateKHz ∈ PanRateAllowed (иначе
|
||||
// 384), ADCSource — АЦП платы. False = нет слота/бэкенд не умеет/не Running.
|
||||
function AddPanDDC(PanId: Integer; FreqHz: Double; RateKHz: Word = 384;
|
||||
ADCSource: Byte = 0): Boolean;
|
||||
procedure RemovePanDDC(PanId: Integer);
|
||||
procedure SetPanDDCFreq(PanId: Integer; FreqHz: Double); // ретюн (HP-пакет)
|
||||
// Допустимое окно ВИДИМОЙ частоты пана: активный XVTR — его диапазон,
|
||||
// иначе пределы железа (UI-кламп drag/тюна панов N).
|
||||
procedure VisibleFreqBounds(out LoHz, HiHz: Double);
|
||||
// Вход/выход/перекалибровка XVTR при живых панах: клампит видимые частоты
|
||||
// панов в новое окно, перешивает freq-слова DDC (XvtrTranslate), слайсы
|
||||
// панов — к краям их полос захвата.
|
||||
procedure RefreshPanDDCs;
|
||||
// Rate ∈ сетке бэкенда (Caps.RatePresets) и кратен 48 кГц (движок).
|
||||
function PanRateAllowed(RateKHz: Word): Boolean;
|
||||
// Смена rate живого пана: движок переоткрывает аккумулятор/анализатор/слайсы,
|
||||
@@ -1252,7 +1260,8 @@ begin
|
||||
FPanZoomF[PanId] := 0.0;
|
||||
FPanPanSl[PanId] := 0.5;
|
||||
FDDCPanMap[ddc] := PanId;
|
||||
FNetwork.SetPanDDC(ddc, True, FreqHz, RateKHz, ADCSource);
|
||||
// В железо — IF-частота: FPanFreqHz хранит видимую (как FCenterFreq).
|
||||
FNetwork.SetPanDDC(ddc, True, XvtrTranslate(FreqHz), RateKHz, ADCSource);
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
@@ -1270,10 +1279,10 @@ begin
|
||||
if FWDSPReady and not FDSPEngine.SetPanRate(PanId, Integer(RateKHz) * 1000) then
|
||||
Exit;
|
||||
FPanRateKHz[PanId] := RateKHz;
|
||||
// DDC железа: реконфиг rate (RebuildDDCSpecific + freq-слово).
|
||||
// DDC железа: реконфиг rate (RebuildDDCSpecific + freq-слово, IF при XVTR).
|
||||
if Assigned(FNetwork) then
|
||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, FPanFreqHz[PanId], RateKHz,
|
||||
FPanADC[PanId]);
|
||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, XvtrTranslate(FPanFreqHz[PanId]),
|
||||
RateKHz, FPanADC[PanId]);
|
||||
// Слайсы, выпавшие из сузившейся полосы, — к её краям (абс. TargetHz + NCO).
|
||||
CapturedSpan(LoHz, HiHz, PanId);
|
||||
for i := 0 to MAX_SLICES - 1 do
|
||||
@@ -1312,9 +1321,9 @@ var i: Integer;
|
||||
begin
|
||||
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
||||
if FPanDDCIdx[PanId] < 0 then Exit;
|
||||
FPanFreqHz[PanId] := FreqHz;
|
||||
FPanFreqHz[PanId] := FreqHz; // видимая; в железо — IF при активном XVTR
|
||||
if Assigned(FNetwork) then
|
||||
FNetwork.SetPanDDCFreq(FPanDDCIdx[PanId], FreqHz);
|
||||
FNetwork.SetPanDDCFreq(FPanDDCIdx[PanId], XvtrTranslate(FreqHz));
|
||||
// Слайсы пана держат абсолютный TargetHz — обновляем их NCO-сдвиги
|
||||
// относительно нового центра (аналог RefreshSliceShifts главного).
|
||||
if Assigned(FDSPEngine) then
|
||||
@@ -1323,6 +1332,57 @@ begin
|
||||
FDSPEngine.SetSliceShift(FSlices[i].Id, FSlices[i].TargetHz - FreqHz);
|
||||
end;
|
||||
|
||||
procedure TRadioController.VisibleFreqBounds(out LoHz, HiHz: Double);
|
||||
begin
|
||||
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT) and
|
||||
FXvtrSettings.Entries[FCurrentXvtr].Enabled then
|
||||
begin
|
||||
// Активный XVTR: видимые частоты живут в его диапазоне, в железо уходит
|
||||
// IF (XvtrTranslate) — клампить видимую частоту пределами АЦП нельзя.
|
||||
LoHz := FXvtrSettings.Entries[FCurrentXvtr].FreqBegin;
|
||||
HiHz := FXvtrSettings.Entries[FCurrentXvtr].FreqEnd;
|
||||
end
|
||||
else if Assigned(FNetwork) then
|
||||
begin
|
||||
LoHz := FNetwork.Caps.MinFreqHz;
|
||||
HiHz := FNetwork.Caps.MaxFreqHz;
|
||||
end
|
||||
else
|
||||
begin
|
||||
LoHz := 0;
|
||||
HiHz := 61440000;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRadioController.RefreshPanDDCs;
|
||||
var
|
||||
p, i: Integer;
|
||||
LoV, HiV, LoHz, HiHz: Double;
|
||||
begin
|
||||
VisibleFreqBounds(LoV, HiV);
|
||||
for p := 1 to MAX_PANS - 1 do
|
||||
if PanDDCActive(p) then
|
||||
begin
|
||||
// Видимый центр пана — в новое допустимое окно, freq-слово DDC — через
|
||||
// свежую трансляцию (вход/выход XVTR, правка LO/LOError).
|
||||
FPanFreqHz[p] := EnsureRange(FPanFreqHz[p], LoV, HiV);
|
||||
if Assigned(FNetwork) then
|
||||
FNetwork.SetPanDDCFreq(FPanDDCIdx[p], XvtrTranslate(FPanFreqHz[p]));
|
||||
// Слайсы держат абсолютный видимый TargetHz: выпавшие из полосы захвата
|
||||
// пана — к её краям (SetSliceTarget обновит NCO), остальные — свежий NCO.
|
||||
CapturedSpan(LoHz, HiHz, p);
|
||||
for i := 0 to MAX_SLICES - 1 do
|
||||
if FSlices[i].Active and (FSlices[i].PanId = p) then
|
||||
begin
|
||||
if FSlices[i].TargetHz < LoHz then SetSliceTarget(FSlices[i].Id, LoHz)
|
||||
else if FSlices[i].TargetHz > HiHz then SetSliceTarget(FSlices[i].Id, HiHz)
|
||||
else if Assigned(FDSPEngine) then
|
||||
FDSPEngine.SetSliceShift(FSlices[i].Id,
|
||||
FSlices[i].TargetHz - FPanFreqHz[p]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TRadioController.PanDDCActive(PanId: Integer): Boolean;
|
||||
begin
|
||||
Result := (PanId >= 1) and (PanId < MAX_PANS) and (FPanDDCIdx[PanId] >= 0);
|
||||
@@ -1364,7 +1424,7 @@ begin
|
||||
if not PanDDCActive(PanId) then Exit;
|
||||
if FPanADC[PanId] = ADC then Exit(True);
|
||||
FPanADC[PanId] := ADC;
|
||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, FPanFreqHz[PanId],
|
||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, XvtrTranslate(FPanFreqHz[PanId]),
|
||||
FPanRateKHz[PanId], ADC);
|
||||
Result := True;
|
||||
end;
|
||||
@@ -3007,6 +3067,7 @@ begin
|
||||
// QO-100 / split-LO: авто display-duplex (мониторинг своего downlink при TX).
|
||||
if E.FullDuplexTx and not FDisplayDuplex then SetDuplex(True);
|
||||
PushNetworkState;
|
||||
RefreshPanDDCs; // живые паны — в диапазон XVTR, DDC — на IF
|
||||
|
||||
Changed(rfXvtr);
|
||||
Changed(rfActiveVfo);
|
||||
@@ -3023,6 +3084,7 @@ begin
|
||||
if FDevConnected then FSettings.Save;
|
||||
FCurrentXvtr := -1;
|
||||
ApplyXvtrToNetwork; // снять XVTR enable bit
|
||||
RefreshPanDDCs; // живые паны — обратно в пределы железа
|
||||
if (FCurrentBand >= 0) and (FCurrentBand < CFG_BAND_COUNT) then
|
||||
RestoreBand(FCurrentBand); // HF-возврат (состояние/DSP/retune)
|
||||
Changed(rfXvtr); // погасить XVTR-кнопки + wideband/web (rfXvtr-рендер)
|
||||
|
||||
Reference in New Issue
Block a user