mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feature(calibration): офсет S-метра на диапазон и на трансвертер, раздельно по железу
Вместо одного офсета на всё устройство — таблицы «на диапазон» и «на слот трансвертера»; состав таблиц задаёт активное железо. - Settings: SMeterOffsetDB -> SMeterBandDB[12] / SMeterXvtrDB[8] (JSON cal_smeter_band_i / cal_smeter_xvtr_i). Легаси-ключ cal_smeter_db становится дефолтом всех слотов — показания после обновления не меняются. Разделение Pluto/openHPSDR даёт сама секция JSON: она ключуется по MAC устройства (у Pluto — synthetic MAC из serial). - Офсет убран из WDSPEngine (FSMeterCalDB): движок не знает ни диапазонов, ни трансвертеров. Теперь TRadioController.SMeterCalFor(VisibleHz) — окно включённого XVTR-слота приоритетнее диапазона, индекс диапазона по плану железа (FreqToBandIdx с IsPluto); ReadSMeterDBm для главного S-метра (MainForm + ewsdrd) и SliceSMeter по TargetHz слайса — паны N на других диапазонах считаются по своему банду, а не по главному. - SettingsForm: таблицы на 12 слотов, подписи/видимость/раскладку ставит RelayoutCalTab; SetCalibrationBackend(IsPluto) вызывается рядом с SetAntennaBackend. У openHPSDR — HF-план, у Pluto — VHF/UHF-план и скрытые группы Power/SWR detector и Supply V/A (нет Alex-моста и его телеметрии). Слоты трансвертеров показываются только включённые, с их именами. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+4
-1
@@ -3481,7 +3481,7 @@ begin
|
||||
|
||||
if FController.FWDSPReady then
|
||||
begin
|
||||
FController.FLastSMeter := FController.FDSPEngine.GetSMeterDBm;
|
||||
FController.FLastSMeter := FController.ReadSMeterDBm;
|
||||
FController.FDSPEngine.SetSpectrumWidth(FPan.SpectrumWidth);
|
||||
Inc(FAgcLineCounter);
|
||||
if FAgcLineCounter >= 6 then
|
||||
@@ -8262,6 +8262,9 @@ begin
|
||||
// физических разъёмов на диапазон/трансвертер (если разъёмов две пары).
|
||||
SF.SetAntennaBackend(FController.BackendCaps.Kind = bkPluto,
|
||||
FController.BackendCaps.HasAntSwitch);
|
||||
// Вкладка Calibration: band-план и состав групп — по активному железу
|
||||
// (у AD936x нет моста детектора мощности и телеметрии питания).
|
||||
SF.SetCalibrationBackend(FController.BackendCaps.Kind = bkPluto);
|
||||
SF.LoadAnt936x(FController.Ant936x, FController.FXvtrSettings);
|
||||
SF.LoadXvtrSettings(FController.FXvtrSettings);
|
||||
SF.LoadPASettings(FController.FPAMaxPower, FController.FPABandCal);
|
||||
|
||||
+43
-6
@@ -623,6 +623,11 @@ type
|
||||
procedure SetSliceDSP(Id, NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
||||
procedure SetSliceFMSquelch(Id: Integer; On_: Boolean; Level: Integer);
|
||||
function SliceSMeter(Id: Integer): Double; // dBm, из DSP-потока
|
||||
// S-метр главного приёмника, dBm, с калибровочным офсетом текущего
|
||||
// диапазона/трансвертера (движок отдаёт сырое значение).
|
||||
function ReadSMeterDBm: Double;
|
||||
// Офсет S-метра (дБ) для видимой частоты: слот трансвертера или диапазон.
|
||||
function SMeterCalFor(VisibleHz: Double): Double;
|
||||
procedure SetSliceDevice(Id, DevIndex: Integer; const DevName: string);
|
||||
function SliceCount: Integer;
|
||||
function GetSlice(Id: Integer; out S: TCtrlSlice): Boolean;
|
||||
@@ -685,7 +690,7 @@ type
|
||||
function PlutoTxAttForDrive: Double; // дБ<0 под текущий FDrivePercent
|
||||
procedure ApplyPlutoTxAtten; // ставит att по FTransmitting/FTuning
|
||||
procedure SetPlutoTxMaxAtt(Db: Double); // потолок на drive=100% (внешний усилитель)
|
||||
procedure SetCalibration(const C: TCalibration); // вкладка Calibration → FCal + офсет S-метра в DSP
|
||||
procedure SetCalibration(const C: TCalibration); // вкладка Calibration → FCal (офсеты S-метра — в SMeterCalFor)
|
||||
procedure ApplyWDSPDrive(Pct: Integer); // цифровой drive WDSP: Pluto=1.0 (мощность — атт), HPSDR=Pct/100
|
||||
|
||||
// Диапазоны / трансвертеры / спан
|
||||
@@ -971,7 +976,6 @@ begin
|
||||
FDSPEngine.OnSliceDemodAudio := OnSliceDemodAudioReady;
|
||||
FDSPEngine.OnDemodAudio := OnDemodAudioReady;
|
||||
FDSPEngine.SetDisplayResLimit(FDisplayPixels);
|
||||
FDSPEngine.SMeterCalDB := FCal.SMeterOffsetDB;
|
||||
|
||||
// QO-100 beacon lock: эталон частоты = декодер (см. ServiceBeaconLock).
|
||||
FBeaconRefHz := 10489750000.0; // центральный BPSK-маяк NB-транспондера (downlink)
|
||||
@@ -2039,9 +2043,42 @@ begin
|
||||
end;
|
||||
|
||||
function TRadioController.SliceSMeter(Id: Integer): Double;
|
||||
// Слайс может стоять на другом диапазоне (паны N кросс-банд), поэтому офсет
|
||||
// берём по ЕГО видимой частоте, а не по главному диапазону.
|
||||
var idx: Integer;
|
||||
begin
|
||||
if Assigned(FDSPEngine) then Result := FDSPEngine.GetSliceSMeter(Id)
|
||||
else Result := -130.0;
|
||||
Result := -130.0;
|
||||
if not Assigned(FDSPEngine) then Exit;
|
||||
Result := FDSPEngine.GetSliceSMeter(Id);
|
||||
idx := FindSliceIndex(Id);
|
||||
if idx >= 0 then Result := Result + SMeterCalFor(FSlices[idx].TargetHz);
|
||||
end;
|
||||
|
||||
function TRadioController.ReadSMeterDBm: Double;
|
||||
begin
|
||||
if not Assigned(FDSPEngine) then Exit(-130.0);
|
||||
Result := FDSPEngine.GetSMeterDBm + SMeterCalFor(ActiveVfoHz);
|
||||
end;
|
||||
|
||||
function TRadioController.SMeterCalFor(VisibleHz: Double): Double;
|
||||
// Трансвертер имеет приоритет над диапазоном: его окно частот — видимые
|
||||
// (не IF), и усиление тракта задаёт конвертер/LNB, а не КВ-вход трансивера.
|
||||
// Индекс диапазона — по плану активного железа (HF openHPSDR / VHF-UHF Pluto).
|
||||
var i, Bi: Integer;
|
||||
begin
|
||||
Result := 0.0;
|
||||
if (FCurrentXvtr >= 0) and (FCurrentXvtr < CFG_XVTR_COUNT)
|
||||
and FXvtrSettings.Entries[FCurrentXvtr].Enabled
|
||||
and (VisibleHz >= FXvtrSettings.Entries[FCurrentXvtr].FreqBegin)
|
||||
and (VisibleHz <= FXvtrSettings.Entries[FCurrentXvtr].FreqEnd) then
|
||||
Exit(FCal.SMeterXvtrDB[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]);
|
||||
Bi := FreqToBandIdx(VisibleHz, IsPluto);
|
||||
if (Bi >= 0) and (Bi < CFG_BAND_COUNT) then Result := FCal.SMeterBandDB[Bi];
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceDevice(Id, DevIndex: Integer;
|
||||
@@ -3567,8 +3604,8 @@ begin
|
||||
// Санитизация: битый конфиг не должен дать деление на ноль/абсурдные ватты.
|
||||
FCal.PwrDetModel := EnsureRange(FCal.PwrDetModel, 0, 3);
|
||||
if FCal.AmpSensMVA <= 0 then FCal.AmpSensMVA := 120.0;
|
||||
if Assigned(FDSPEngine) then
|
||||
FDSPEngine.SMeterCalDB := FCal.SMeterOffsetDB;
|
||||
// Офсет S-метра берётся из FCal на каждом чтении (SMeterCalFor) — применять
|
||||
// отдельно нечего: он зависит от диапазона/трансвертера, а не от движка.
|
||||
SaveGlobalSettings; // персист (гейт по FDevConnected внутри)
|
||||
end;
|
||||
|
||||
|
||||
+21
-5
@@ -339,7 +339,12 @@ type
|
||||
SupplyVoltCal: Double; // множитель напряжения питания (1.0 = без коррекции)
|
||||
AmpVoffMV: Double; // сдвиг нуля датчика тока, мВ (Thetis default 360)
|
||||
AmpSensMVA: Double; // чувствительность датчика тока, мВ/А (Thetis default 120)
|
||||
SMeterOffsetDB: Double; // офсет S-метра, дБ (прибавляется к WDSP dBm)
|
||||
// Офсет S-метра, дБ — раздельно на диапазон и на слот трансвертера (усиление
|
||||
// тракта разное на 160м и на 10м, а у XVTR своё — конвертер/LNB). Смысл
|
||||
// индекса диапазона задаёт band-план железа (HF у openHPSDR, VHF/UHF у
|
||||
// Pluto); таблицы не пересекаются, т.к. секция JSON ключуется по MAC.
|
||||
SMeterBandDB: array[0..CFG_BAND_COUNT-1] of Double;
|
||||
SMeterXvtrDB: array[0..CFG_XVTR_COUNT-1] of Double;
|
||||
end;
|
||||
|
||||
TGlobalSettings = record
|
||||
@@ -641,7 +646,7 @@ begin
|
||||
C.SupplyVoltCal := 1.0;
|
||||
C.AmpVoffMV := 360.0;
|
||||
C.AmpSensMVA := 120.0;
|
||||
C.SMeterOffsetDB := 0.0;
|
||||
// SMeterBandDB/SMeterXvtrDB — нули после FillChar (без коррекции).
|
||||
end;
|
||||
|
||||
constructor TSettingsManager.Create(const FilePath: string);
|
||||
@@ -769,7 +774,7 @@ end;
|
||||
function TSettingsManager.LoadDevice(const MAC: array of Byte;
|
||||
out G: TGlobalSettings;
|
||||
var Bands: array of TBandSettings): Boolean;
|
||||
var MacStr: string; DevObj,GObj,BObj: TJSONObject; i: Integer;
|
||||
var MacStr: string; DevObj,GObj,BObj: TJSONObject; i: Integer; SMLegacy: Double;
|
||||
begin
|
||||
MacStr := MacToStr(MAC);
|
||||
Result := FRoot.Find(MacStr) <> nil;
|
||||
@@ -891,7 +896,15 @@ begin
|
||||
G.Cal.SupplyVoltCal := EnsureRange(JD(GObj,'cal_supply_volt', 1.0), 0.1, 5.0);
|
||||
G.Cal.AmpVoffMV := EnsureRange(JD(GObj,'cal_amp_voff_mv', 360.0), 0.0, 2000.0);
|
||||
G.Cal.AmpSensMVA := EnsureRange(JD(GObj,'cal_amp_sens_mva', 120.0), 1.0, 1000.0);
|
||||
G.Cal.SMeterOffsetDB := EnsureRange(JD(GObj,'cal_smeter_db', 0.0), -30.0, 30.0);
|
||||
// S-метр: офсет на диапазон/трансвертер. Легаси-ключ (одно значение на всё
|
||||
// устройство) становится дефолтом всех слотов — показания не меняются.
|
||||
SMLegacy := EnsureRange(JD(GObj,'cal_smeter_db', 0.0), -30.0, 30.0);
|
||||
for i := 0 to CFG_BAND_COUNT-1 do
|
||||
G.Cal.SMeterBandDB[i] :=
|
||||
EnsureRange(JD(GObj,'cal_smeter_band_'+IntToStr(i), SMLegacy), -30.0, 30.0);
|
||||
for i := 0 to CFG_XVTR_COUNT-1 do
|
||||
G.Cal.SMeterXvtrDB[i] :=
|
||||
EnsureRange(JD(GObj,'cal_smeter_xvtr_'+IntToStr(i), SMLegacy), -30.0, 30.0);
|
||||
|
||||
for i := 0 to CFG_BAND_COUNT-1 do
|
||||
begin
|
||||
@@ -1008,7 +1021,10 @@ begin
|
||||
JW(O,'cal_supply_volt',G.Cal.SupplyVoltCal);
|
||||
JW(O,'cal_amp_voff_mv',G.Cal.AmpVoffMV);
|
||||
JW(O,'cal_amp_sens_mva',G.Cal.AmpSensMVA);
|
||||
JW(O,'cal_smeter_db',G.Cal.SMeterOffsetDB);
|
||||
for i := 0 to CFG_BAND_COUNT-1 do
|
||||
JW(O,'cal_smeter_band_'+IntToStr(i),G.Cal.SMeterBandDB[i]);
|
||||
for i := 0 to CFG_XVTR_COUNT-1 do
|
||||
JW(O,'cal_smeter_xvtr_'+IntToStr(i),G.Cal.SMeterXvtrDB[i]);
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.SaveBand(const MAC: array of Byte; BandIdx: Integer;
|
||||
|
||||
+223
-52
@@ -153,14 +153,31 @@ type
|
||||
FVHFCalLabels: array[0..CFG_XVTR_COUNT-1] of TLabel;
|
||||
|
||||
// ---- Calibration tab controls ----
|
||||
// Таблицы «на диапазон» строятся на 12 слотов (максимум плана); подписи,
|
||||
// видимость и раскладка задаются железом в RelayoutCalTab: у openHPSDR
|
||||
// виден HF-план, у Pluto — VHF/UHF-план, слоты трансвертеров — только
|
||||
// включённые. Значения пишутся в per-device секцию JSON (ключ = MAC),
|
||||
// поэтому таблицы разных аппаратов не пересекаются.
|
||||
FPageCalib: TScrollBox;
|
||||
FNavCalib: TFlatButton;
|
||||
FCalGrpDet: TPanel; // Power / SWR detector
|
||||
FCalGrpVA: TPanel; // Supply voltage / current
|
||||
FCalGrpSM: TPanel; // S-meter
|
||||
FCmbPwrDetModel: TFlatComboBox; // модель детектора Alex-моста
|
||||
FEdPADetCal: array[0..10] of TFlatFloatSpinEdit; // множитель FWD/REV на банд
|
||||
FEdPADetCal: array[0..CFG_BAND_COUNT-1] of TFlatFloatSpinEdit; // множитель FWD/REV на банд
|
||||
FLblPADetCal: array[0..CFG_BAND_COUNT-1] of TLabel;
|
||||
FEdSupplyVoltCal: TFlatFloatSpinEdit; // множитель напряжения питания
|
||||
FEdAmpVoff: TFlatFloatSpinEdit; // датчик тока: сдвиг нуля, мВ
|
||||
FEdAmpSens: TFlatFloatSpinEdit; // датчик тока: мВ/А
|
||||
FEdSMeterOffset: TFlatFloatSpinEdit; // офсет S-метра, дБ
|
||||
FEdSMBand: array[0..CFG_BAND_COUNT-1] of TFlatFloatSpinEdit; // офсет S-метра на диапазон
|
||||
FLblSMBand: array[0..CFG_BAND_COUNT-1] of TLabel;
|
||||
FEdSMXvtr: array[0..CFG_XVTR_COUNT-1] of TFlatFloatSpinEdit; // офсет S-метра на трансвертер
|
||||
FLblSMXvtr: array[0..CFG_XVTR_COUNT-1] of TLabel;
|
||||
FLblSMBandHdr: TLabel;
|
||||
FLblSMXvtrHdr: TLabel;
|
||||
FCalIsPluto: Boolean; // активное железо — AD936x
|
||||
FCalXvtrOn: array[0..CFG_XVTR_COUNT-1] of Boolean; // слот трансвертера включён
|
||||
FCalXvtrName: array[0..CFG_XVTR_COUNT-1] of string; // подпись слота
|
||||
FCalConfig: TCalibration;
|
||||
FOnCalibrationChange: TOnCalibrationChange;
|
||||
|
||||
@@ -352,6 +369,7 @@ type
|
||||
procedure BuildRX1Tab;
|
||||
procedure BuildPATab;
|
||||
procedure BuildCalibrationTab;
|
||||
procedure RelayoutCalTab;
|
||||
procedure CollectCalFromUI;
|
||||
procedure OnCalAnyChange(Sender: TObject);
|
||||
procedure BuildCATTab;
|
||||
@@ -463,6 +481,8 @@ type
|
||||
procedure LoadPASettings(MaxPower: Double; const BandCal: array of Double);
|
||||
procedure LoadPlutoTxMaxAtt(MaxAttDb: Double);
|
||||
procedure LoadCalibration(const C: TCalibration);
|
||||
// Железо вкладки Calibration: band-план и состав групп (Pluto/openHPSDR).
|
||||
procedure SetCalibrationBackend(IsPluto: Boolean);
|
||||
// Вкладка Antenna: Alex-таблица (openHPSDR) либо таблица разъёмов AD936x.
|
||||
procedure SetAntennaBackend(IsAD936x, HasAntSwitch: Boolean);
|
||||
// Таблица разъёмов + имена/видимость слотов трансвертеров.
|
||||
@@ -569,6 +589,21 @@ const
|
||||
PA_BAND_NAMES: array[0..10] of string =
|
||||
('160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m');
|
||||
|
||||
// Раскладка вкладки Calibration — общая для построения (BuildCalibrationTab)
|
||||
// и перекладки под активное железо (RelayoutCalTab).
|
||||
CAL_MARGIN = 22;
|
||||
CAL_PAD = 18;
|
||||
CAL_ROW_H = 32;
|
||||
CAL_R1 = 42;
|
||||
CAL_ED_W = 72;
|
||||
CAL_LBL_W = 54;
|
||||
CAL_SM_LBL_W = 68; // подписи трансвертеров длиннее ('70cm', 'QO-100')
|
||||
CAL_COLS = 4;
|
||||
CAL_GRP_W = 700;
|
||||
CAL_GRP1_H = 236; // Power / SWR detector
|
||||
CAL_GRP2_H = 156; // Supply voltage / current
|
||||
CAL_VA_LBL_W = 220;
|
||||
|
||||
{ TSettingsForm }
|
||||
|
||||
constructor TSettingsForm.Create(AOwner: TComponent);
|
||||
@@ -1888,20 +1923,11 @@ end;
|
||||
procedure TSettingsForm.BuildCalibrationTab;
|
||||
// Вкладка Calibration (паритет с Thetis-Enhanced): модель детектора мощности
|
||||
// Alex-моста + множитель FWD/REV на банд (Det. Cal.), калибровка напряжения/
|
||||
// тока питания (PAVoltCal/AmpVoff/AmpSens) и офсет S-метра.
|
||||
// тока питания (PAVoltCal/AmpVoff/AmpSens) и офсет S-метра на диапазон и на
|
||||
// слот трансвертера. Позиции/подписи/видимость band-строк ставит RelayoutCalTab
|
||||
// под активное железо — здесь только создание контролов.
|
||||
const
|
||||
MARGIN = 22;
|
||||
GRP_PAD = 18;
|
||||
LBL_W = 54;
|
||||
ED_W = 72;
|
||||
COL_W = LBL_W + ED_W + 14;
|
||||
COLS = 4;
|
||||
ROW_H = 32;
|
||||
R1 = 42;
|
||||
GRP1_H = 236;
|
||||
GRP2_H = 156;
|
||||
GRP3_H = 92;
|
||||
VA_LBL_W = 220;
|
||||
GRP3_H0 = 200; // стартовая высота S-метра, уточняется в RelayoutCalTab
|
||||
|
||||
function MakeCalSpin(AParent: TWinControl; ALeft, ATop: Integer;
|
||||
AMin, AMax, AInc: Double; ADec: Integer;
|
||||
@@ -1910,7 +1936,7 @@ const
|
||||
begin
|
||||
E := TFlatFloatSpinEdit.Create(Self);
|
||||
E.Parent := AParent;
|
||||
E.SetBounds(ALeft, ATop, ED_W, BTN_H + 2);
|
||||
E.SetBounds(ALeft, ATop, CAL_ED_W, BTN_H + 2);
|
||||
E.Color := CLR_INPUT;
|
||||
E.Font.Color := CLR_INPUT_TEXT;
|
||||
E.Font.Name := UI_FONT;
|
||||
@@ -1927,18 +1953,24 @@ const
|
||||
var
|
||||
Grp: TPanel;
|
||||
Lbl: TLabel;
|
||||
i, r, c, X, Y, GTop: Integer;
|
||||
i, GTop: Integer;
|
||||
begin
|
||||
// Гард: SetItemIndex у TFlatComboBox стреляет OnChange и при программном
|
||||
// присвоении — без гарда OnCalAnyChange дёрнется из «ItemIndex := 0» ниже,
|
||||
// когда остальные контролы вкладки ещё nil → AV в CollectCalFromUI.
|
||||
FLoading := True;
|
||||
FCalIsPluto := False;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
FCalXvtrOn[i] := False;
|
||||
FCalXvtrName[i] := '';
|
||||
end;
|
||||
|
||||
with TLabel.Create(Self) do
|
||||
begin
|
||||
Parent := FPageCalib;
|
||||
Caption := 'Calibration';
|
||||
SetBounds(MARGIN, 18, 400, 28);
|
||||
SetBounds(CAL_MARGIN, 18, 400, 28);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 16;
|
||||
Font.Style := [fsBold];
|
||||
@@ -1949,7 +1981,7 @@ begin
|
||||
begin
|
||||
Parent := FPageCalib;
|
||||
Caption := 'Power/SWR detector, supply voltage/current and S-meter calibration.';
|
||||
SetBounds(MARGIN, 48, 620, 20);
|
||||
SetBounds(CAL_MARGIN, 48, 620, 20);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 9;
|
||||
Font.Color := CLR_TEXTDIM;
|
||||
@@ -1957,10 +1989,12 @@ begin
|
||||
|
||||
// ── Power / SWR detector ────────────────────────────────────────────────
|
||||
GTop := 86;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'Power / SWR detector', MARGIN, GTop, 700, GRP1_H);
|
||||
FCalGrpDet := MakeGroupPanel(FPageCalib, 'Power / SWR detector',
|
||||
CAL_MARGIN, GTop, CAL_GRP_W, CAL_GRP1_H);
|
||||
Grp := FCalGrpDet;
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Detector model', GRP_PAD, R1 + 6, 132);
|
||||
FCmbPwrDetModel := MakeCombo(Grp, GRP_PAD + 150, R1, 280, OnCalAnyChange);
|
||||
Lbl := MakeLbl(Grp, 'Detector model', CAL_PAD, CAL_R1 + 6, 132);
|
||||
FCmbPwrDetModel := MakeCombo(Grp, CAL_PAD + 150, CAL_R1, 280, OnCalAnyChange);
|
||||
FCmbPwrDetModel.Items.Add('ANAN-10/100/100B/100D (3.3V)');
|
||||
FCmbPwrDetModel.Items.Add('ANAN-200D / Orion');
|
||||
FCmbPwrDetModel.Items.Add('ANAN-7000DLE / Anvelina Pro 3 / G2');
|
||||
@@ -1970,58 +2004,187 @@ begin
|
||||
Lbl := MakeLbl(Grp,
|
||||
'FWD/REV multiplier per band: 1.00 = no correction, >1 if meter under-reads '
|
||||
+ '(e.g. 88 W shown at real 100 W -> 1.14). SWR is not affected.',
|
||||
GRP_PAD, R1 + ROW_H + 10, 650);
|
||||
CAL_PAD, CAL_R1 + CAL_ROW_H + 10, 650);
|
||||
|
||||
for i := 0 to 10 do
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
r := i div COLS;
|
||||
c := i mod COLS;
|
||||
X := GRP_PAD + c * (COL_W + 4);
|
||||
Y := R1 + ROW_H + 46 + r * ROW_H;
|
||||
|
||||
Lbl := MakeLbl(Grp, PA_BAND_NAMES[i] + ':', X, Y + 5, LBL_W);
|
||||
|
||||
FEdPADetCal[i] := MakeCalSpin(Grp, X + LBL_W, Y, 0.50, 2.00, 0.01, 2, 1.00);
|
||||
FLblPADetCal[i] := MakeLbl(Grp, '', 0, 0, CAL_LBL_W);
|
||||
FEdPADetCal[i] := MakeCalSpin(Grp, 0, 0, 0.50, 2.00, 0.01, 2, 1.00);
|
||||
FEdPADetCal[i].Tag := i;
|
||||
end;
|
||||
|
||||
// ── Supply voltage / current ────────────────────────────────────────────
|
||||
GTop := GTop + GRP1_H + 14;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'Supply voltage / current', MARGIN, GTop, 700, GRP2_H);
|
||||
GTop := GTop + CAL_GRP1_H + 14;
|
||||
FCalGrpVA := MakeGroupPanel(FPageCalib, 'Supply voltage / current',
|
||||
CAL_MARGIN, GTop, CAL_GRP_W, CAL_GRP2_H);
|
||||
Grp := FCalGrpVA;
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Voltage multiplier (1.000 = no correction)', GRP_PAD, R1 + 6, VA_LBL_W);
|
||||
FEdSupplyVoltCal := MakeCalSpin(Grp, GRP_PAD + VA_LBL_W + 10, R1, 0.100, 5.000, 0.001, 3, 1.000);
|
||||
Lbl := MakeLbl(Grp, 'Voltage multiplier (1.000 = no correction)',
|
||||
CAL_PAD, CAL_R1 + 6, CAL_VA_LBL_W);
|
||||
FEdSupplyVoltCal := MakeCalSpin(Grp, CAL_PAD + CAL_VA_LBL_W + 10, CAL_R1,
|
||||
0.100, 5.000, 0.001, 3, 1.000);
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Current sensor zero offset (mV)', GRP_PAD, R1 + ROW_H + 6, VA_LBL_W);
|
||||
FEdAmpVoff := MakeCalSpin(Grp, GRP_PAD + VA_LBL_W + 10, R1 + ROW_H, 0.0, 2000.0, 1.0, 0, 360.0);
|
||||
Lbl := MakeLbl(Grp, 'Current sensor zero offset (mV)',
|
||||
CAL_PAD, CAL_R1 + CAL_ROW_H + 6, CAL_VA_LBL_W);
|
||||
FEdAmpVoff := MakeCalSpin(Grp, CAL_PAD + CAL_VA_LBL_W + 10, CAL_R1 + CAL_ROW_H,
|
||||
0.0, 2000.0, 1.0, 0, 360.0);
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Current sensor sensitivity (mV/A)', GRP_PAD, R1 + 2 * ROW_H + 6, VA_LBL_W);
|
||||
FEdAmpSens := MakeCalSpin(Grp, GRP_PAD + VA_LBL_W + 10, R1 + 2 * ROW_H, 1.0, 1000.0, 0.1, 1, 120.0);
|
||||
Lbl := MakeLbl(Grp, 'Current sensor sensitivity (mV/A)',
|
||||
CAL_PAD, CAL_R1 + 2 * CAL_ROW_H + 6, CAL_VA_LBL_W);
|
||||
FEdAmpSens := MakeCalSpin(Grp, CAL_PAD + CAL_VA_LBL_W + 10, CAL_R1 + 2 * CAL_ROW_H,
|
||||
1.0, 1000.0, 0.1, 1, 120.0);
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Defaults 360 mV / 120 mV/A (ACS712-style, Orion MkII)',
|
||||
GRP_PAD + VA_LBL_W + 10 + ED_W + 14, R1 + ROW_H + 6, 320);
|
||||
CAL_PAD + CAL_VA_LBL_W + 10 + CAL_ED_W + 14,
|
||||
CAL_R1 + CAL_ROW_H + 6, 320);
|
||||
|
||||
// ── S-meter ─────────────────────────────────────────────────────────────
|
||||
GTop := GTop + GRP2_H + 14;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'S-meter', MARGIN, GTop, 700, GRP3_H);
|
||||
GTop := GTop + CAL_GRP2_H + 14;
|
||||
FCalGrpSM := MakeGroupPanel(FPageCalib, 'S-meter',
|
||||
CAL_MARGIN, GTop, CAL_GRP_W, GRP3_H0);
|
||||
Grp := FCalGrpSM;
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Offset (dB), added to all S-meter readings', GRP_PAD, R1 + 6, VA_LBL_W);
|
||||
FEdSMeterOffset := MakeCalSpin(Grp, GRP_PAD + VA_LBL_W + 10, R1, -30.0, 30.0, 0.1, 1, 0.0);
|
||||
FLblSMBandHdr := MakeLbl(Grp,
|
||||
'Offset (dB) added to S-meter readings — per band (+ = meter reads higher).',
|
||||
CAL_PAD, 30, 650);
|
||||
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
FLblSMBand[i] := MakeLbl(Grp, '', 0, 0, CAL_SM_LBL_W);
|
||||
FEdSMBand[i] := MakeCalSpin(Grp, 0, 0, -30.0, 30.0, 0.1, 1, 0.0);
|
||||
FEdSMBand[i].Tag := i;
|
||||
end;
|
||||
|
||||
FLblSMXvtrHdr := MakeLbl(Grp, 'Per transverter slot', CAL_PAD, 0, 300);
|
||||
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
FLblSMXvtr[i] := MakeLbl(Grp, '', 0, 0, CAL_SM_LBL_W);
|
||||
FLblSMXvtr[i].AutoSize := False;
|
||||
FLblSMXvtr[i].ShowHint := True;
|
||||
FEdSMXvtr[i] := MakeCalSpin(Grp, 0, 0, -30.0, 30.0, 0.1, 1, 0.0);
|
||||
FEdSMXvtr[i].Tag := i;
|
||||
end;
|
||||
|
||||
RelayoutCalTab; // стартовая раскладка (HF-план, трансвертеры скрыты)
|
||||
|
||||
FLoading := False;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.RelayoutCalTab;
|
||||
// Показывает только то, что есть у активного железа: band-план (HF у openHPSDR,
|
||||
// VHF/UHF у Pluto), из трансвертеров — включённые слоты. Детектор мощности и
|
||||
// датчики питания — свойства Alex-моста openHPSDR, у AD936x такой телеметрии
|
||||
// нет, поэтому обе группы прячутся, а S-метр поднимается наверх.
|
||||
var
|
||||
i, r, c, X, Y, GTop, BandRows, XvtrRows, Slot, H: Integer;
|
||||
Nm: string;
|
||||
begin
|
||||
// Гард: вкладка ещё строится (или LoadXvtrSettings пришёл раньше неё).
|
||||
if (FCalGrpDet = nil) or (FCalGrpVA = nil) or (FCalGrpSM = nil)
|
||||
or (FLblSMXvtrHdr = nil) then Exit;
|
||||
|
||||
// ---- строки диапазонов: позиция по индексу плана, пустые слоты скрыты ----
|
||||
BandRows := 0;
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
Nm := BandName(i, FCalIsPluto);
|
||||
r := i div CAL_COLS;
|
||||
c := i mod CAL_COLS;
|
||||
|
||||
X := CAL_PAD + c * (CAL_LBL_W + CAL_ED_W + 18);
|
||||
Y := CAL_R1 + CAL_ROW_H + 46 + r * CAL_ROW_H;
|
||||
if FLblPADetCal[i] <> nil then
|
||||
begin
|
||||
FLblPADetCal[i].Caption := Nm + ':';
|
||||
FLblPADetCal[i].SetBounds(X, Y + 5, CAL_LBL_W, 18);
|
||||
FLblPADetCal[i].Visible := Nm <> '';
|
||||
end;
|
||||
if FEdPADetCal[i] <> nil then
|
||||
begin
|
||||
FEdPADetCal[i].SetBounds(X + CAL_LBL_W, Y, CAL_ED_W, BTN_H + 2);
|
||||
FEdPADetCal[i].Visible := Nm <> '';
|
||||
end;
|
||||
|
||||
X := CAL_PAD + c * (CAL_SM_LBL_W + CAL_ED_W + 14);
|
||||
Y := 52 + r * CAL_ROW_H;
|
||||
if FLblSMBand[i] <> nil then
|
||||
begin
|
||||
FLblSMBand[i].Caption := Nm + ':';
|
||||
FLblSMBand[i].SetBounds(X, Y + 5, CAL_SM_LBL_W, 18);
|
||||
FLblSMBand[i].Visible := Nm <> '';
|
||||
end;
|
||||
if FEdSMBand[i] <> nil then
|
||||
begin
|
||||
FEdSMBand[i].SetBounds(X + CAL_SM_LBL_W, Y, CAL_ED_W, BTN_H + 2);
|
||||
FEdSMBand[i].Visible := Nm <> '';
|
||||
end;
|
||||
if Nm <> '' then BandRows := r + 1;
|
||||
end;
|
||||
|
||||
// ---- строки трансвертеров: только включённые слоты, без дырок ----
|
||||
Y := 52 + BandRows * CAL_ROW_H + 6;
|
||||
FLblSMXvtrHdr.SetBounds(CAL_PAD, Y, 300, 18);
|
||||
Slot := 0;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
if FCalXvtrOn[i] then
|
||||
begin
|
||||
r := Slot div CAL_COLS;
|
||||
c := Slot mod CAL_COLS;
|
||||
X := CAL_PAD + c * (CAL_SM_LBL_W + CAL_ED_W + 14);
|
||||
if FCalXvtrName[i] <> '' then Nm := FCalXvtrName[i]
|
||||
else Nm := 'XVTR' + IntToStr(i);
|
||||
FLblSMXvtr[i].Caption := Nm + ':';
|
||||
FLblSMXvtr[i].Hint := 'XVTR' + IntToStr(i) + ' (' + Nm + ')';
|
||||
FLblSMXvtr[i].SetBounds(X, Y + 24 + r * CAL_ROW_H + 5, CAL_SM_LBL_W, 18);
|
||||
FEdSMXvtr[i].SetBounds(X + CAL_SM_LBL_W, Y + 24 + r * CAL_ROW_H,
|
||||
CAL_ED_W, BTN_H + 2);
|
||||
Inc(Slot);
|
||||
end;
|
||||
FLblSMXvtr[i].Visible := FCalXvtrOn[i];
|
||||
FEdSMXvtr[i].Visible := FCalXvtrOn[i];
|
||||
end;
|
||||
XvtrRows := (Slot + CAL_COLS - 1) div CAL_COLS;
|
||||
FLblSMXvtrHdr.Visible := Slot > 0;
|
||||
|
||||
if Slot > 0 then H := Y + 24 + XvtrRows * CAL_ROW_H + 12
|
||||
else H := Y + 12;
|
||||
|
||||
// ---- вертикальная укладка групп ----
|
||||
GTop := 86;
|
||||
FCalGrpDet.Visible := not FCalIsPluto;
|
||||
FCalGrpVA.Visible := not FCalIsPluto;
|
||||
if not FCalIsPluto then
|
||||
begin
|
||||
FCalGrpDet.SetBounds(CAL_MARGIN, GTop, CAL_GRP_W, CAL_GRP1_H);
|
||||
GTop := GTop + CAL_GRP1_H + 14;
|
||||
FCalGrpVA.SetBounds(CAL_MARGIN, GTop, CAL_GRP_W, CAL_GRP2_H);
|
||||
GTop := GTop + CAL_GRP2_H + 14;
|
||||
end;
|
||||
FCalGrpSM.SetBounds(CAL_MARGIN, GTop, CAL_GRP_W, H);
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.SetCalibrationBackend(IsPluto: Boolean);
|
||||
begin
|
||||
FCalIsPluto := IsPluto;
|
||||
RelayoutCalTab;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.CollectCalFromUI;
|
||||
var i: Integer;
|
||||
begin
|
||||
FCalConfig.PwrDetModel := FCmbPwrDetModel.ItemIndex;
|
||||
// UI редактирует HF-банды 0..10; слот 11 (пустой в HF-плане) не трогаем.
|
||||
for i := 0 to 10 do
|
||||
FCalConfig.PADetCal[i] := FEdPADetCal[i].Value;
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
if FEdPADetCal[i] <> nil then FCalConfig.PADetCal[i] := FEdPADetCal[i].Value;
|
||||
if FEdSMBand[i] <> nil then FCalConfig.SMeterBandDB[i] := FEdSMBand[i].Value;
|
||||
end;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
if FEdSMXvtr[i] <> nil then FCalConfig.SMeterXvtrDB[i] := FEdSMXvtr[i].Value;
|
||||
FCalConfig.SupplyVoltCal := FEdSupplyVoltCal.Value;
|
||||
FCalConfig.AmpVoffMV := FEdAmpVoff.Value;
|
||||
FCalConfig.AmpSensMVA := FEdAmpSens.Value;
|
||||
FCalConfig.SMeterOffsetDB := FEdSMeterOffset.Value;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.OnCalAnyChange(Sender: TObject);
|
||||
@@ -2059,12 +2222,16 @@ begin
|
||||
try
|
||||
FCalConfig := C;
|
||||
FCmbPwrDetModel.ItemIndex := EnsureRange(C.PwrDetModel, 0, 3);
|
||||
for i := 0 to 10 do
|
||||
FEdPADetCal[i].Value := C.PADetCal[i];
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
if FEdPADetCal[i] <> nil then FEdPADetCal[i].Value := C.PADetCal[i];
|
||||
if FEdSMBand[i] <> nil then FEdSMBand[i].Value := C.SMeterBandDB[i];
|
||||
end;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
if FEdSMXvtr[i] <> nil then FEdSMXvtr[i].Value := C.SMeterXvtrDB[i];
|
||||
FEdSupplyVoltCal.Value := C.SupplyVoltCal;
|
||||
FEdAmpVoff.Value := C.AmpVoffMV;
|
||||
FEdAmpSens.Value := C.AmpSensMVA;
|
||||
FEdSMeterOffset.Value := C.SMeterOffsetDB;
|
||||
finally
|
||||
FLoading := False;
|
||||
end;
|
||||
@@ -4012,7 +4179,11 @@ begin
|
||||
FVHFCalLabels[i].Caption := 'VHF' + IntToStr(i) + ':';
|
||||
FVHFCalLabels[i].Hint := FVHFCalLabels[i].Caption;
|
||||
end;
|
||||
// Офсеты S-метра на вкладке Calibration — только по включённым слотам.
|
||||
FCalXvtrOn[i] := X.Entries[i].Enabled;
|
||||
FCalXvtrName[i] := X.Entries[i].ButtonText;
|
||||
end;
|
||||
RelayoutCalTab;
|
||||
if FChkXvtrTunPwr <> nil then FChkXvtrTunPwr.Checked := X.UseXVTRTunePower;
|
||||
LoadQOFromConfig; // QO100_SLOT → отдельная страница QO-100
|
||||
finally
|
||||
|
||||
+5
-6
@@ -451,7 +451,6 @@ type
|
||||
FTXMode: Integer; // may differ from RX when a slice is TX source
|
||||
FRawFMDeviation: Double;
|
||||
FSMeter: Double;
|
||||
FSMeterCalDB: Double; // калибровочный офсет S-метра, дБ (вкладка Calibration)
|
||||
FFilterLow: Integer;
|
||||
FFilterHigh: Integer;
|
||||
FAGCMode: TWDSPAGCMode;
|
||||
@@ -744,8 +743,6 @@ type
|
||||
property SNBEnabled: Boolean read FSNBEnabled;
|
||||
property LastError: string read FLastError;
|
||||
property SMeter: Double read FSMeter;
|
||||
// Офсет S-метра из вкладки Calibration; применяется в GetSMeterDBm/GetSliceSMeter
|
||||
property SMeterCalDB: Double read FSMeterCalDB write FSMeterCalDB;
|
||||
property FFTSize: Integer read FFFTSize;
|
||||
property WindowType: Integer read FWindowType;
|
||||
property SpecDetector: Integer read FSpecDetector;
|
||||
@@ -1248,7 +1245,6 @@ begin
|
||||
FAGCTop := -90.0;
|
||||
FVolume := 0.7;
|
||||
FSMeter := -130.0;
|
||||
FSMeterCalDB := 0.0;
|
||||
FNRMode := NR_MODE_OFF;
|
||||
FNBMode := NB_MODE_OFF;
|
||||
FSNBEnabled := False;
|
||||
@@ -2831,7 +2827,7 @@ begin
|
||||
FSliceLock.Enter;
|
||||
try
|
||||
idx := FindSliceIdx(Id);
|
||||
if idx >= 0 then Result := FSlices[idx].SMeter + FSMeterCalDB;
|
||||
if idx >= 0 then Result := FSlices[idx].SMeter;
|
||||
finally
|
||||
FSliceLock.Leave;
|
||||
end;
|
||||
@@ -3884,7 +3880,10 @@ function TWDSPEngine.GetSMeterDBm: Double;
|
||||
begin
|
||||
// НЕ вызываем GetRXAMeter здесь повторно — значение уже обновлено
|
||||
// в DSP-колбэке. Повторный вызов сбрасывает аккумулятор WDSP → 0.
|
||||
Result := FSMeter + FSMeterCalDB;
|
||||
// Калибровочный офсет здесь НЕ прибавляется: он зависит от диапазона/
|
||||
// трансвертера, о которых движок не знает — его добавляет TRadioController
|
||||
// (ReadSMeterDBm / SliceSMeter).
|
||||
Result := FSMeter;
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<UseVersionInfo Value="True"/>
|
||||
<AutoIncrementBuild Value="True"/>
|
||||
<MinorVersionNr Value="9"/>
|
||||
<BuildNr Value="276"/>
|
||||
<BuildNr Value="277"/>
|
||||
</VersionInfo>
|
||||
<MacroValues Count="106">
|
||||
<MacroValues Count="108">
|
||||
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
||||
@@ -126,6 +126,8 @@
|
||||
<Macro104 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro105 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro106 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro107 Name="LCLWidgetType" Value="qt6"/>
|
||||
<Macro108 Name="LCLWidgetType" Value="qt6"/>
|
||||
</MacroValues>
|
||||
<BuildModes>
|
||||
<Item Name="Debug" Default="True"/>
|
||||
|
||||
+1
-1
@@ -466,7 +466,7 @@ begin
|
||||
// не обновляет в headless — освежаем здесь, как GUI-таймер (MainForm). Без
|
||||
// этого PushState слал бы клиентам залипший -130 dBm.
|
||||
if FCtrl.FRunning and FCtrl.FWDSPReady then
|
||||
FCtrl.FLastSMeter := FCtrl.FDSPEngine.GetSMeterDBm;
|
||||
FCtrl.FLastSMeter := FCtrl.ReadSMeterDBm;
|
||||
FWebAd.PushState; // исходящее зеркало состояния/спектра
|
||||
lastPush := nowMs;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user