mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
feat: QO-100 beacon lock — robustness, persistence, FT8-aware UI
Builds on the beacon-lock baseline: keeps the proven display-FFT control
path (hardware-LO trim folded into the active transverter LOError), and
hardens it. The narrowband NCO/FLL scaffold (BeaconLock.pas) is removed —
it was never in the control path.
- RadioController:
* Persist live: each correction folds straight into the active xvtr
LOError (visible in Settings, survives restart as LNB calibration);
disk writes throttled. FBeaconLockHz is now only a session indicator.
* Robust tracking vs nearby signals: narrow ±2 kHz gate while locked
(±6 kHz only for acquisition), slew-rate outlier rejection (a sudden
centroid jump = interferer, not slow LNB drift → ignored), and lobe
shape validation in MeasureBeaconFFT (width + power symmetry) so a CW
carrier / one-sided neighbour isn't mistaken for the BPSK beacon.
Prominence measured over the in-window noise floor (gate-width robust).
* Fast convergence: feed-forward (predict post-retune position so the
window follows the beacon through the jump) + near-deadbeat correction
on the manual click → one click locks instead of repeated tapping.
* Single central BPSK beacon (10489.750); dead CoarseBeaconOffset and
unused throttle counters removed; stale NCO/FLL/4 Hz comments fixed.
- WDSPEngine: drop the per-sample TBeaconTracker RX-IQ tap (tracker gone).
- MainForm: BEACON is now a plain button, shown only on Pluto in a
transverter. Lock status (off / click / search / LOCK + correction +
prominence) moves to status-bar field 7 in place of PLL on Pluto;
openHPSDR keeps PLL there.
- SettingsForm/StatusBar: widen LO Error field to ±10 MHz (QO-100 LNBs
drift hundreds of kHz) and widen status field 7 for the beacon text.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+47
-45
@@ -43,7 +43,7 @@ uses
|
||||
PowerInhibit,
|
||||
DeviceStore,
|
||||
RadioBackend, PlutoBackend,
|
||||
RadioController, ChannelController, BeaconLock;
|
||||
RadioController, ChannelController;
|
||||
|
||||
const
|
||||
CLR_BG = TColor($00101010);
|
||||
@@ -238,7 +238,7 @@ type
|
||||
PanelFilter: TPanel;
|
||||
BtnFilter: array[0..FILT_COUNT-1] of TFlatButton;
|
||||
BtnCTun: TFlatButton;
|
||||
BtnBeacon: TFlatButton; // QO-100 beacon lock (видим только в XVTR-режиме)
|
||||
BtnBeacon: TFlatButton; // QO-100 beacon lock (видим только на Pluto в трансвертере)
|
||||
BtnDUP: TFlatButton;
|
||||
PanelFMSQ: TPanel;
|
||||
BtnFMSQ: TFlatButton;
|
||||
@@ -352,6 +352,8 @@ type
|
||||
|
||||
// Public UI update (called from sync objects)
|
||||
procedure UpdateTXMeters;
|
||||
procedure UpdateStatusField7; // поле 7: PLL (HPSDR) или beacon (Pluto)
|
||||
function BeaconStatusText: string; // компактный статус QO-100 beacon lock
|
||||
procedure DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord);
|
||||
|
||||
// Event handlers
|
||||
@@ -1194,10 +1196,11 @@ begin
|
||||
if BtnXvtrBand[i] <> nil then
|
||||
StyleButton(BtnXvtrBand[i], i = FController.FCurrentXvtr);
|
||||
UpdateFreqDisplayMax; // трансвертер может быть >6 ГГц (QO-100)
|
||||
// BEACON-кнопка актуальна только в трансвертер-режиме (QO-100 lock).
|
||||
// BEACON-кнопка — только Pluto в трансвертере (QO-100 lock); для
|
||||
// openHPSDR смысла не имеет (нет дрейфующего LNB → прячем).
|
||||
if BtnBeacon <> nil then
|
||||
begin
|
||||
BtnBeacon.Visible := FController.FCurrentXvtr >= 0;
|
||||
BtnBeacon.Visible := FController.IsPluto and (FController.FCurrentXvtr >= 0);
|
||||
UpdateBeaconButton;
|
||||
end;
|
||||
// Wideband-вид + web-зеркало xvtr (ранее в обёртках Activate/Deactivate).
|
||||
@@ -3175,18 +3178,14 @@ procedure TMainForm.UpdateTXMeters;
|
||||
// FLastSupplyV/FLastSupplyA обновляются на rate HP Status (~150/с)
|
||||
// в TRadioController.ApplyHPStatus.
|
||||
begin
|
||||
UpdateStatusField7; // PLL (openHPSDR) или статус beacon lock (Pluto)
|
||||
|
||||
if not FController.FRunning then
|
||||
begin
|
||||
SetStatusText(3, 'Supply --');
|
||||
SetStatusText(7, 'PLL --');
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if FController.FLastPLLLock then
|
||||
SetStatusText(7, 'PLL OK')
|
||||
else
|
||||
SetStatusText(7, 'PLL?');
|
||||
|
||||
if not BoardSupportsSupplyVoltage(FController.FNetwork.Device.BoardType) then
|
||||
begin
|
||||
SetStatusText(3, 'Supply n/a');
|
||||
@@ -3205,6 +3204,35 @@ begin
|
||||
SetStatusText(3, 'Supply --');
|
||||
end;
|
||||
|
||||
function TMainForm.BeaconStatusText: string;
|
||||
// Компактный статус QO-100 beacon lock для поля 7 статус-бара (Pluto). Courier 8pt,
|
||||
// поле ~200px → держим ≤ ~24 символов.
|
||||
begin
|
||||
if not FController.BeaconLockEnabled then Exit('BCN: off');
|
||||
if FBeaconArming then Exit('BCN: click beacon');
|
||||
case FController.BeaconState of
|
||||
bsLock: Result := Format('BCN LOCK %.0fHz /%.0f',
|
||||
[FController.BeaconCorrectionHz, FController.BeaconSNRdB]);
|
||||
bsSearch: Result := Format('BCN search /%.0f', [FController.BeaconSNRdB]);
|
||||
else Result := 'BCN --';
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdateStatusField7;
|
||||
// Поле 7 статус-бара. openHPSDR — PLL-lock (как прежде). Pluto в трансвертере —
|
||||
// статус QO-100 beacon lock (у Pluto нет PLL-телеметрии); Pluto без XVTR — пусто.
|
||||
begin
|
||||
if FController.IsPluto then
|
||||
begin
|
||||
if FController.FCurrentXvtr >= 0 then SetStatusText(7, BeaconStatusText)
|
||||
else SetStatusText(7, '');
|
||||
Exit;
|
||||
end;
|
||||
if not FController.FRunning then SetStatusText(7, 'PLL --')
|
||||
else if FController.FLastPLLLock then SetStatusText(7, 'PLL OK')
|
||||
else SetStatusText(7, 'PLL?');
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnWidebandCB(ADCIndex: Integer;
|
||||
const Samples: array of SmallInt; Count: Integer);
|
||||
begin
|
||||
@@ -3897,46 +3925,20 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdateBeaconButton;
|
||||
// Подпись + подсветка кнопки BEACON по состоянию лока. Зовётся из BtnBeaconClick
|
||||
// и из рендера rfBeaconLock (контур обновляет статус каждый тик).
|
||||
var
|
||||
cap: string;
|
||||
corr: Double;
|
||||
// Beacon-маркеры + кнопка BEACON. Кнопка видима только на Pluto в трансвертере
|
||||
// (см. rfXvtr) — это ПРОСТО кнопка: подпись 'BEACON', подсветка = лок включён.
|
||||
// Вся инфа (lock/коррекция/поиск/«click») — в статус-баре, поле 7 (вместо PLL),
|
||||
// см. UpdateStatusField7. На openHPSDR кнопка скрыта, beacon-маркеры неактивны.
|
||||
begin
|
||||
if BtnBeacon = nil then Exit;
|
||||
// Маркеры на спектре: опорная частота (зелёная) + позиция трекера (оранж).
|
||||
// Маркеры на спектре: опорная частота (зелёная) + отслеживаемый центроид (оранж).
|
||||
if FSpecView <> nil then
|
||||
FSpecView.SetBeaconMarkers(FController.BeaconLockEnabled,
|
||||
FController.BeaconRefHz,
|
||||
FController.BeaconTrackedFreqHz);
|
||||
if not FController.BeaconLockEnabled then
|
||||
begin
|
||||
BtnBeacon.Caption := 'BEACON';
|
||||
StyleButton(BtnBeacon, False);
|
||||
end
|
||||
else if FBeaconArming then
|
||||
begin
|
||||
BtnBeacon.Caption := 'CLICK BCN'; // ждём клик пользователя по маяку
|
||||
StyleButton(BtnBeacon, True);
|
||||
end
|
||||
else
|
||||
begin
|
||||
case FController.BeaconState of
|
||||
bsLock:
|
||||
begin
|
||||
corr := FController.BeaconCorrectionHz;
|
||||
// LOCK + коррекция LO (Гц) + SNR — видно запас.
|
||||
cap := Format('L%.0f /%.0f', [corr, FController.BeaconSNRdB]);
|
||||
StyleButton(BtnBeacon, True);
|
||||
end;
|
||||
bsSearch:
|
||||
// Показываем SNR при поиске — диагностика: растёт → маяк ловится.
|
||||
begin cap := Format('BCN ?%.0f', [FController.BeaconSNRdB]); StyleButton(BtnBeacon, True); end;
|
||||
else
|
||||
begin cap := 'BCN --'; StyleButton(BtnBeacon, False); end;
|
||||
end;
|
||||
BtnBeacon.Caption := cap;
|
||||
end;
|
||||
UpdateStatusField7; // моментальный апдейт статус-бара (не ждём MeterTimer)
|
||||
if BtnBeacon = nil then Exit;
|
||||
BtnBeacon.Caption := 'BEACON';
|
||||
StyleButton(BtnBeacon, FController.BeaconLockEnabled);
|
||||
BtnBeacon.Repaint;
|
||||
end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user