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:
2026-07-18 14:35:34 +03:00
co-authored by Claude Fable 5
parent a7e154b959
commit c645b0d1e6
6 changed files with 381 additions and 20 deletions
+44
View File
@@ -330,6 +330,18 @@ type
EnableXvtrHf: Boolean; // режим XVTR HF
end;
// Калибровки (вкладка Calibration): детектор мощности/КСВ Alex-моста,
// напряжение/ток питания, S-метр. Модель детектора задаёт константы моста
// (Vref/bridge_volt/ADC-offset, как в Thetis computeAlexFwdPower).
TCalibration = record
PwrDetModel: Integer; // 0=ANAN-10/100 (3.3V), 1=ANAN-200D, 2=ANAN-7000DLE/Anvelina Pro 3, 3=ANAN-8000DLE/Orion MkII
PADetCal: array[0..CFG_BAND_COUNT-1] of Double; // множитель FWD/REV на банд, 0.50..2.00 (1.0 = без коррекции)
SupplyVoltCal: Double; // множитель напряжения питания (1.0 = без коррекции)
AmpVoffMV: Double; // сдвиг нуля датчика тока, мВ (Thetis default 360)
AmpSensMVA: Double; // чувствительность датчика тока, мВ/А (Thetis default 120)
SMeterOffsetDB: Double; // офсет S-метра, дБ (прибавляется к WDSP dBm)
end;
TGlobalSettings = record
Volume: Integer;
TxMonVolume: Integer; // громкость self-monitor RX-аудио на TX (RX MUTE off)
@@ -397,6 +409,8 @@ type
PlutoTxMaxAttDb: Double; // Pluto: TX-аттенюация на drive=100%, дБ<0 (дефолт -10)
PABandCal: array[0..CFG_BAND_COUNT-1] of Double; // калибровка на диапазон 38.8..100.0
VHFBandCal: array[0..CFG_XVTR_COUNT-1] of Double; // калибровка для XVTR слотов 38.8..100.0
// --- Calibration (детектор мощности/КСВ, напряжение/ток, S-метр) ---
Cal: TCalibration;
// --- ADC settings ---
DitherEnabled: Boolean; // DDC Specific byte 5 — уменьшает интермодуляцию
RandomEnabled: Boolean; // DDC Specific byte 6 — рандомизация ADC
@@ -454,6 +468,7 @@ type
class function MacToStr(const MAC: array of Byte): string;
class procedure DefaultBand(BandIdx: Integer; out B: TBandSettings);
class procedure DefaultGlobal(out G: TGlobalSettings);
class procedure DefaultCalibration(out C: TCalibration);
class procedure DefaultTX(out T: TTXSettings);
// Размер окна — не привязан к MAC, хранится в корне JSON
procedure SaveWindowBounds(L, T, W, H, DPI: Integer; Maximized: Boolean);
@@ -614,6 +629,19 @@ begin
// ADC — включены по умолчанию: поддерживаются на Hermes, Angelia, Orion
G.DitherEnabled := True;
G.RandomEnabled := True;
DefaultCalibration(G.Cal);
end;
class procedure TSettingsManager.DefaultCalibration(out C: TCalibration);
var i: Integer;
begin
FillChar(C, SizeOf(C), 0);
C.PwrDetModel := 0; // ANAN-10/100 — совпадает с прежней зашитой формулой
for i := 0 to CFG_BAND_COUNT-1 do C.PADetCal[i] := 1.0;
C.SupplyVoltCal := 1.0;
C.AmpVoffMV := 360.0;
C.AmpSensMVA := 120.0;
C.SMeterOffsetDB := 0.0;
end;
constructor TSettingsManager.Create(const FilePath: string);
@@ -856,6 +884,14 @@ begin
// ADC settings
G.DitherEnabled := JB(GObj,'dither_enabled', True);
G.RandomEnabled := JB(GObj,'random_enabled', True);
// Calibration (детектор мощности/КСВ, напряжение/ток, S-метр)
G.Cal.PwrDetModel := EnsureRange(JI(GObj,'cal_pwr_det_model', 0), 0, 3);
for i := 0 to CFG_BAND_COUNT-1 do
G.Cal.PADetCal[i] := EnsureRange(JD(GObj,'cal_pa_det_'+IntToStr(i), 1.0), 0.5, 2.0);
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);
for i := 0 to CFG_BAND_COUNT-1 do
begin
@@ -965,6 +1001,14 @@ begin
// ADC settings
JW(O,'dither_enabled',G.DitherEnabled);
JW(O,'random_enabled',G.RandomEnabled);
// Calibration
JW(O,'cal_pwr_det_model',G.Cal.PwrDetModel);
for i := 0 to CFG_BAND_COUNT-1 do
JW(O,'cal_pa_det_'+IntToStr(i),G.Cal.PADetCal[i]);
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);
end;
procedure TSettingsManager.SaveBand(const MAC: array of Byte; BandIdx: Integer;