mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feature(calibration): офсет спектра/водопада на диапазон и на трансвертер
Вторая калибровочная таблица рядом с S-метром (паритет с Display Cal Offset в Thetis): у display-тракта своё окно/детектор, и его уровень расходится с показаниями стрелки на пару дБ, поэтому таблицы раздельные. - Settings: DispBandDB[12] / DispXvtrDB[8] (JSON cal_disp_band_i / cal_disp_xvtr_i, дефолт 0 — картинка не меняется до первой правки). - WDSPEngine: колбэк OnDispCal(PanId) — движок раз в кадр спрашивает офсет в UpdateSpectrum и прибавляет к пикселям (главный спектр/водопад в копирующем цикле, паны in-place при ненулевом офсете). На TX-дисплее не применяется. Так обошлись без хуков на каждое присваивание FCenterFreq. - RadioController: общий CalLookup(Hz, BandTbl, XvtrTbl) — на нём SMeterCalFor и DispCalFor(PanId): главный дисплей по FCenterFreq, пан по FPanFreqHz[p], т.е. кросс-банд паны получают свой офсет. Колбэк вешается в CreateEngines, поэтому работает и в GUI, и в ewsdrd; web-зеркало получает готовые кадры. - SettingsForm: группа «Spectrum / waterfall» с той же разбивкой (диапазоны + включённые трансвертеры активного железа) и кнопка «= S-meter» — копия таблицы стрелки как старт калибровки; общая раскладка сеток вынесена в LayoutCalOffsets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+31
-4
@@ -452,6 +452,10 @@ type
|
||||
procedure OnAudioReady(const Left, Right: array of Single; Count: Integer);
|
||||
procedure OnDemodAudioReady(const Left, Right: array of Single; Count: Integer);
|
||||
procedure OnDMRAudioReady(const PCM: array of Single; Count: Integer);
|
||||
// Общая выборка калибровочной таблицы «диапазон/трансвертер» по частоте.
|
||||
function CalLookup(VisibleHz: Double;
|
||||
const BandTbl: array of Double;
|
||||
const XvtrTbl: array of Double): Double;
|
||||
procedure OnSpectrumReady(const Pixels: array of Single; Count: Integer);
|
||||
procedure OnWaterfallReady(const Pixels: array of Single; Count: Integer);
|
||||
procedure OnMicPacket(const Data: TMicDataPacket);
|
||||
@@ -628,6 +632,9 @@ type
|
||||
function ReadSMeterDBm: Double;
|
||||
// Офсет S-метра (дБ) для видимой частоты: слот трансвертера или диапазон.
|
||||
function SMeterCalFor(VisibleHz: Double): Double;
|
||||
// Офсет спектра/водопада (дБ) для дисплея: PanId 0 = главный, 1..N — пан.
|
||||
// Колбэк движка (display-поток), см. TOnDispCalQuery.
|
||||
function DispCalFor(PanId: Integer): Double;
|
||||
procedure SetSliceDevice(Id, DevIndex: Integer; const DevName: string);
|
||||
function SliceCount: Integer;
|
||||
function GetSlice(Id: Integer; out S: TCtrlSlice): Boolean;
|
||||
@@ -975,6 +982,9 @@ begin
|
||||
FDSPEngine.OnSliceAudio := OnSliceAudioReady;
|
||||
FDSPEngine.OnSliceDemodAudio := OnSliceDemodAudioReady;
|
||||
FDSPEngine.OnDemodAudio := OnDemodAudioReady;
|
||||
// Калибровка уровня спектра/водопада на диапазон/трансвертер — движок
|
||||
// спрашивает её раз в кадр (сам он про диапазоны не знает).
|
||||
FDSPEngine.OnDispCal := DispCalFor;
|
||||
FDSPEngine.SetDisplayResLimit(FDisplayPixels);
|
||||
|
||||
// QO-100 beacon lock: эталон частоты = декодер (см. ServiceBeaconLock).
|
||||
@@ -2060,7 +2070,8 @@ begin
|
||||
Result := FDSPEngine.GetSMeterDBm + SMeterCalFor(ActiveVfoHz);
|
||||
end;
|
||||
|
||||
function TRadioController.SMeterCalFor(VisibleHz: Double): Double;
|
||||
function TRadioController.CalLookup(VisibleHz: Double;
|
||||
const BandTbl: array of Double; const XvtrTbl: array of Double): Double;
|
||||
// Трансвертер имеет приоритет над диапазоном: его окно частот — видимые
|
||||
// (не IF), и усиление тракта задаёт конвертер/LNB, а не КВ-вход трансивера.
|
||||
// Индекс диапазона — по плану активного железа (HF openHPSDR / VHF-UHF Pluto).
|
||||
@@ -2071,14 +2082,30 @@ begin
|
||||
and FXvtrSettings.Entries[FCurrentXvtr].Enabled
|
||||
and (VisibleHz >= FXvtrSettings.Entries[FCurrentXvtr].FreqBegin)
|
||||
and (VisibleHz <= FXvtrSettings.Entries[FCurrentXvtr].FreqEnd) then
|
||||
Exit(FCal.SMeterXvtrDB[FCurrentXvtr]);
|
||||
Exit(XvtrTbl[FCurrentXvtr]);
|
||||
for i := 0 to CFG_XVTR_COUNT-1 do
|
||||
if FXvtrSettings.Entries[i].Enabled
|
||||
and (VisibleHz >= FXvtrSettings.Entries[i].FreqBegin)
|
||||
and (VisibleHz <= FXvtrSettings.Entries[i].FreqEnd) then
|
||||
Exit(FCal.SMeterXvtrDB[i]);
|
||||
Exit(XvtrTbl[i]);
|
||||
Bi := FreqToBandIdx(VisibleHz, IsPluto);
|
||||
if (Bi >= 0) and (Bi < CFG_BAND_COUNT) then Result := FCal.SMeterBandDB[Bi];
|
||||
if (Bi >= 0) and (Bi < CFG_BAND_COUNT) then Result := BandTbl[Bi];
|
||||
end;
|
||||
|
||||
function TRadioController.SMeterCalFor(VisibleHz: Double): Double;
|
||||
begin
|
||||
Result := CalLookup(VisibleHz, FCal.SMeterBandDB, FCal.SMeterXvtrDB);
|
||||
end;
|
||||
|
||||
function TRadioController.DispCalFor(PanId: Integer): Double;
|
||||
// Зовётся из display-потока движка раз в кадр. Главный дисплей калибруем по
|
||||
// центру полосы, доп. пан — по своей частоте (паны бывают кросс-банд).
|
||||
var Hz: Double;
|
||||
begin
|
||||
if (PanId > 0) and (PanId < MAX_PANS) then Hz := FPanFreqHz[PanId]
|
||||
else Hz := FCenterFreq;
|
||||
if Hz <= 0 then Exit(0.0);
|
||||
Result := CalLookup(Hz, FCal.DispBandDB, FCal.DispXvtrDB);
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceDevice(Id, DevIndex: Integer;
|
||||
|
||||
Reference in New Issue
Block a user