mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(puresignal): цель feedback 22 для Orion MkII + outlier-фильтр calcc
Разбор «IMD3 хуже, чем в Thetis»: юзерская плата (Orion MkII/Anvelina PRO3) при стоковой цели feedback 152 перегружает входные каскады ADC2208+кодека — фидбек сам интермодулирует, PS корректирует по искажённому наблюдению. Замеры eu2av (Thetis-Enhanced): оптимум FB≈22 при ATT≈10 дБ. - PSFBTarget: цель уровня feedback, авто по плате (board 5 → 22, иначе 152), настройка ps_fb_target (0 = авто) - авто-ATT: пороги от цели (FB > 1.5×цели / FB < 0.7×цели при ATT>0), ddB = 20*log10(FB/цель). Заодно чинит «ATT всегда 0»: старый порог >181 на этой плате никогда не достигался - PSOutlierSigmaEff → SetPSOutlierSigma (новый экспорт libwdsp): MAD- фильтр выбросов перед фитом calcc, авто σ=5.0 для Orion MkII, настройка ps_outlier_sigma (-1 = авто) - лампа FB в поповере: зоны от цели (0.7–1.3× зелёная), подпись «FB: тек/цель» Требует libwdsp с патчами eu2av (форк wdsp, коммит d27684c). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+14
-8
@@ -97,8 +97,9 @@ const
|
||||
CLR_INPUT = TColor($00FFFFFF);
|
||||
CLR_INPUT_TEXT = TColor($00202020);
|
||||
|
||||
// Лампа feedback (пороги Thetis: >181 горячо, 129..181 оптимум, 91..128
|
||||
// слабовато, <=90 нет сигнала). TColor = BGR.
|
||||
// Лампа feedback — пороги от цели PSFBTarget (Thetis-Enhanced eu2av):
|
||||
// >1.5×цели горячо, 0.7..1.3×цели оптимум, 0.5×..0.7× слабовато, ниже — нет
|
||||
// сигнала. TColor = BGR.
|
||||
CLR_FB_HOT = TColor($00FF9030); // голубой: слишком горячо (атт. мал)
|
||||
CLR_FB_OK = TColor($0000FF00); // зелёный: оптимум
|
||||
CLR_FB_LOW = TColor($0000FFFF); // жёлтый: слабовато
|
||||
@@ -382,7 +383,7 @@ end;
|
||||
|
||||
procedure TPureSignalPopup.RefreshStatus;
|
||||
var
|
||||
FB: Integer;
|
||||
FB, FBTarget: Integer;
|
||||
LampClr: TColor;
|
||||
begin
|
||||
if (FController = nil) or not Visible then Exit;
|
||||
@@ -394,17 +395,22 @@ begin
|
||||
FBtn2Ton.Active := FController.FTwoTone;
|
||||
|
||||
FB := FController.PSFeedbackLevel;
|
||||
FBTarget := FController.PSFBTarget;
|
||||
if FController.FPSFeedbackOn then
|
||||
begin
|
||||
if FB > 181 then LampClr := CLR_FB_HOT
|
||||
else if FB > 128 then LampClr := CLR_FB_OK
|
||||
else if FB > 90 then LampClr := CLR_FB_LOW
|
||||
else LampClr := CLR_FB_NONE;
|
||||
if FB > Round(FBTarget * 1.5) then LampClr := CLR_FB_HOT
|
||||
else if FB >= Round(FBTarget * 0.7) then
|
||||
begin
|
||||
if FB <= Round(FBTarget * 1.3) then LampClr := CLR_FB_OK
|
||||
else LampClr := CLR_FB_LOW // 1.3..1.5×: желтовато
|
||||
end
|
||||
else if FB >= Round(FBTarget * 0.5) then LampClr := CLR_FB_LOW
|
||||
else LampClr := CLR_FB_NONE;
|
||||
end
|
||||
else
|
||||
LampClr := CLR_LAMP_OFF;
|
||||
if FFbLamp.Color <> LampClr then FFbLamp.Color := LampClr;
|
||||
FLbFbVal.Caption := Format('FB: %d', [FB]);
|
||||
FLbFbVal.Caption := Format('FB: %d/%d', [FB, FBTarget]);
|
||||
|
||||
if FController.PSCorrecting then
|
||||
begin
|
||||
|
||||
+40
-8
@@ -507,6 +507,7 @@ type
|
||||
procedure ApplyNoiseFilterButtonsToDSP; // NR/NB/SNB/ANF → WDSP
|
||||
procedure SendDUCSpecificFromSettings; // DUC Specific (mic/keyer/atten) в сеть
|
||||
procedure ApplyTXSettingsToDSP; // TX-цепь (фильтр/gain/EQ/comp/...) → WDSP
|
||||
function PSOutlierSigmaEff: Double; // σ outlier-фильтра calcc (авто по плате)
|
||||
|
||||
// ---- Управление диапазонами (состояние + DSP; рендер через события) ----
|
||||
// MakeBandSettings — снимок текущего состояния в запись диапазона.
|
||||
@@ -756,7 +757,11 @@ type
|
||||
// Вооружение/снятие feedback-тракта (сеть + движок), идемпотентно.
|
||||
procedure PSSetFeedbackPath(En: Boolean);
|
||||
// Статус для UI (кэш последнего PureSignalTick)
|
||||
function PSFeedbackLevel: Integer; // info[4], оптимум ~140-160
|
||||
function PSFeedbackLevel: Integer; // info[4], оптимум ~PSFBTarget
|
||||
// Эффективная цель уровня feedback: настройка ps_fb_target, либо авто по
|
||||
// плате (Orion MkII/ANAN-7000/8000 → 22 — выше перегружается вход ADC,
|
||||
// замеры eu2av на Anvelina PRO3; остальные → 152, классика Thetis).
|
||||
function PSFBTarget: Integer;
|
||||
function PSCalCount: Integer; // info[5]
|
||||
function PSCorrecting: Boolean; // info[14]=1 — коррекция применяется
|
||||
function PSMaxTXVal: Double; // GetPSMaxTX (пик TX для SetPk)
|
||||
@@ -4412,6 +4417,30 @@ begin
|
||||
Changed(rfPureSignal);
|
||||
end;
|
||||
|
||||
function TRadioController.PSFBTarget: Integer;
|
||||
begin
|
||||
Result := FTXSettings.PSFBTarget;
|
||||
if Result <= 0 then
|
||||
begin
|
||||
if FDevConnected and (FNetwork <> nil) and (FNetwork.Device.BoardType = 5) then
|
||||
Result := 22 // Orion MkII: замеры eu2av — при 152 фидбек-АЦП сам даёт IMD
|
||||
else
|
||||
Result := 152; // классическая цель Thetis
|
||||
end;
|
||||
end;
|
||||
|
||||
function TRadioController.PSOutlierSigmaEff: Double;
|
||||
begin
|
||||
Result := FTXSettings.PSOutlierSigma;
|
||||
if Result < 0 then
|
||||
begin
|
||||
if FDevConnected and (FNetwork <> nil) and (FNetwork.Device.BoardType = 5) then
|
||||
Result := 5.0 // Orion MkII: дефолт Thetis-Enhanced eu2av
|
||||
else
|
||||
Result := 0.0; // выключен
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRadioController.ApplyPSSettingsToDSP;
|
||||
var
|
||||
Ints, Spi: Integer;
|
||||
@@ -4426,7 +4455,7 @@ begin
|
||||
FTXSettings.PSTXDelayNs, FTXSettings.PSRelaxPtol,
|
||||
FTXSettings.PSPin, FTXSettings.PSMap,
|
||||
FTXSettings.PSStabilize, Ints, Spi,
|
||||
FTXSettings.PSHWPeak);
|
||||
FTXSettings.PSHWPeak, PSOutlierSigmaEff);
|
||||
// Правка частот двухтональника при активном 2TON — применяем живьём.
|
||||
if FTwoTone then
|
||||
FDSPEngine.SetTXTwoTone(True, FTXSettings.PSTTFreq1, FTXSettings.PSTTFreq2);
|
||||
@@ -4464,6 +4493,7 @@ procedure TRadioController.PureSignalTick;
|
||||
// + auto-attenuate (timer2code): подстройка AttOnTX по уровню feedback.
|
||||
var
|
||||
NewAtt: Integer;
|
||||
FBTarget: Integer;
|
||||
ddB: Double;
|
||||
CalAttemptsChanged: Boolean;
|
||||
begin
|
||||
@@ -4555,21 +4585,23 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// --- Auto-attenuate (Thetis timer2code) ---
|
||||
// --- Auto-attenuate (Thetis-Enhanced eu2av timer2code) ---
|
||||
// По завершении очередной попытки калибровки: если feedback слишком горячий
|
||||
// (>181) или слабый при ненулевом атт. (<=128), подстроить AttOnTX так,
|
||||
// чтобы уровень лёг к оптимуму 152.
|
||||
// (>1.5×цели) или слабый при ненулевом атт. (<0.7×цели), подстроить AttOnTX
|
||||
// так, чтобы уровень лёг к цели PSFBTarget (22 на Orion MkII — выше вход
|
||||
// фидбек-АЦП интермодулирует сам, и PS корректирует по искажённому сигналу).
|
||||
FBTarget := PSFBTarget;
|
||||
case FPSAAState of
|
||||
0: begin
|
||||
CalAttemptsChanged := FPSInfo[5] <> FPSInfoPrev[5];
|
||||
if FTXSettings.PSAutoAtten and CalAttemptsChanged
|
||||
and ((FPSInfo[4] > 181) or
|
||||
((FPSInfo[4] <= 128) and (FTXSettings.AttOnTX > 0))) then
|
||||
and ((FPSInfo[4] > Round(FBTarget * 1.5)) or
|
||||
((FPSInfo[4] < Round(FBTarget * 0.7)) and (FTXSettings.AttOnTX > 0))) then
|
||||
begin
|
||||
FPSAAState := 1;
|
||||
if (FPSInfo[4] > 0) and (FPSInfo[4] <= 256) then
|
||||
begin
|
||||
ddB := 20.0 * Log10(FPSInfo[4] / 152.293);
|
||||
ddB := 20.0 * Log10(FPSInfo[4] / FBTarget);
|
||||
if ddB < -100.0 then ddB := -100.0;
|
||||
if ddB > +100.0 then ddB := +100.0;
|
||||
end
|
||||
|
||||
@@ -234,6 +234,12 @@ type
|
||||
PSHWPeak: Double; // SetPk (0.2899 для P2, 0.6121 Saturn)
|
||||
PSTTFreq1: Integer; // Гц — тон 1 двухтональника (700)
|
||||
PSTTFreq2: Integer; // Гц — тон 2 двухтональника (1900)
|
||||
// Калибровка фидбек-тракта (Thetis-Enhanced eu2av): на Orion MkII цель 152
|
||||
// перегружает входные каскады ADC → IMD-«юбка», оптимум FB≈22 при ATT≈10дБ.
|
||||
PSFBTarget: Integer; // цель уровня feedback info[4]; 0 = авто по плате
|
||||
// (Orion MkII → 22, иначе 152)
|
||||
PSOutlierSigma: Double; // σ outlier-фильтра calcc; <0 = авто по плате
|
||||
// (Orion MkII → 5.0, иначе выкл.), 0 = выкл.
|
||||
end;
|
||||
|
||||
// Web-сервер — глобальные настройки (не привязаны к устройству, секция "web").
|
||||
@@ -1214,6 +1220,8 @@ begin
|
||||
T.PSHWPeak := 0.2899;
|
||||
T.PSTTFreq1 := 700;
|
||||
T.PSTTFreq2 := 1900;
|
||||
T.PSFBTarget := 0; // авто по плате
|
||||
T.PSOutlierSigma := -1.0; // авто по плате
|
||||
end;
|
||||
|
||||
function TSettingsManager.LoadTX(const MAC: array of Byte;
|
||||
@@ -1293,6 +1301,8 @@ begin
|
||||
T.PSHWPeak := JD(O,'ps_hw_peak', T.PSHWPeak);
|
||||
T.PSTTFreq1 := JI(O,'ps_tt_freq1', T.PSTTFreq1);
|
||||
T.PSTTFreq2 := JI(O,'ps_tt_freq2', T.PSTTFreq2);
|
||||
T.PSFBTarget := EnsureRange(JI(O,'ps_fb_target', T.PSFBTarget), 0, 256);
|
||||
T.PSOutlierSigma := JD(O,'ps_outlier_sigma', T.PSOutlierSigma);
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.SaveTX(const MAC: array of Byte;
|
||||
@@ -1364,6 +1374,8 @@ begin
|
||||
JW(O,'ps_hw_peak', T.PSHWPeak);
|
||||
JW(O,'ps_tt_freq1', T.PSTTFreq1);
|
||||
JW(O,'ps_tt_freq2', T.PSTTFreq2);
|
||||
JW(O,'ps_fb_target', T.PSFBTarget);
|
||||
JW(O,'ps_outlier_sigma',T.PSOutlierSigma);
|
||||
end;
|
||||
|
||||
class procedure TSettingsManager.DefaultAlex(out A: TAlexSettings);
|
||||
|
||||
@@ -281,6 +281,8 @@ procedure SetPSPinMode(channel: Integer; pin: Integer); cdecl; external WDSP_LIB
|
||||
procedure SetPSMapMode(channel: Integer; map: Integer); cdecl; external WDSP_LIB;
|
||||
procedure SetPSStabilize(channel: Integer; stbl: Integer); cdecl; external WDSP_LIB;
|
||||
procedure SetPSIntsAndSpi(channel: Integer; ints: Integer; spi: Integer); cdecl; external WDSP_LIB;
|
||||
// eu2av: медианный (MAD) outlier-фильтр перед кубическим фитом calcc; 0 = выкл.
|
||||
procedure SetPSOutlierSigma(channel: Integer; sigma: Double); cdecl; external WDSP_LIB;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// cblock.c
|
||||
|
||||
+7
-2
@@ -404,6 +404,7 @@ type
|
||||
FPSInts: Integer;
|
||||
FPSSpi: Integer;
|
||||
FPSHWPeak: Double;
|
||||
FPSOutlierSigma: Double; // eu2av MAD-фильтр перед фитом; 0 = выкл.
|
||||
|
||||
// Кэшированные TX-параметры — применяются после OpenChannel(TXA) и при изменении.
|
||||
// Для Filter/Compressor/Leveler/ALC/PhaseRot/EQ/AM/FM/CTCSS.
|
||||
@@ -668,7 +669,8 @@ type
|
||||
function PSGetMaxTX: Double;
|
||||
procedure PSSetParams(MoxDelay, LoopDelay: Double; TXDelayNs: Integer;
|
||||
RelaxPtol: Boolean; Pin, Map, Stabilize: Boolean;
|
||||
Ints, Spi: Integer; HWPeak: Double);
|
||||
Ints, Spi: Integer; HWPeak: Double;
|
||||
OutlierSigma: Double);
|
||||
|
||||
// Расширенное TX управление (применяются мгновенно если канал открыт)
|
||||
procedure SetTXFilterFull(Low, High, NC, MP, Window: Integer);
|
||||
@@ -1318,6 +1320,7 @@ begin
|
||||
FPSInts := 16;
|
||||
FPSSpi := 256;
|
||||
FPSHWPeak := 0.2899; // протокол 2 (Saturn: 0.6121)
|
||||
FPSOutlierSigma := 0.0; // выкл. до ApplyPSSettingsToDSP (авто по плате)
|
||||
FMonitorRXDuringTX := False;
|
||||
FPostTXMuteUntil := 0;
|
||||
FActiveDisplayID := RX_DISP_ID;
|
||||
@@ -3549,11 +3552,12 @@ begin
|
||||
SetPSStabilize(TXA_CHAN, Ord(FPSStabilize));
|
||||
SetPSIntsAndSpi(TXA_CHAN, FPSInts, FPSSpi);
|
||||
SetPSHWPeak(TXA_CHAN, FPSHWPeak);
|
||||
SetPSOutlierSigma(TXA_CHAN, FPSOutlierSigma);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.PSSetParams(MoxDelay, LoopDelay: Double; TXDelayNs: Integer;
|
||||
RelaxPtol: Boolean; Pin, Map, Stabilize: Boolean; Ints, Spi: Integer;
|
||||
HWPeak: Double);
|
||||
HWPeak: Double; OutlierSigma: Double);
|
||||
begin
|
||||
FPSMoxDelay := MoxDelay;
|
||||
FPSLoopDelay := LoopDelay;
|
||||
@@ -3565,6 +3569,7 @@ begin
|
||||
if Ints > 0 then FPSInts := Ints;
|
||||
if Spi > 0 then FPSSpi := Spi;
|
||||
if HWPeak > 0 then FPSHWPeak := HWPeak;
|
||||
if OutlierSigma >= 0 then FPSOutlierSigma := OutlierSigma;
|
||||
ApplyPSParams;
|
||||
end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user