mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat: QO-100 decoder-based beacon lock (replace FFT lock)
Replace the display-FFT centroid beacon lock with a decoder-based loop. The beacon decoder already tracks the carrier precisely via its NCO (squaring-FFT acquisition + Costas offload); its residual ResidHz+CarFreqHz is an exact measurement of the beacon's offset from the aim point. Feed that into LOError of the active transverter so the LO retunes to compensate LNB drift — the whole downlink stays put, calibration persists. RadioController: - Remove MeasureBeaconFFT and all display-FFT lock state/constants (lobe/search/track/slew/sym/shape/seed-gain/prom), fields FBeaconManualSeed/FBeaconPromDB/FBeaconDecOn, methods SetBeaconDecode/SetBeaconDecodeAtHz/BeaconDecodeEnabled. - SetBeaconLock is now the master switch (lock = decoder); BeaconSeedAtHz aims the decoder; ServiceBeaconLock measures beacon freq from the decoder scope and trims LOError (gain 0.5, deadband 20 Hz, step clamp 400 Hz, settle 8 ticks). Feed-forward of the aim keeps the decoder locked through the retune (net baseband ~0). Lock/SNR now come from the decoder. MainForm: single BEACON button — left-click toggles lock (+ opens the constellation/bulletin scope, arms the spectrum click for aiming), right-click shows/hides the scope. Spectrum click (armed or Shift) aims via BeaconSeedAtHz. Simplified status field and markers. Both targets build (lazbuild --ws=qt6 + build-ewsdrd.sh). Not yet verified on air. Risk: BEACON_RESID_SIGN=+1.0 — flip to -1.0 if the loop runs away. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+27
-39
@@ -135,7 +135,6 @@ type
|
||||
FSpecDragX0: Integer; // X при нажатии
|
||||
FSpecDragFreq: Double; // FCenterFreq при нажатии
|
||||
FBeaconArming: Boolean; // ждём клик по маяку (после включения BEACON)
|
||||
FBeaconDecArming: Boolean; // ждём клик: навести узкий фильтр декодера на маяк
|
||||
FSpectrumDirty: Boolean; // таймер должен перерисовать спектр/водопад
|
||||
// TX DUC-очередь (FDUCPending*) переехала в TRadioController (OnTXIQ).
|
||||
FSMeterPeak: Double; // верхняя граница светлой зоны
|
||||
@@ -3278,15 +3277,12 @@ function TMainForm.BeaconStatusText: string;
|
||||
// Компактный статус QO-100 beacon lock для поля 7 статус-бара (Pluto). Courier 8pt,
|
||||
// поле ~200px → держим ≤ ~24 символов.
|
||||
begin
|
||||
if FBeaconDecArming then Exit('DEC: click beacon');
|
||||
if FController.BeaconDecodeEnabled and (FController.BeaconDecodeFreqHz > 0) then
|
||||
Exit('DEC: shift-click=re-aim');
|
||||
if not FController.BeaconLockEnabled then Exit('BCN: off');
|
||||
if FBeaconArming then Exit('BCN: click beacon');
|
||||
if FController.BeaconDecodeFreqHz <= 0 then Exit('BCN: click beacon');
|
||||
case FController.BeaconState of
|
||||
bsLock: Result := Format('BCN LOCK %.0fHz /%.0f',
|
||||
bsLock: Result := Format('BCN LOCK %.0fHz /%.0fdB',
|
||||
[FController.BeaconCorrectionHz, FController.BeaconSNRdB]);
|
||||
bsSearch: Result := Format('BCN search /%.0f', [FController.BeaconSNRdB]);
|
||||
bsSearch: Result := Format('BCN sync /%.0fdB', [FController.BeaconSNRdB]);
|
||||
else Result := 'BCN --';
|
||||
end;
|
||||
end;
|
||||
@@ -3989,34 +3985,34 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnBeaconClick(Sender: TObject);
|
||||
// ЛКМ по BEACON: вкл/выкл лок маяка (= декодер + трим LOError). При включении
|
||||
// «вооружаем» клик (следующий ЛКМ по спектру наведёт декодер на маяк) и открываем
|
||||
// окно констелляции/бюллетеня. Декодер ведёт несущую, контур стекает дрейф в LOError.
|
||||
begin
|
||||
FController.SetBeaconLock(not FController.BeaconLockEnabled);
|
||||
// При включении — «вооружаем» клик: следующий ЛКМ по спектру укажет маяк
|
||||
// (надёжнее автопоиска в забитой полосе). Авто-сид работает до клика.
|
||||
FBeaconArming := FController.BeaconLockEnabled;
|
||||
if FController.BeaconLockEnabled then
|
||||
begin
|
||||
if FBeaconScopeForm = nil then
|
||||
FBeaconScopeForm := TBeaconScopeForm.CreateWith(Self, FController);
|
||||
FBeaconScopeForm.ApplyTheme(DarkTheme);
|
||||
FBeaconScopeForm.Show;
|
||||
end;
|
||||
UpdateBeaconButton;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnBeaconMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
// ПКМ по BEACON: включает фронтенд-декодер маяка (BPSK 400 бод) и открывает окно
|
||||
// констелляции для диагностики демодуляции (Milestone 1 — до подключения FEC).
|
||||
// ПКМ по BEACON: показать/скрыть окно констелляции+бюллетеня (диагностика декодера).
|
||||
// Лок не трогает — он на ЛКМ.
|
||||
begin
|
||||
if Button <> mbRight then Exit;
|
||||
FController.SetBeaconDecode(not FController.BeaconDecodeEnabled);
|
||||
if FController.BeaconDecodeEnabled then
|
||||
begin
|
||||
// «Вооружаем» наведение: следующий ЛКМ по спектру поставит узкий фильтр
|
||||
// декодера на маяк. Потом перенавести — Shift+ЛКМ по спектру.
|
||||
FBeaconDecArming := True;
|
||||
if FBeaconScopeForm = nil then
|
||||
FBeaconScopeForm := TBeaconScopeForm.CreateWith(Self, FController);
|
||||
FBeaconScopeForm.ApplyTheme(DarkTheme);
|
||||
FBeaconScopeForm.Show;
|
||||
end
|
||||
else
|
||||
FBeaconDecArming := False;
|
||||
UpdateBeaconButton;
|
||||
if not FController.BeaconLockEnabled then Exit;
|
||||
if FBeaconScopeForm = nil then
|
||||
FBeaconScopeForm := TBeaconScopeForm.CreateWith(Self, FController);
|
||||
FBeaconScopeForm.ApplyTheme(DarkTheme);
|
||||
if FBeaconScopeForm.Visible then FBeaconScopeForm.Hide
|
||||
else FBeaconScopeForm.Show;
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdateBeaconButton;
|
||||
@@ -4033,7 +4029,7 @@ begin
|
||||
FController.BeaconTrackedFreqHz);
|
||||
// Узкий фильтр-маркер декодера (±450 Гц ≈ полоса BPSK-маяка).
|
||||
FSpecView.SetBeaconDecMarker(
|
||||
FController.BeaconDecodeEnabled and (FController.BeaconDecodeFreqHz > 0),
|
||||
FController.BeaconLockEnabled and (FController.BeaconDecodeFreqHz > 0),
|
||||
FController.BeaconDecodeFreqHz, 450.0);
|
||||
end;
|
||||
UpdateStatusField7; // моментальный апдейт статус-бара (не ждём MeterTimer)
|
||||
@@ -4223,19 +4219,11 @@ begin
|
||||
|
||||
if Button = mbLeft then
|
||||
begin
|
||||
// Наведение узкого фильтра ДЕКОДЕРА на маяк: после ПКМ BEACON (вооружено)
|
||||
// либо Shift+ЛКМ в любой момент при включённом декодере. Не трогает VFO.
|
||||
if FController.BeaconDecodeEnabled and (PbSpectrum.Width > 0) and
|
||||
(FBeaconDecArming or (ssShift in Shift)) then
|
||||
begin
|
||||
FController.SetBeaconDecodeAtHz(
|
||||
PixelToFreq(X, PbSpectrum.Width, FController.FCenterFreq, FController.FSpanHz));
|
||||
FBeaconDecArming := False;
|
||||
UpdateBeaconButton;
|
||||
Exit;
|
||||
end;
|
||||
// Наведение beacon-lock: ЛКМ указывает на маяк (вместо перестройки VFO).
|
||||
if FBeaconArming and (PbSpectrum.Width > 0) then
|
||||
// Наведение маяка: ЛКМ указывает на маяк (после включения BEACON «вооружено»,
|
||||
// либо Shift+ЛКМ в любой момент при включённом локе для перенаведения). Декодер
|
||||
// наводится на эту частоту, дальше сам ведёт несущую. Не трогает VFO.
|
||||
if FController.BeaconLockEnabled and (PbSpectrum.Width > 0) and
|
||||
(FBeaconArming or (ssShift in Shift)) then
|
||||
begin
|
||||
FController.BeaconSeedAtHz(
|
||||
PixelToFreq(X, PbSpectrum.Width, FController.FCenterFreq, FController.FSpanHz));
|
||||
|
||||
Reference in New Issue
Block a user