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:
+6
-2
@@ -6154,8 +6154,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
PanViewWindow(P, VC, VS);
|
PanViewWindow(P, VC, VS);
|
||||||
NewHz := FPanCenterDragF0 - (X - FPanCenterDragX0) * VS / W;
|
NewHz := FPanCenterDragF0 - (X - FPanCenterDragX0) * VS / W;
|
||||||
NewHz := Max(FController.BackendCaps.MinFreqHz,
|
// Кламп в ВИДИМЫХ частотах: при активном XVTR — его диапазон (иначе
|
||||||
Min(FController.BackendCaps.MaxFreqHz, NewHz));
|
// 1296 МГц «падала» на MaxFreqHz железа ~61 МГц), без XVTR — железо.
|
||||||
|
FController.VisibleFreqBounds(LoHz, HiHz);
|
||||||
|
NewHz := Max(LoHz, Min(HiHz, NewHz));
|
||||||
FController.SetPanDDCFreq(P.PanId, NewHz);
|
FController.SetPanDDCFreq(P.PanId, NewHz);
|
||||||
SyncPanZoomUI(P); // окно вьюхи с учётом зума + freq зум-бара
|
SyncPanZoomUI(P); // окно вьюхи с учётом зума + freq зум-бара
|
||||||
P.LayoutFlags;
|
P.LayoutFlags;
|
||||||
@@ -6885,6 +6887,8 @@ begin
|
|||||||
DeactivateXvtr;
|
DeactivateXvtr;
|
||||||
// Перепрошить XVTR в сеть (если параметры текущего изменились)
|
// Перепрошить XVTR в сеть (если параметры текущего изменились)
|
||||||
ApplyXvtrToNetwork;
|
ApplyXvtrToNetwork;
|
||||||
|
// Правка LO/LOError при живых панах: freq-слова их DDC — через свежую трансляцию.
|
||||||
|
FController.RefreshPanDDCs;
|
||||||
UpdateWidebandFrequencyView;
|
UpdateWidebandFrequencyView;
|
||||||
if PbWideband <> nil then PbWideband.Invalidate;
|
if PbWideband <> nil then PbWideband.Invalidate;
|
||||||
if PbWidebandRuler <> nil then PbWidebandRuler.Invalidate;
|
if PbWidebandRuler <> nil then PbWidebandRuler.Invalidate;
|
||||||
|
|||||||
+72
-10
@@ -565,13 +565,21 @@ type
|
|||||||
function SliceFitsCapture(TargetHz: Double; PanId: Integer = 0): Boolean;
|
function SliceFitsCapture(TargetHz: Double; PanId: Integer = 0): Boolean;
|
||||||
|
|
||||||
// ---- Панадаптеры на аппаратных DDC (этап 3.1; UI/движок — 3.2/3.3) ----
|
// ---- Панадаптеры на аппаратных DDC (этап 3.1; UI/движок — 3.2/3.3) ----
|
||||||
// Создаёт пан PanId (1..MAX_PANS-1) на своём DDC: FreqHz = центр (сырые Гц
|
// Создаёт пан PanId (1..MAX_PANS-1) на своём DDC: FreqHz = центр в ВИДИМЫХ
|
||||||
// железа, XVTR-трансляции у панов нет), RateKHz ∈ PanRateAllowed (иначе 384),
|
// Гц (как FVfoA/FCenterFreq: при активном XVTR транслируется в IF только
|
||||||
// ADCSource — АЦП платы. False = нет слота/бэкенд не умеет/не Running.
|
// на границе с железом, XvtrTranslate), RateKHz ∈ PanRateAllowed (иначе
|
||||||
|
// 384), ADCSource — АЦП платы. False = нет слота/бэкенд не умеет/не Running.
|
||||||
function AddPanDDC(PanId: Integer; FreqHz: Double; RateKHz: Word = 384;
|
function AddPanDDC(PanId: Integer; FreqHz: Double; RateKHz: Word = 384;
|
||||||
ADCSource: Byte = 0): Boolean;
|
ADCSource: Byte = 0): Boolean;
|
||||||
procedure RemovePanDDC(PanId: Integer);
|
procedure RemovePanDDC(PanId: Integer);
|
||||||
procedure SetPanDDCFreq(PanId: Integer; FreqHz: Double); // ретюн (HP-пакет)
|
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 кГц (движок).
|
// Rate ∈ сетке бэкенда (Caps.RatePresets) и кратен 48 кГц (движок).
|
||||||
function PanRateAllowed(RateKHz: Word): Boolean;
|
function PanRateAllowed(RateKHz: Word): Boolean;
|
||||||
// Смена rate живого пана: движок переоткрывает аккумулятор/анализатор/слайсы,
|
// Смена rate живого пана: движок переоткрывает аккумулятор/анализатор/слайсы,
|
||||||
@@ -1252,7 +1260,8 @@ begin
|
|||||||
FPanZoomF[PanId] := 0.0;
|
FPanZoomF[PanId] := 0.0;
|
||||||
FPanPanSl[PanId] := 0.5;
|
FPanPanSl[PanId] := 0.5;
|
||||||
FDDCPanMap[ddc] := PanId;
|
FDDCPanMap[ddc] := PanId;
|
||||||
FNetwork.SetPanDDC(ddc, True, FreqHz, RateKHz, ADCSource);
|
// В железо — IF-частота: FPanFreqHz хранит видимую (как FCenterFreq).
|
||||||
|
FNetwork.SetPanDDC(ddc, True, XvtrTranslate(FreqHz), RateKHz, ADCSource);
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -1270,10 +1279,10 @@ begin
|
|||||||
if FWDSPReady and not FDSPEngine.SetPanRate(PanId, Integer(RateKHz) * 1000) then
|
if FWDSPReady and not FDSPEngine.SetPanRate(PanId, Integer(RateKHz) * 1000) then
|
||||||
Exit;
|
Exit;
|
||||||
FPanRateKHz[PanId] := RateKHz;
|
FPanRateKHz[PanId] := RateKHz;
|
||||||
// DDC железа: реконфиг rate (RebuildDDCSpecific + freq-слово).
|
// DDC железа: реконфиг rate (RebuildDDCSpecific + freq-слово, IF при XVTR).
|
||||||
if Assigned(FNetwork) then
|
if Assigned(FNetwork) then
|
||||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, FPanFreqHz[PanId], RateKHz,
|
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, XvtrTranslate(FPanFreqHz[PanId]),
|
||||||
FPanADC[PanId]);
|
RateKHz, FPanADC[PanId]);
|
||||||
// Слайсы, выпавшие из сузившейся полосы, — к её краям (абс. TargetHz + NCO).
|
// Слайсы, выпавшие из сузившейся полосы, — к её краям (абс. TargetHz + NCO).
|
||||||
CapturedSpan(LoHz, HiHz, PanId);
|
CapturedSpan(LoHz, HiHz, PanId);
|
||||||
for i := 0 to MAX_SLICES - 1 do
|
for i := 0 to MAX_SLICES - 1 do
|
||||||
@@ -1312,9 +1321,9 @@ var i: Integer;
|
|||||||
begin
|
begin
|
||||||
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
||||||
if FPanDDCIdx[PanId] < 0 then Exit;
|
if FPanDDCIdx[PanId] < 0 then Exit;
|
||||||
FPanFreqHz[PanId] := FreqHz;
|
FPanFreqHz[PanId] := FreqHz; // видимая; в железо — IF при активном XVTR
|
||||||
if Assigned(FNetwork) then
|
if Assigned(FNetwork) then
|
||||||
FNetwork.SetPanDDCFreq(FPanDDCIdx[PanId], FreqHz);
|
FNetwork.SetPanDDCFreq(FPanDDCIdx[PanId], XvtrTranslate(FreqHz));
|
||||||
// Слайсы пана держат абсолютный TargetHz — обновляем их NCO-сдвиги
|
// Слайсы пана держат абсолютный TargetHz — обновляем их NCO-сдвиги
|
||||||
// относительно нового центра (аналог RefreshSliceShifts главного).
|
// относительно нового центра (аналог RefreshSliceShifts главного).
|
||||||
if Assigned(FDSPEngine) then
|
if Assigned(FDSPEngine) then
|
||||||
@@ -1323,6 +1332,57 @@ begin
|
|||||||
FDSPEngine.SetSliceShift(FSlices[i].Id, FSlices[i].TargetHz - FreqHz);
|
FDSPEngine.SetSliceShift(FSlices[i].Id, FSlices[i].TargetHz - FreqHz);
|
||||||
end;
|
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;
|
function TRadioController.PanDDCActive(PanId: Integer): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := (PanId >= 1) and (PanId < MAX_PANS) and (FPanDDCIdx[PanId] >= 0);
|
Result := (PanId >= 1) and (PanId < MAX_PANS) and (FPanDDCIdx[PanId] >= 0);
|
||||||
@@ -1364,7 +1424,7 @@ begin
|
|||||||
if not PanDDCActive(PanId) then Exit;
|
if not PanDDCActive(PanId) then Exit;
|
||||||
if FPanADC[PanId] = ADC then Exit(True);
|
if FPanADC[PanId] = ADC then Exit(True);
|
||||||
FPanADC[PanId] := ADC;
|
FPanADC[PanId] := ADC;
|
||||||
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, FPanFreqHz[PanId],
|
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, XvtrTranslate(FPanFreqHz[PanId]),
|
||||||
FPanRateKHz[PanId], ADC);
|
FPanRateKHz[PanId], ADC);
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
@@ -3007,6 +3067,7 @@ begin
|
|||||||
// QO-100 / split-LO: авто display-duplex (мониторинг своего downlink при TX).
|
// QO-100 / split-LO: авто display-duplex (мониторинг своего downlink при TX).
|
||||||
if E.FullDuplexTx and not FDisplayDuplex then SetDuplex(True);
|
if E.FullDuplexTx and not FDisplayDuplex then SetDuplex(True);
|
||||||
PushNetworkState;
|
PushNetworkState;
|
||||||
|
RefreshPanDDCs; // живые паны — в диапазон XVTR, DDC — на IF
|
||||||
|
|
||||||
Changed(rfXvtr);
|
Changed(rfXvtr);
|
||||||
Changed(rfActiveVfo);
|
Changed(rfActiveVfo);
|
||||||
@@ -3023,6 +3084,7 @@ begin
|
|||||||
if FDevConnected then FSettings.Save;
|
if FDevConnected then FSettings.Save;
|
||||||
FCurrentXvtr := -1;
|
FCurrentXvtr := -1;
|
||||||
ApplyXvtrToNetwork; // снять XVTR enable bit
|
ApplyXvtrToNetwork; // снять XVTR enable bit
|
||||||
|
RefreshPanDDCs; // живые паны — обратно в пределы железа
|
||||||
if (FCurrentBand >= 0) and (FCurrentBand < CFG_BAND_COUNT) then
|
if (FCurrentBand >= 0) and (FCurrentBand < CFG_BAND_COUNT) then
|
||||||
RestoreBand(FCurrentBand); // HF-возврат (состояние/DSP/retune)
|
RestoreBand(FCurrentBand); // HF-возврат (состояние/DSP/retune)
|
||||||
Changed(rfXvtr); // погасить XVTR-кнопки + wideband/web (rfXvtr-рендер)
|
Changed(rfXvtr); // погасить XVTR-кнопки + wideband/web (rfXvtr-рендер)
|
||||||
|
|||||||
Reference in New Issue
Block a user