mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
feature(settings): вкладка Calibration — детектор мощности/КСВ, V/A, S-метр
Паритет с Thetis-Enhanced (Det. Cal. / Volts&Amps правки): - TCalibration в TGlobalSettings (JSON cal_*): модель детектора Alex-моста, per-band множитель FWD/REV 0.5..2.0, множитель напряжения, Voff/Sens датчика тока, офсет S-метра. - AlexDetToWatts: константы Thetis computeAlexFwdPower/computeRefPower по моделям (ANAN-100 / 200D / 7000DLE-Anvelina Pro 3 / 8000DLE-Orion MkII, 6m-спецкейс REV). Дефолт = прежняя формула ANAN-100 (поведение не меняется). - OnHPStatus: FWD и REV через модельную формулу x множитель банда; КСВ = (1+p)/(1-p), p=sqrt(RevW/FwdW) (Thetis) вместо отношения сырых ADC; напряжение x SupplyVoltCal; ток с калибруемыми Voff/Sens. - WDSPEngine.SMeterCalDB: офсет в GetSMeterDBm/GetSliceSMeter (главный S-метр, slice-флаги, web). - Выбор модели в комбо подставляет модельные дефолты датчика тока (Anvelina Pro 3/7000DLE: 340 мВ / 88 мВ/А — Thetis GetDefaultVoltCalibration). - Фиксы: гард FLoading при постройке вкладки (SetItemIndex стреляет OnChange на программном присвоении -> AV на nil-контролах), FPageCalib/FNavCalib в списках SelectPage (вкладка была невидимой). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+216
-5
@@ -41,6 +41,8 @@ type
|
||||
TOnAnt936xChange = procedure(const A: TAD936xAnt) of object;
|
||||
// VHF (XVTR) PA calibration: 8 slots, 38.8..100.0
|
||||
TOnVHFCalChange = procedure(const VHFCal: array of Double) of object;
|
||||
// Калибровки (вкладка Calibration): детектор мощности/КСВ, напряжение/ток, S-метр
|
||||
TOnCalibrationChange = procedure(const C: TCalibration) of object;
|
||||
// TX-настройки целиком (любая правка → один callback с актуальной структурой)
|
||||
TOnTXSettingsChange = procedure(const T: TTXSettings) of object;
|
||||
|
||||
@@ -150,6 +152,18 @@ type
|
||||
FEdVHFCal: array[0..CFG_XVTR_COUNT-1] of TFlatFloatSpinEdit;
|
||||
FVHFCalLabels: array[0..CFG_XVTR_COUNT-1] of TLabel;
|
||||
|
||||
// ---- Calibration tab controls ----
|
||||
FPageCalib: TScrollBox;
|
||||
FNavCalib: TFlatButton;
|
||||
FCmbPwrDetModel: TFlatComboBox; // модель детектора Alex-моста
|
||||
FEdPADetCal: array[0..10] of TFlatFloatSpinEdit; // множитель FWD/REV на банд
|
||||
FEdSupplyVoltCal: TFlatFloatSpinEdit; // множитель напряжения питания
|
||||
FEdAmpVoff: TFlatFloatSpinEdit; // датчик тока: сдвиг нуля, мВ
|
||||
FEdAmpSens: TFlatFloatSpinEdit; // датчик тока: мВ/А
|
||||
FEdSMeterOffset: TFlatFloatSpinEdit; // офсет S-метра, дБ
|
||||
FCalConfig: TCalibration;
|
||||
FOnCalibrationChange: TOnCalibrationChange;
|
||||
|
||||
// ---- Transmit tab controls ----
|
||||
// Текущее состояние, отдаётся в OnTXChange целиком при любой правке.
|
||||
FTX: TTXSettings;
|
||||
@@ -337,6 +351,9 @@ type
|
||||
procedure BuildDisplayTab;
|
||||
procedure BuildRX1Tab;
|
||||
procedure BuildPATab;
|
||||
procedure BuildCalibrationTab;
|
||||
procedure CollectCalFromUI;
|
||||
procedure OnCalAnyChange(Sender: TObject);
|
||||
procedure BuildCATTab;
|
||||
procedure BuildTransmitTab;
|
||||
procedure BuildAlexTab;
|
||||
@@ -445,6 +462,7 @@ type
|
||||
procedure LoadFreqMhzDigits(Digits: Integer);
|
||||
procedure LoadPASettings(MaxPower: Double; const BandCal: array of Double);
|
||||
procedure LoadPlutoTxMaxAtt(MaxAttDb: Double);
|
||||
procedure LoadCalibration(const C: TCalibration);
|
||||
// Вкладка Antenna: Alex-таблица (openHPSDR) либо таблица разъёмов AD936x.
|
||||
procedure SetAntennaBackend(IsAD936x, HasAntSwitch: Boolean);
|
||||
// Таблица разъёмов + имена/видимость слотов трансвертеров.
|
||||
@@ -474,6 +492,7 @@ type
|
||||
property OnPlutoTxChange: TOnPlutoTxChange read FOnPlutoTxChange write FOnPlutoTxChange;
|
||||
property OnAnt936xChange: TOnAnt936xChange read FOnAnt936xChange write FOnAnt936xChange;
|
||||
property OnVHFCalChange: TOnVHFCalChange read FOnVHFCalChange write FOnVHFCalChange;
|
||||
property OnCalibrationChange: TOnCalibrationChange read FOnCalibrationChange write FOnCalibrationChange;
|
||||
property OnDisplayChange: TOnDisplayParamChange read FOnDisplayChange write FOnDisplayChange;
|
||||
property OnWaterfallChange: TOnWaterfallParamChange read FOnWaterfallChange write FOnWaterfallChange;
|
||||
property OnWfRenderChange: TOnWfRenderChange read FOnWfRenderChange write FOnWfRenderChange;
|
||||
@@ -704,11 +723,12 @@ begin
|
||||
FNavWaterfall := MakeNavButton('Waterfall', 182);
|
||||
FNavTransmit := MakeNavButton('Transmit', 218);
|
||||
FNavPA := MakeNavButton('Power Amplifier', 254);
|
||||
FNavAdvanced := MakeNavButton('Advanced', 290);
|
||||
FNavCAT := MakeNavButton('CAT', 326);
|
||||
FNavAlex := MakeNavButton('Antenna / Alex', 362);
|
||||
FNavXvtr := MakeNavButton('Transverter', 398);
|
||||
FNavQO := MakeNavButton('QO-100', 434);
|
||||
FNavCalib := MakeNavButton('Calibration', 290);
|
||||
FNavAdvanced := MakeNavButton('Advanced', 326);
|
||||
FNavCAT := MakeNavButton('CAT', 362);
|
||||
FNavAlex := MakeNavButton('Antenna / Alex', 398);
|
||||
FNavXvtr := MakeNavButton('Transverter', 434);
|
||||
FNavQO := MakeNavButton('QO-100', 470);
|
||||
|
||||
FContentPanel := TPanel.Create(Self);
|
||||
FContentPanel.Parent := Self;
|
||||
@@ -722,6 +742,7 @@ begin
|
||||
FPageWaterfall := MakeScrollPage;
|
||||
FPageTransmit := MakeScrollPage;
|
||||
FPagePA := MakeScrollPage;
|
||||
FPageCalib := MakeScrollPage;
|
||||
FPageAdvanced := MakeScrollPage;
|
||||
FPageCAT := MakeScrollPage;
|
||||
FPageAlex := MakeScrollPage;
|
||||
@@ -730,12 +751,14 @@ begin
|
||||
FAlexBoardType := 0;
|
||||
TSettingsManager.DefaultAlex(FAlexConfig);
|
||||
TSettingsManager.DefaultXvtr(FXvtrConfig);
|
||||
TSettingsManager.DefaultCalibration(FCalConfig);
|
||||
|
||||
BuildAudioTab;
|
||||
BuildDisplayTab;
|
||||
BuildRX1Tab;
|
||||
BuildTransmitTab;
|
||||
BuildPATab;
|
||||
BuildCalibrationTab;
|
||||
BuildAdvancedTab;
|
||||
BuildCATTab;
|
||||
BuildAlexTab;
|
||||
@@ -768,6 +791,7 @@ begin
|
||||
else if Sender = FNavWaterfall then SelectPage(FPageWaterfall, FNavWaterfall)
|
||||
else if Sender = FNavTransmit then SelectPage(FPageTransmit, FNavTransmit)
|
||||
else if Sender = FNavPA then SelectPage(FPagePA, FNavPA)
|
||||
else if Sender = FNavCalib then SelectPage(FPageCalib, FNavCalib)
|
||||
else if Sender = FNavAdvanced then SelectPage(FPageAdvanced, FNavAdvanced)
|
||||
else if Sender = FNavCAT then SelectPage(FPageCAT, FNavCAT)
|
||||
else if Sender = FNavAlex then SelectPage(FPageAlex, FNavAlex)
|
||||
@@ -783,6 +807,7 @@ begin
|
||||
FPageWaterfall.Visible:= APage = FPageWaterfall;
|
||||
FPageTransmit.Visible := APage = FPageTransmit;
|
||||
FPagePA.Visible := APage = FPagePA;
|
||||
FPageCalib.Visible := APage = FPageCalib;
|
||||
FPageAdvanced.Visible := APage = FPageAdvanced;
|
||||
FPageCAT.Visible := APage = FPageCAT;
|
||||
FPageAlex.Visible := APage = FPageAlex;
|
||||
@@ -795,6 +820,7 @@ begin
|
||||
FNavWaterfall.Active:= ANav = FNavWaterfall;
|
||||
FNavTransmit.Active := ANav = FNavTransmit;
|
||||
FNavPA.Active := ANav = FNavPA;
|
||||
FNavCalib.Active := ANav = FNavCalib;
|
||||
FNavAdvanced.Active := ANav = FNavAdvanced;
|
||||
FNavCAT.Active := ANav = FNavCAT;
|
||||
FNavAlex.Active := ANav = FNavAlex;
|
||||
@@ -1859,6 +1885,191 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.BuildCalibrationTab;
|
||||
// Вкладка Calibration (паритет с Thetis-Enhanced): модель детектора мощности
|
||||
// Alex-моста + множитель FWD/REV на банд (Det. Cal.), калибровка напряжения/
|
||||
// тока питания (PAVoltCal/AmpVoff/AmpSens) и офсет S-метра.
|
||||
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;
|
||||
|
||||
function MakeCalSpin(AParent: TWinControl; ALeft, ATop: Integer;
|
||||
AMin, AMax, AInc: Double; ADec: Integer;
|
||||
ADefault: Double): TFlatFloatSpinEdit;
|
||||
var E: TFlatFloatSpinEdit;
|
||||
begin
|
||||
E := TFlatFloatSpinEdit.Create(Self);
|
||||
E.Parent := AParent;
|
||||
E.SetBounds(ALeft, ATop, ED_W, BTN_H + 2);
|
||||
E.Color := CLR_INPUT;
|
||||
E.Font.Color := CLR_INPUT_TEXT;
|
||||
E.Font.Name := UI_FONT;
|
||||
E.Font.Size := 9;
|
||||
E.MinValue := AMin;
|
||||
E.MaxValue := AMax;
|
||||
E.Increment := AInc;
|
||||
E.DecimalPlaces := ADec;
|
||||
E.Value := ADefault;
|
||||
E.OnChange := OnCalAnyChange;
|
||||
Result := E;
|
||||
end;
|
||||
|
||||
var
|
||||
Grp: TPanel;
|
||||
Lbl: TLabel;
|
||||
i, r, c, X, Y, GTop: Integer;
|
||||
begin
|
||||
// Гард: SetItemIndex у TFlatComboBox стреляет OnChange и при программном
|
||||
// присвоении — без гарда OnCalAnyChange дёрнется из «ItemIndex := 0» ниже,
|
||||
// когда остальные контролы вкладки ещё nil → AV в CollectCalFromUI.
|
||||
FLoading := True;
|
||||
|
||||
with TLabel.Create(Self) do
|
||||
begin
|
||||
Parent := FPageCalib;
|
||||
Caption := 'Calibration';
|
||||
SetBounds(MARGIN, 18, 400, 28);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 16;
|
||||
Font.Style := [fsBold];
|
||||
Font.Color := CLR_TEXT;
|
||||
end;
|
||||
|
||||
with TLabel.Create(Self) do
|
||||
begin
|
||||
Parent := FPageCalib;
|
||||
Caption := 'Power/SWR detector, supply voltage/current and S-meter calibration.';
|
||||
SetBounds(MARGIN, 48, 620, 20);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 9;
|
||||
Font.Color := CLR_TEXTDIM;
|
||||
end;
|
||||
|
||||
// ── Power / SWR detector ────────────────────────────────────────────────
|
||||
GTop := 86;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'Power / SWR detector', MARGIN, GTop, 700, GRP1_H);
|
||||
|
||||
Lbl := MakeLbl(Grp, 'Detector model', GRP_PAD, R1 + 6, 132);
|
||||
FCmbPwrDetModel := MakeCombo(Grp, GRP_PAD + 150, 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');
|
||||
FCmbPwrDetModel.Items.Add('ANAN-8000DLE / Orion MkII');
|
||||
FCmbPwrDetModel.ItemIndex := 0;
|
||||
|
||||
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);
|
||||
|
||||
for i := 0 to 10 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);
|
||||
FEdPADetCal[i].Tag := i;
|
||||
end;
|
||||
|
||||
// ── Supply voltage / current ────────────────────────────────────────────
|
||||
GTop := GTop + GRP1_H + 14;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'Supply voltage / current', MARGIN, GTop, 700, GRP2_H);
|
||||
|
||||
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, '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 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, 'Defaults 360 mV / 120 mV/A (ACS712-style, Orion MkII)',
|
||||
GRP_PAD + VA_LBL_W + 10 + ED_W + 14, R1 + ROW_H + 6, 320);
|
||||
|
||||
// ── S-meter ─────────────────────────────────────────────────────────────
|
||||
GTop := GTop + GRP2_H + 14;
|
||||
Grp := MakeGroupPanel(FPageCalib, 'S-meter', MARGIN, GTop, 700, GRP3_H);
|
||||
|
||||
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);
|
||||
|
||||
FLoading := False;
|
||||
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;
|
||||
FCalConfig.SupplyVoltCal := FEdSupplyVoltCal.Value;
|
||||
FCalConfig.AmpVoffMV := FEdAmpVoff.Value;
|
||||
FCalConfig.AmpSensMVA := FEdAmpSens.Value;
|
||||
FCalConfig.SMeterOffsetDB := FEdSMeterOffset.Value;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.OnCalAnyChange(Sender: TObject);
|
||||
begin
|
||||
if FLoading then Exit;
|
||||
// Смена модели детектора подставляет модельные дефолты датчика тока
|
||||
// (Thetis GetDefaultVoltCalibration): ANAN-7000DLE/Anvelina Pro 3 — 340/88,
|
||||
// остальные — 360/120. Правится руками после, если датчик нестандартный.
|
||||
if Sender = FCmbPwrDetModel then
|
||||
begin
|
||||
FLoading := True;
|
||||
try
|
||||
if FCmbPwrDetModel.ItemIndex = 2 then
|
||||
begin
|
||||
FEdAmpVoff.Value := 340.0;
|
||||
FEdAmpSens.Value := 88.0;
|
||||
end else
|
||||
begin
|
||||
FEdAmpVoff.Value := 360.0;
|
||||
FEdAmpSens.Value := 120.0;
|
||||
end;
|
||||
finally
|
||||
FLoading := False;
|
||||
end;
|
||||
end;
|
||||
CollectCalFromUI;
|
||||
if Assigned(FOnCalibrationChange) then
|
||||
FOnCalibrationChange(FCalConfig);
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.LoadCalibration(const C: TCalibration);
|
||||
var i: Integer;
|
||||
begin
|
||||
FLoading := True;
|
||||
try
|
||||
FCalConfig := C;
|
||||
FCmbPwrDetModel.ItemIndex := EnsureRange(C.PwrDetModel, 0, 3);
|
||||
for i := 0 to 10 do
|
||||
FEdPADetCal[i].Value := C.PADetCal[i];
|
||||
FEdSupplyVoltCal.Value := C.SupplyVoltCal;
|
||||
FEdAmpVoff.Value := C.AmpVoffMV;
|
||||
FEdAmpSens.Value := C.AmpSensMVA;
|
||||
FEdSMeterOffset.Value := C.SMeterOffsetDB;
|
||||
finally
|
||||
FLoading := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.BuildAdvancedTab;
|
||||
const
|
||||
MARGIN = 22;
|
||||
|
||||
Reference in New Issue
Block a user